@@ -48,6 +48,5 @@ output/ | |||||
.classpath | .classpath | ||||
logs/ | logs/ | ||||
/dubhe-k8s/src/main/resources/kubeconfig | /dubhe-k8s/src/main/resources/kubeconfig | ||||
/dubhe-k8s/src/main/resources | |||||
*.log | *.log | ||||
/dubhe-admin/kubeconfig | /dubhe-admin/kubeconfig |
@@ -1,13 +1,22 @@ | |||||
# 一站式开发平台-服务端 | |||||
# 之江天枢-服务端 | |||||
## 本地开发 | |||||
**之江天枢一站式人工智能开源平台**(简称:**之江天枢**),包括海量数据处理、交互式模型构建(包含Notebook和模型可视化)、AI模型高效训练。多维度产品形态满足从开发者到大型企业的不同需求,将提升人工智能技术的研发效率、扩大算法模型的应用范围,进一步构建人工智能生态“朋友圈”。 | |||||
## 源码部署 | |||||
### 准备环境 | ### 准备环境 | ||||
安装如下软件环境。 | 安装如下软件环境。 | ||||
- OpenJDK:1.8+ | - OpenJDK:1.8+ | ||||
- Redis: 3.0+ | - Redis: 3.0+ | ||||
- Maven: 3.0+ | - Maven: 3.0+ | ||||
- MYSQL: 5.5.0+ | |||||
- MYSQL: 5.7.0+ | |||||
### 下载源码 | |||||
``` bash | |||||
git clone https://codeup.teambition.com/zhejianglab/dubhe-server.git | |||||
# 进入项目根目录 | |||||
cd dubhe-server | |||||
``` | |||||
### 创建DB | ### 创建DB | ||||
在MySQL中依次执行如下sql文件 | 在MySQL中依次执行如下sql文件 | ||||
@@ -20,14 +29,35 @@ sql/v1/02-Dubhe-DML.sql | |||||
### 配置 | ### 配置 | ||||
根据实际情况修改如下配置文件。 | 根据实际情况修改如下配置文件。 | ||||
``` | ``` | ||||
dubhe-admin/src/main/resources/config/application-dev.yml | |||||
dubhe-admin/src/main/resources/config/application-prod.yml | |||||
``` | ``` | ||||
### 启动: | |||||
### 构建 | |||||
``` bash | |||||
# 构建,生成的 jar 包位于 ./dubhe-admin/target/dubhe-admin-1.0.jar | |||||
mvn clean compile package | |||||
``` | ``` | ||||
mvn spring-boot:run | |||||
### 启动 | |||||
``` bash | |||||
# 指定启动环境为 prod | |||||
## admin模块 | |||||
java -jar ./dubhe-admin/target/dubhe-admin-1.0-exec.jar --spring.profiles.active=prod | |||||
## task模块 | |||||
java -jar ./dubhe-task/target/dubhe-task-1.0.jar --spring.profiles.active=prod | |||||
``` | ``` | ||||
## 本地开发 | |||||
### 必要条件: | |||||
导入maven项目,下载所需的依赖包 | |||||
mysql下创建数据库dubhe,初始化数据脚本 | |||||
安装redis | |||||
### 启动: | |||||
mvn spring-boot:run | |||||
## 代码结构: | ## 代码结构: | ||||
``` | ``` | ||||
├── common 公共模块 | ├── common 公共模块 | ||||
@@ -49,6 +79,7 @@ mvn spring-boot:run | |||||
├── dubhe-data 数据处理模块 | ├── dubhe-data 数据处理模块 | ||||
├── dubhe-model 模型管理模块 | ├── dubhe-model 模型管理模块 | ||||
├── dubhe-system 系统管理 | ├── dubhe-system 系统管理 | ||||
├── dubhe-task 定时任务模块 | |||||
``` | ``` | ||||
## docker服务器 | ## docker服务器 | ||||
@@ -29,11 +29,6 @@ | |||||
<artifactId>guava</artifactId> | <artifactId>guava</artifactId> | ||||
<version>21.0</version> | <version>21.0</version> | ||||
</dependency> | </dependency> | ||||
<dependency> | |||||
<groupId>com.github.penggle</groupId> | |||||
<artifactId>kaptcha</artifactId> | |||||
<version>${kaptcha.version}</version> | |||||
</dependency> | |||||
<!-- shiro --> | <!-- shiro --> | ||||
<dependency> | <dependency> | ||||
<groupId>org.apache.shiro</groupId> | <groupId>org.apache.shiro</groupId> | ||||
@@ -95,6 +90,10 @@ | |||||
<artifactId>commons-compress</artifactId> | <artifactId>commons-compress</artifactId> | ||||
<version>1.20</version> | <version>1.20</version> | ||||
</dependency> | </dependency> | ||||
<dependency> | |||||
<groupId>com.github.whvcse</groupId> | |||||
<artifactId>easy-captcha</artifactId> | |||||
</dependency> | |||||
</dependencies> | </dependencies> | ||||
<build> | <build> | ||||
<plugins> | <plugins> | ||||
@@ -14,31 +14,28 @@ | |||||
* limitations under the License. | * limitations under the License. | ||||
* ============================================================= | * ============================================================= | ||||
*/ | */ | ||||
package org.dubhe.annotation; | package org.dubhe.annotation; | ||||
import java.lang.annotation.*; | |||||
/** | /** | ||||
* 数据权限过滤Mapper拦截 | |||||
* | |||||
* @date 2020-06-22 | |||||
* @description 数据权限注解 | |||||
* @date 2020-09-24 | |||||
*/ | */ | ||||
import java.lang.annotation.*; | |||||
@Target({ElementType.METHOD, ElementType.TYPE}) | @Target({ElementType.METHOD, ElementType.TYPE}) | ||||
@Retention(RetentionPolicy.RUNTIME) | @Retention(RetentionPolicy.RUNTIME) | ||||
@Documented | @Documented | ||||
public @interface DataPermission { | public @interface DataPermission { | ||||
/** | /** | ||||
* 不需要数据权限的方法名 | |||||
* 只在类的注解上使用,代表方法的数据权限类型 | |||||
* @return | |||||
*/ | */ | ||||
String[] ignores() default {}; | |||||
String permission() default ""; | |||||
/** | /** | ||||
* 只在方法的注解上使用,代表方法的数据权限类型,如果不加注解,只会识别带"select"方法名的方法 | |||||
* | |||||
* 不需要数据权限的方法名 | |||||
* @return | * @return | ||||
*/ | */ | ||||
String[] permission() default {}; | |||||
String[] ignoresMethod() default {}; | |||||
} | } |
@@ -0,0 +1,47 @@ | |||||
/** | |||||
* Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||||
* | |||||
* 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.dubhe.annotation; | |||||
import org.dubhe.enums.DatasetTypeEnum; | |||||
import java.lang.annotation.ElementType; | |||||
import java.lang.annotation.Retention; | |||||
import java.lang.annotation.RetentionPolicy; | |||||
import java.lang.annotation.Target; | |||||
/** | |||||
* @description 数据权限方法注解 | |||||
* @date 2020-09-24 | |||||
*/ | |||||
@Target(ElementType.METHOD) | |||||
@Retention(RetentionPolicy.RUNTIME) | |||||
public @interface DataPermissionMethod { | |||||
/** | |||||
* 是否需要拦截标识 true: 不拦截 false: 拦截 | |||||
* | |||||
* @return 拦截标识 | |||||
*/ | |||||
boolean interceptFlag() default false; | |||||
/** | |||||
* 数据类型 | |||||
* | |||||
* @return 数据集类型 | |||||
*/ | |||||
DatasetTypeEnum dataType() default DatasetTypeEnum.PRIVATE; | |||||
} |
@@ -17,19 +17,20 @@ | |||||
package org.dubhe.annotation; | package org.dubhe.annotation; | ||||
import javax.validation.Constraint; | |||||
import javax.validation.ConstraintValidator; | |||||
import javax.validation.ConstraintValidatorContext; | |||||
import javax.validation.Payload; | |||||
import java.lang.annotation.ElementType; | import java.lang.annotation.ElementType; | ||||
import java.lang.annotation.Retention; | import java.lang.annotation.Retention; | ||||
import java.lang.annotation.RetentionPolicy; | import java.lang.annotation.RetentionPolicy; | ||||
import java.lang.annotation.Target; | import java.lang.annotation.Target; | ||||
import java.lang.reflect.InvocationTargetException; | import java.lang.reflect.InvocationTargetException; | ||||
import java.lang.reflect.Method; | import java.lang.reflect.Method; | ||||
import javax.validation.Constraint; | |||||
import javax.validation.ConstraintValidator; | |||||
import javax.validation.ConstraintValidatorContext; | |||||
import javax.validation.Payload; | |||||
/** | /** | ||||
* @date: 2020-05-21 | |||||
* @description 接口枚举类检测标注类 | |||||
* @date 2020-05-21 | |||||
*/ | */ | ||||
@Target({ ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE }) | @Target({ ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE }) | ||||
@Retention(RetentionPolicy.RUNTIME) | @Retention(RetentionPolicy.RUNTIME) | ||||
@@ -0,0 +1,66 @@ | |||||
/** | |||||
* Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||||
* | |||||
* 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.dubhe.annotation; | |||||
import javax.validation.Constraint; | |||||
import javax.validation.ConstraintValidator; | |||||
import javax.validation.ConstraintValidatorContext; | |||||
import javax.validation.Payload; | |||||
import java.lang.annotation.*; | |||||
import java.util.Arrays; | |||||
/** | |||||
* @description 自定义状态校验注解(传入值是否在指定状态范围内) | |||||
* @date 2020-09-18 | |||||
*/ | |||||
@Target({ElementType.FIELD, ElementType.PARAMETER}) | |||||
@Retention(RetentionPolicy.RUNTIME) | |||||
@Constraint(validatedBy = FlagValidator.Validator.class) | |||||
@Documented | |||||
public @interface FlagValidator { | |||||
String[] value() default {}; | |||||
String message() default "flag value is invalid"; | |||||
Class<?>[] groups() default {}; | |||||
Class<? extends Payload>[] payload() default {}; | |||||
/** | |||||
* @description 校验传入值是否在默认值范围校验逻辑 | |||||
* @date 2020-09-18 | |||||
*/ | |||||
class Validator implements ConstraintValidator<FlagValidator, Integer> { | |||||
private String[] values; | |||||
@Override | |||||
public void initialize(FlagValidator flagValidator) { | |||||
this.values = flagValidator.value(); | |||||
} | |||||
@Override | |||||
public boolean isValid(Integer value, ConstraintValidatorContext constraintValidatorContext) { | |||||
if (value == null) { | |||||
//当状态为空时,使用默认值 | |||||
return false; | |||||
} | |||||
return Arrays.stream(values).anyMatch(value::equals); | |||||
} | |||||
} | |||||
} |
@@ -15,8 +15,7 @@ | |||||
*/ | */ | ||||
package org.dubhe.aspect; | package org.dubhe.aspect; | ||||
import java.util.UUID; | |||||
import lombok.extern.slf4j.Slf4j; | |||||
import org.aspectj.lang.JoinPoint; | import org.aspectj.lang.JoinPoint; | ||||
import org.aspectj.lang.ProceedingJoinPoint; | import org.aspectj.lang.ProceedingJoinPoint; | ||||
import org.aspectj.lang.annotation.Around; | import org.aspectj.lang.annotation.Around; | ||||
@@ -28,10 +27,11 @@ import org.slf4j.MDC; | |||||
import org.springframework.stereotype.Component; | import org.springframework.stereotype.Component; | ||||
import org.springframework.util.StringUtils; | import org.springframework.util.StringUtils; | ||||
import lombok.extern.slf4j.Slf4j; | |||||
import java.util.UUID; | |||||
/** | /** | ||||
* @date 2020/04/10 | |||||
* @description 日志切面 | |||||
* @date 2020-04-10 | |||||
*/ | */ | ||||
@Component | @Component | ||||
@Aspect | @Aspect | ||||
@@ -54,7 +54,7 @@ public class LogAspect { | |||||
public void taskAspect() { | public void taskAspect() { | ||||
} | } | ||||
@Pointcut(" serviceAspect() || taskAspect() ") | |||||
@Pointcut(" serviceAspect() ") | |||||
public void aroundAspect() { | public void aroundAspect() { | ||||
} | } | ||||
@@ -0,0 +1,116 @@ | |||||
/** | |||||
* Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||||
* | |||||
* 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.dubhe.aspect; | |||||
import org.aspectj.lang.ProceedingJoinPoint; | |||||
import org.aspectj.lang.annotation.Around; | |||||
import org.aspectj.lang.annotation.Aspect; | |||||
import org.aspectj.lang.annotation.Pointcut; | |||||
import org.aspectj.lang.reflect.MethodSignature; | |||||
import org.dubhe.annotation.DataPermissionMethod; | |||||
import org.dubhe.base.BaseService; | |||||
import org.dubhe.base.DataContext; | |||||
import org.dubhe.domain.dto.CommonPermissionDataDTO; | |||||
import org.dubhe.enums.DatasetTypeEnum; | |||||
import org.dubhe.enums.LogEnum; | |||||
import org.dubhe.utils.JwtUtils; | |||||
import org.dubhe.utils.LogUtil; | |||||
import org.springframework.stereotype.Component; | |||||
import java.lang.reflect.Method; | |||||
import java.util.HashSet; | |||||
import java.util.Objects; | |||||
import java.util.Set; | |||||
/** | |||||
* @description 数据权限切面 | |||||
* @date 2020-09-24 | |||||
*/ | |||||
@Aspect | |||||
@Component | |||||
public class PermissionAspect { | |||||
/** | |||||
* 公共数据的有用户ID | |||||
*/ | |||||
public static final Long PUBLIC_DATA_USER_ID = 0L; | |||||
/** | |||||
* 基于注解的切面方法 | |||||
*/ | |||||
@Pointcut("@annotation(org.dubhe.annotation.DataPermissionMethod)") | |||||
private void cutMethod() { | |||||
} | |||||
/** | |||||
*环绕通知 | |||||
* @param joinPoint 切入参数对象 | |||||
* @return 返回方法结果集 | |||||
* @throws Throwable | |||||
*/ | |||||
@Around("cutMethod()") | |||||
public Object around(ProceedingJoinPoint joinPoint) throws Throwable { | |||||
// 获取方法传入参数 | |||||
Object[] params = joinPoint.getArgs(); | |||||
DataPermissionMethod dataPermissionMethod = getDeclaredAnnotation(joinPoint); | |||||
if (!Objects.isNull(JwtUtils.getCurrentUserDto()) && !Objects.isNull(dataPermissionMethod)) { | |||||
Set<Long> ids = new HashSet<>(); | |||||
ids.add(JwtUtils.getCurrentUserDto().getId()); | |||||
CommonPermissionDataDTO commonPermissionDataDTO = CommonPermissionDataDTO.builder().type(dataPermissionMethod.interceptFlag()).resourceUserIds(ids).build(); | |||||
if (DatasetTypeEnum.PUBLIC.equals(dataPermissionMethod.dataType())) { | |||||
ids.add(PUBLIC_DATA_USER_ID); | |||||
commonPermissionDataDTO.setResourceUserIds(ids); | |||||
} | |||||
DataContext.set(commonPermissionDataDTO); | |||||
} | |||||
// 执行源方法 | |||||
try { | |||||
return joinPoint.proceed(params); | |||||
} finally { | |||||
// 模拟进行验证 | |||||
BaseService.removeContext(); | |||||
} | |||||
} | |||||
/** | |||||
* 获取方法中声明的注解 | |||||
* | |||||
* @param joinPoint 切入参数对象 | |||||
* @return DataPermissionMethod 方法注解类型 | |||||
*/ | |||||
public DataPermissionMethod getDeclaredAnnotation(ProceedingJoinPoint joinPoint){ | |||||
// 获取方法名 | |||||
String methodName = joinPoint.getSignature().getName(); | |||||
// 反射获取目标类 | |||||
Class<?> targetClass = joinPoint.getTarget().getClass(); | |||||
// 拿到方法对应的参数类型 | |||||
Class<?>[] parameterTypes = ((MethodSignature) joinPoint.getSignature()).getParameterTypes(); | |||||
// 根据类、方法、参数类型(重载)获取到方法的具体信息 | |||||
Method objMethod = null; | |||||
try { | |||||
objMethod = targetClass.getMethod(methodName, parameterTypes); | |||||
} catch (NoSuchMethodException e) { | |||||
LogUtil.error(LogEnum.BIZ_DATASET,"获取注解方法参数异常 error:{}",e); | |||||
} | |||||
// 拿到方法定义的注解信息 | |||||
DataPermissionMethod annotation = objMethod.getDeclaredAnnotation(DataPermissionMethod.class); | |||||
// 返回 | |||||
return annotation; | |||||
} | |||||
} |
@@ -25,7 +25,7 @@ import java.io.Serializable; | |||||
/** | /** | ||||
* @description 镜像基础类DTO | * @description 镜像基础类DTO | ||||
* @date: 2020-07-14 | |||||
* @date 2020-07-14 | |||||
*/ | */ | ||||
@Data | @Data | ||||
@Accessors(chain = true) | @Accessors(chain = true) | ||||
@@ -0,0 +1,77 @@ | |||||
/** | |||||
* Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||||
* | |||||
* 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.dubhe.base; | |||||
import org.dubhe.constant.PermissionConstant; | |||||
import org.dubhe.domain.dto.UserDTO; | |||||
import org.dubhe.domain.entity.Role; | |||||
import org.dubhe.exception.BaseErrorCode; | |||||
import org.dubhe.exception.BusinessException; | |||||
import org.dubhe.utils.JwtUtils; | |||||
import org.springframework.util.CollectionUtils; | |||||
import java.util.List; | |||||
import java.util.Objects; | |||||
import java.util.stream.Collectors; | |||||
/** | |||||
* @description 服务层基础数据公共方法类 | |||||
* @date 2020-03-27 | |||||
*/ | |||||
public class BaseService { | |||||
private BaseService (){} | |||||
/** | |||||
* 校验是否具有管理员权限 | |||||
*/ | |||||
public static void checkAdminPermission() { | |||||
if(!isAdmin()){ | |||||
throw new BusinessException(BaseErrorCode.DATASET_ADMIN_PERMISSION_ERROR); | |||||
} | |||||
} | |||||
/** | |||||
* 校验是否是管理管理员 | |||||
* | |||||
* @return 校验标识 | |||||
*/ | |||||
public static Boolean isAdmin() { | |||||
UserDTO currentUserDto = JwtUtils.getCurrentUserDto(); | |||||
if (currentUserDto != null && !CollectionUtils.isEmpty(currentUserDto.getRoles())) { | |||||
List<Role> roles = currentUserDto.getRoles(); | |||||
List<Role> roleList = roles.stream(). | |||||
filter(a -> a.getId().compareTo(PermissionConstant.ADMIN_USER_ID) == 0) | |||||
.collect(Collectors.toList()); | |||||
if (!CollectionUtils.isEmpty(roleList)) { | |||||
return true; | |||||
} | |||||
} | |||||
return false; | |||||
} | |||||
/** | |||||
* 清除本地线程数据权限数据 | |||||
*/ | |||||
public static void removeContext(){ | |||||
if( !Objects.isNull(DataContext.get())){ | |||||
DataContext.remove(); | |||||
} | |||||
} | |||||
} |
@@ -24,8 +24,8 @@ import java.io.Serializable; | |||||
import java.sql.Timestamp; | import java.sql.Timestamp; | ||||
/** | /** | ||||
* @description: VO基础类 | |||||
* @date: 2020-05-22 | |||||
* @description VO基础类 | |||||
* @date 2020-05-22 | |||||
*/ | */ | ||||
@Data | @Data | ||||
public class BaseVO implements Serializable { | public class BaseVO implements Serializable { | ||||
@@ -0,0 +1,62 @@ | |||||
/** | |||||
* Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||||
* | |||||
* 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.dubhe.base; | |||||
import org.dubhe.domain.dto.CommonPermissionDataDTO; | |||||
/** | |||||
* @description 共享上下文数据集信息 | |||||
* @date 2020-04-10 | |||||
*/ | |||||
public class DataContext { | |||||
/** | |||||
* 私有化构造参数 | |||||
*/ | |||||
private DataContext() { | |||||
} | |||||
private static final ThreadLocal<CommonPermissionDataDTO> CONTEXT = new ThreadLocal<>(); | |||||
/** | |||||
* 存放数据集信息 | |||||
* | |||||
* @param datasetVO | |||||
*/ | |||||
public static void set(CommonPermissionDataDTO datasetVO) { | |||||
CONTEXT.set(datasetVO); | |||||
} | |||||
/** | |||||
* 获取用户信息 | |||||
* | |||||
* @return | |||||
*/ | |||||
public static CommonPermissionDataDTO get() { | |||||
return CONTEXT.get(); | |||||
} | |||||
/** | |||||
* 清除当前线程内引用,防止内存泄漏 | |||||
*/ | |||||
public static void remove() { | |||||
CONTEXT.remove(); | |||||
} | |||||
} |
@@ -18,7 +18,8 @@ | |||||
package org.dubhe.base; | package org.dubhe.base; | ||||
/** | /** | ||||
* @date: 2020-05-14 | |||||
* @description 常用常量类 | |||||
* @date 2020-05-14 | |||||
*/ | */ | ||||
public final class MagicNumConstant { | public final class MagicNumConstant { | ||||
@@ -86,6 +87,7 @@ public final class MagicNumConstant { | |||||
public static final long TWELVE_LONG = 12L; | public static final long TWELVE_LONG = 12L; | ||||
public static final long SIXTY_LONG = 60L; | public static final long SIXTY_LONG = 60L; | ||||
public static final long THOUSAND_LONG = 1000L; | |||||
public static final long TEN_THOUSAND_LONG = 10000L; | public static final long TEN_THOUSAND_LONG = 10000L; | ||||
public static final long ONE_ZERO_ONE_ZERO_ONE_ZERO_LONG = 101010L; | public static final long ONE_ZERO_ONE_ZERO_ONE_ZERO_LONG = 101010L; | ||||
public static final long NINE_ZERO_NINE_ZERO_NINE_ZERO_LONG = 909090L; | public static final long NINE_ZERO_NINE_ZERO_NINE_ZERO_LONG = 909090L; | ||||
@@ -26,8 +26,8 @@ import org.dubhe.constant.NumberConstant; | |||||
import javax.validation.constraints.Min; | import javax.validation.constraints.Min; | ||||
/** | /** | ||||
* @description: 分页基类 | |||||
* @date: 2020-05-8 | |||||
* @description 分页基类 | |||||
* @date 2020-05-08 | |||||
*/ | */ | ||||
@Data | @Data | ||||
@Accessors(chain = true) | @Accessors(chain = true) | ||||
@@ -14,32 +14,31 @@ | |||||
* limitations under the License. | * limitations under the License. | ||||
* ============================================================= | * ============================================================= | ||||
*/ | */ | ||||
package org.dubhe.task; | |||||
package org.dubhe.base; | |||||
import org.dubhe.enums.LogEnum; | import org.dubhe.enums.LogEnum; | ||||
import org.dubhe.service.PtImageService; | |||||
import org.dubhe.utils.LogUtil; | import org.dubhe.utils.LogUtil; | ||||
import org.springframework.beans.factory.annotation.Autowired; | |||||
import org.springframework.scheduling.annotation.Scheduled; | |||||
import org.springframework.stereotype.Component; | |||||
/** | /** | ||||
* @description 从harbor同步projectName | |||||
* @date 2020-6-23 | |||||
**/ | |||||
@Component | |||||
public class HarborProjectNameSyncTask { | |||||
* @description 定时任务处理器, 主要做日志标识 | |||||
* @date 2020-08-13 | |||||
*/ | |||||
public class ScheduleTaskHandler { | |||||
public static void process(Handler handler) { | |||||
LogUtil.startScheduleTrace(); | |||||
try { | |||||
handler.run(); | |||||
} catch (Exception e) { | |||||
LogUtil.error(LogEnum.BIZ_SYS, "There is something wrong in schedule task handler :{}", e); | |||||
} finally { | |||||
LogUtil.cleanTrace(); | |||||
} | |||||
} | |||||
@Autowired | |||||
private PtImageService ptImageService; | |||||
/** | |||||
* 每天晚上11点开始同步 | |||||
**/ | |||||
@Scheduled(cron = "0 0 23 * * ?") | |||||
public void syncProjectName() { | |||||
LogUtil.info(LogEnum.BIZ_TRAIN, "开始到harbor同步projectName到harbor_project表。。。。。"); | |||||
ptImageService.harborImageNameSync(); | |||||
public interface Handler { | |||||
void run(); | |||||
} | } | ||||
} | } |
@@ -1,65 +0,0 @@ | |||||
/** | |||||
* Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||||
* | |||||
* 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.dubhe.config; | |||||
import com.google.code.kaptcha.impl.DefaultKaptcha; | |||||
import com.google.code.kaptcha.util.Config; | |||||
import org.springframework.context.annotation.Bean; | |||||
import org.springframework.stereotype.Component; | |||||
import java.util.Properties; | |||||
/** | |||||
* @description 验证码配置 | |||||
* @date 2020-02-23 | |||||
*/ | |||||
@Component | |||||
public class KaptchaConfig { | |||||
private final static String CODE_LENGTH = "4"; | |||||
private final static String SESSION_KEY = "verification_session_key"; | |||||
@Bean | |||||
public DefaultKaptcha defaultKaptcha() { | |||||
DefaultKaptcha defaultKaptcha = new DefaultKaptcha(); | |||||
Properties properties = new Properties(); | |||||
// 设置边框 | |||||
properties.setProperty("kaptcha.border", "yes"); | |||||
// 设置边框颜色 | |||||
properties.setProperty("kaptcha.border.color", "105,179,90"); | |||||
// 设置字体颜色 | |||||
properties.setProperty("kaptcha.textproducer.font.color", "blue"); | |||||
// 设置图片宽度 | |||||
properties.setProperty("kaptcha.image.width", "108"); | |||||
// 设置图片高度 | |||||
properties.setProperty("kaptcha.image.height", "28"); | |||||
// 设置字体尺寸 | |||||
properties.setProperty("kaptcha.textproducer.font.size", "26"); | |||||
// 设置session key | |||||
properties.setProperty("kaptcha.session.key", SESSION_KEY); | |||||
// 设置验证码长度 | |||||
properties.setProperty("kaptcha.textproducer.char.length", CODE_LENGTH); | |||||
// 设置字体 | |||||
properties.setProperty("kaptcha.textproducer.font.names", "宋体,楷体,黑体"); | |||||
//去噪点 | |||||
properties.setProperty("kaptcha.noise.impl", "com.google.code.kaptcha.impl.NoNoise"); | |||||
Config config = new Config(properties); | |||||
defaultKaptcha.setConfig(config); | |||||
return defaultKaptcha; | |||||
} | |||||
} |
@@ -1,12 +1,12 @@ | |||||
/** | /** | ||||
* Copyright 2020 Zhejiang Lab. All Rights Reserved. | * Copyright 2020 Zhejiang Lab. All Rights Reserved. | ||||
* | |||||
* | |||||
* Licensed under the Apache License, Version 2.0 (the "License"); | * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
* you may not use this file except in compliance with the License. | * you may not use this file except in compliance with the License. | ||||
* You may obtain a copy of the License at | * You may obtain a copy of the License at | ||||
* | |||||
* | |||||
* http://www.apache.org/licenses/LICENSE-2.0 | * http://www.apache.org/licenses/LICENSE-2.0 | ||||
* | |||||
* | |||||
* Unless required by applicable law or agreed to in writing, software | * Unless required by applicable law or agreed to in writing, software | ||||
* distributed under the License is distributed on an "AS IS" BASIS, | * distributed under the License is distributed on an "AS IS" BASIS, | ||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
@@ -30,21 +30,17 @@ import java.util.Objects; | |||||
/** | /** | ||||
* @description 处理新增和更新的基础数据填充,配合BaseEntity和MyBatisPlusConfig使用 | * @description 处理新增和更新的基础数据填充,配合BaseEntity和MyBatisPlusConfig使用 | ||||
* @date 2020-6-10 | |||||
* @date 2020-06-10 | |||||
*/ | */ | ||||
@Component | @Component | ||||
public class MetaHandlerConfig implements MetaObjectHandler { | public class MetaHandlerConfig implements MetaObjectHandler { | ||||
private final String LOCK_USER_ID = "LOCK_USER_ID"; | |||||
/** | /** | ||||
* 新增数据执行 | * 新增数据执行 | ||||
* | * | ||||
* @param metaObject | |||||
* @param metaObject 基础数据 | |||||
*/ | */ | ||||
@Override | @Override | ||||
public void insertFill(MetaObject metaObject) { | public void insertFill(MetaObject metaObject) { | ||||
if (Objects.isNull(getFieldValByName(StringConstant.CREATE_TIME, metaObject))) { | if (Objects.isNull(getFieldValByName(StringConstant.CREATE_TIME, metaObject))) { | ||||
@@ -53,13 +49,14 @@ public class MetaHandlerConfig implements MetaObjectHandler { | |||||
if (Objects.isNull(getFieldValByName(StringConstant.UPDATE_TIME, metaObject))) { | if (Objects.isNull(getFieldValByName(StringConstant.UPDATE_TIME, metaObject))) { | ||||
this.setFieldValByName(StringConstant.UPDATE_TIME, DateUtil.getCurrentTimestamp(), metaObject); | this.setFieldValByName(StringConstant.UPDATE_TIME, DateUtil.getCurrentTimestamp(), metaObject); | ||||
} | } | ||||
synchronized (LOCK_USER_ID){ | |||||
if (Objects.isNull(getFieldValByName(StringConstant.UPDATE_USER_ID, metaObject))) { | |||||
this.setFieldValByName(StringConstant.UPDATE_USER_ID, getUserId(), metaObject); | |||||
} | |||||
if (Objects.isNull(getFieldValByName(StringConstant.CREATE_USER_ID, metaObject))) { | |||||
this.setFieldValByName(StringConstant.CREATE_USER_ID, getUserId(), metaObject); | |||||
} | |||||
if (Objects.isNull(getFieldValByName(StringConstant.UPDATE_USER_ID, metaObject))) { | |||||
this.setFieldValByName(StringConstant.UPDATE_USER_ID, getUserId(), metaObject); | |||||
} | |||||
if (Objects.isNull(getFieldValByName(StringConstant.CREATE_USER_ID, metaObject))) { | |||||
this.setFieldValByName(StringConstant.CREATE_USER_ID, getUserId(), metaObject); | |||||
} | |||||
if (Objects.isNull(getFieldValByName(StringConstant.ORIGIN_USER_ID, metaObject))) { | |||||
this.setFieldValByName(StringConstant.ORIGIN_USER_ID, getUserId(), metaObject); | |||||
} | } | ||||
if (Objects.isNull(getFieldValByName(StringConstant.DELETED, metaObject))) { | if (Objects.isNull(getFieldValByName(StringConstant.DELETED, metaObject))) { | ||||
this.setFieldValByName(StringConstant.DELETED, SwitchEnum.getBooleanValue(SwitchEnum.OFF.getValue()), metaObject); | this.setFieldValByName(StringConstant.DELETED, SwitchEnum.getBooleanValue(SwitchEnum.OFF.getValue()), metaObject); | ||||
@@ -69,7 +66,7 @@ public class MetaHandlerConfig implements MetaObjectHandler { | |||||
/** | /** | ||||
* 更新数据执行 | * 更新数据执行 | ||||
* | * | ||||
* @param metaObject | |||||
* @param metaObject 基础数据 | |||||
*/ | */ | ||||
@Override | @Override | ||||
public void updateFill(MetaObject metaObject) { | public void updateFill(MetaObject metaObject) { | ||||
@@ -17,294 +17,27 @@ | |||||
package org.dubhe.config; | package org.dubhe.config; | ||||
import com.baomidou.mybatisplus.core.override.MybatisMapperProxy; | |||||
import com.baomidou.mybatisplus.core.parser.ISqlParser; | |||||
import com.baomidou.mybatisplus.core.parser.SqlParserHelper; | |||||
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor; | |||||
import com.baomidou.mybatisplus.extension.plugins.tenant.TenantHandler; | |||||
import com.baomidou.mybatisplus.extension.plugins.tenant.TenantSqlParser; | |||||
import com.google.common.collect.Sets; | |||||
import net.sf.jsqlparser.expression.Expression; | |||||
import net.sf.jsqlparser.expression.LongValue; | |||||
import net.sf.jsqlparser.expression.operators.relational.ExpressionList; | |||||
import net.sf.jsqlparser.expression.operators.relational.InExpression; | |||||
import net.sf.jsqlparser.schema.Column; | |||||
import org.apache.ibatis.mapping.MappedStatement; | |||||
import org.apache.shiro.UnavailableSecurityManagerException; | |||||
import org.dubhe.annotation.DataPermission; | |||||
import org.dubhe.base.MagicNumConstant; | |||||
import org.dubhe.constant.PermissionConstant; | |||||
import org.dubhe.domain.dto.UserDTO; | |||||
import org.dubhe.domain.entity.Role; | |||||
import org.dubhe.enums.LogEnum; | |||||
import org.dubhe.utils.JwtUtils; | |||||
import org.dubhe.utils.LogUtil; | |||||
import org.springframework.beans.BeansException; | |||||
import org.springframework.context.ApplicationContext; | |||||
import org.springframework.context.ApplicationContextAware; | |||||
import org.springframework.context.ApplicationListener; | |||||
import org.dubhe.interceptor.PaginationInterceptor; | |||||
import org.springframework.context.annotation.Bean; | import org.springframework.context.annotation.Bean; | ||||
import org.springframework.context.annotation.Configuration; | import org.springframework.context.annotation.Configuration; | ||||
import org.springframework.context.event.ContextRefreshedEvent; | |||||
import org.springframework.core.annotation.AnnotationUtils; | |||||
import org.springframework.transaction.annotation.EnableTransactionManagement; | import org.springframework.transaction.annotation.EnableTransactionManagement; | ||||
import org.springframework.util.CollectionUtils; | |||||
import java.lang.annotation.Annotation; | |||||
import java.lang.reflect.Field; | |||||
import java.lang.reflect.Method; | |||||
import java.lang.reflect.Proxy; | |||||
import java.util.*; | |||||
import java.util.stream.Collectors; | |||||
/** | /** | ||||
* @description MybatisPlus配置类 | |||||
* @date 2020-06-24 | |||||
* @description mybatis plus拦截器 | |||||
* @date 2020-06-10 | |||||
*/ | */ | ||||
@EnableTransactionManagement | @EnableTransactionManagement | ||||
@Configuration | @Configuration | ||||
public class MybatisPlusConfig implements ApplicationListener<ContextRefreshedEvent>, ApplicationContextAware { | |||||
/** | |||||
* 以此字段作为租户实现数据隔离 | |||||
*/ | |||||
private static final String TENANT_ID_COLUMN = "create_user_id"; | |||||
/** | |||||
* 以0作为公共数据的标识 | |||||
*/ | |||||
private static final long PUBLIC_TENANT_ID = MagicNumConstant.ZERO; | |||||
private static final Set<Long> PUBLIC_TENANT_ID_SET = new HashSet<Long>() {{ | |||||
add(PUBLIC_TENANT_ID); | |||||
}}; | |||||
private static final String PACKAGE_SEPARATOR = "."; | |||||
private static final Set<String> SELECT_PERMISSION = new HashSet<String>() {{ | |||||
add(PermissionConstant.SELECT); | |||||
}}; | |||||
private static final Set<String> UPDATE_DELETE_PERMISSION = new HashSet<String>() {{ | |||||
add(PermissionConstant.UPDATE); | |||||
add(PermissionConstant.DELETE); | |||||
}}; | |||||
public class MybatisPlusConfig { | |||||
private static final String SELECT_STR = "select"; | |||||
/** | /** | ||||
* 优先级高于dataFilters,如果ignore,则不进行sql注入 | |||||
*/ | |||||
private Map<String, Set<String>> dataFilters = new HashMap<>(); | |||||
private ApplicationContext applicationContext; | |||||
public Set<Long> tenantId; | |||||
/** | |||||
* mybatis plus 分页插件 | |||||
* 其中增加了通过多租户实现了数据权限功能 | |||||
* 注入 MybatisPlus 分页拦截器 | |||||
* | * | ||||
* @return | |||||
* @return 自定义MybatisPlus分页拦截器 | |||||
*/ | */ | ||||
@Bean | @Bean | ||||
public PaginationInterceptor paginationInterceptor() { | public PaginationInterceptor paginationInterceptor() { | ||||
PaginationInterceptor paginationInterceptor = new PaginationInterceptor(); | PaginationInterceptor paginationInterceptor = new PaginationInterceptor(); | ||||
List<ISqlParser> sqlParserList = new ArrayList<>(); | |||||
TenantSqlParser tenantSqlParser = new TenantSqlParser(); | |||||
tenantSqlParser.setTenantHandler(new TenantHandler() { | |||||
@Override | |||||
public Expression getTenantId(boolean where) { | |||||
Set<Long> tenants = tenantId; | |||||
final boolean multipleTenantIds = tenants.size() > MagicNumConstant.ONE; | |||||
if (multipleTenantIds) { | |||||
return multipleTenantIdCondition(tenants); | |||||
} else { | |||||
return singleTenantIdCondition(tenants); | |||||
} | |||||
} | |||||
private Expression singleTenantIdCondition(Set<Long> tenants) { | |||||
return new LongValue((Long) tenants.toArray()[0]); | |||||
} | |||||
private Expression multipleTenantIdCondition(Set<Long> tenants) { | |||||
final InExpression inExpression = new InExpression(); | |||||
inExpression.setLeftExpression(new Column(getTenantIdColumn())); | |||||
final ExpressionList itemsList = new ExpressionList(); | |||||
final List<Expression> inValues = new ArrayList<>(tenants.size()); | |||||
tenants.forEach(i -> | |||||
inValues.add(new LongValue(i)) | |||||
); | |||||
itemsList.setExpressions(inValues); | |||||
inExpression.setRightItemsList(itemsList); | |||||
return inExpression; | |||||
} | |||||
@Override | |||||
public String getTenantIdColumn() { | |||||
return TENANT_ID_COLUMN; | |||||
} | |||||
@Override | |||||
public boolean doTableFilter(String tableName) { | |||||
return false; | |||||
} | |||||
}); | |||||
sqlParserList.add(tenantSqlParser); | |||||
paginationInterceptor.setSqlParserList(sqlParserList); | |||||
paginationInterceptor.setSqlParserFilter(metaObject -> { | |||||
MappedStatement ms = SqlParserHelper.getMappedStatement(metaObject); | |||||
String method = ms.getId(); | |||||
if (!dataFilters.containsKey(method) || isAdmin()) { | |||||
return true; | |||||
} | |||||
Set<String> permission = dataFilters.get(method); | |||||
tenantId = getTenantId(permission); | |||||
return false; | |||||
}); | |||||
return paginationInterceptor; | return paginationInterceptor; | ||||
} | } | ||||
/** | |||||
* 判断用户是否是管理员 | |||||
* 如果未登录,无法请求任何接口,所以不会到该层,因此匿名认为是定时任务,给予admin权限。 | |||||
* | |||||
* @return 判断用户是否是管理员 | |||||
*/ | |||||
private boolean isAdmin() { | |||||
UserDTO user; | |||||
try { | |||||
user = JwtUtils.getCurrentUserDto(); | |||||
} catch (UnavailableSecurityManagerException e) { | |||||
return true; | |||||
} | |||||
if (Objects.isNull(user)) { | |||||
return true; | |||||
} | |||||
List<Role> roles; | |||||
if ((roles = user.getRoles()) == null) { | |||||
return false; | |||||
} | |||||
Set<String> permissions = roles.stream().map(Role::getPermission).collect(Collectors.toSet()); | |||||
if (CollectionUtils.isEmpty(permissions)) { | |||||
return false; | |||||
} | |||||
return user.getId() == PermissionConstant.ANONYMOUS_USER || user.getId() == PermissionConstant.ADMIN_USER_ID; | |||||
} | |||||
/** | |||||
* 如果是管理员,在前一步isAdmin已过滤; | |||||
* 如果是匿名用户,在shiro层被过滤; | |||||
* 因此只会是无角色、权限用户或普通用户 | |||||
* | |||||
* @return Set<Long> 租户ID集合 | |||||
*/ | |||||
private Set<Long> getTenantId(Set<String> permission) { | |||||
UserDTO user = JwtUtils.getCurrentUserDto(); | |||||
List<Role> roles; | |||||
if (Objects.isNull(user) || (roles = user.getRoles()) == null) { | |||||
if (permission.contains(PermissionConstant.SELECT)) { | |||||
return PUBLIC_TENANT_ID_SET; | |||||
} | |||||
return Collections.EMPTY_SET; | |||||
} | |||||
Set<String> permissions = roles.stream().map(Role::getPermission).collect(Collectors.toSet()); | |||||
if (CollectionUtils.isEmpty(permissions)) { | |||||
if (permission.contains(PermissionConstant.SELECT)) { | |||||
return PUBLIC_TENANT_ID_SET; | |||||
} | |||||
return Collections.EMPTY_SET; | |||||
} | |||||
if (permission.contains(PermissionConstant.SELECT)) { | |||||
return new HashSet<Long>() {{ | |||||
add(PUBLIC_TENANT_ID); | |||||
add(user.getId()); | |||||
}}; | |||||
} | |||||
return new HashSet<Long>() {{ | |||||
add(user.getId()); | |||||
}}; | |||||
} | |||||
/** | |||||
* 设置上下文 | |||||
* #需要通过上下文 获取SpringBean | |||||
* | |||||
* @param applicationContext spring上下文 | |||||
* @throws BeansException 找不到bean异常 | |||||
*/ | |||||
@Override | |||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { | |||||
this.applicationContext = applicationContext; | |||||
} | |||||
@Override | |||||
public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) { | |||||
Class<? extends Annotation> annotationClass = DataPermission.class; | |||||
Map<String, Object> beanWithAnnotation = applicationContext.getBeansWithAnnotation(annotationClass); | |||||
Set<Map.Entry<String, Object>> entitySet = beanWithAnnotation.entrySet(); | |||||
for (Map.Entry<String, Object> entry : entitySet) { | |||||
Proxy proxy = (Proxy) entry.getValue(); | |||||
Class clazz = getMapperClass(proxy); | |||||
populateDataFilters(clazz); | |||||
} | |||||
} | |||||
/** | |||||
* 根据mapper对应代理对象获取Class | |||||
* | |||||
* @param proxy mapper对应代理对象 | |||||
* @return | |||||
*/ | |||||
private Class getMapperClass(Proxy proxy) { | |||||
try { | |||||
Field field = proxy.getClass().getSuperclass().getDeclaredField("h"); | |||||
field.setAccessible(true); | |||||
MybatisMapperProxy mapperProxy = (MybatisMapperProxy) field.get(proxy); | |||||
field = mapperProxy.getClass().getDeclaredField("mapperInterface"); | |||||
field.setAccessible(true); | |||||
return (Class) field.get(mapperProxy); | |||||
} catch (NoSuchFieldException | IllegalAccessException e) { | |||||
LogUtil.error(LogEnum.BIZ_DATASET, "reflect error", e); | |||||
} | |||||
return null; | |||||
} | |||||
/** | |||||
* 填充数据权限过滤,处理那些需要排除的方法 | |||||
* | |||||
* @param clazz 需要处理的类(mapper) | |||||
*/ | |||||
private void populateDataFilters(Class clazz) { | |||||
if (clazz == null) { | |||||
return; | |||||
} | |||||
Method[] methods = clazz.getMethods(); | |||||
DataPermission dataPermission = AnnotationUtils.findAnnotation((Class<?>) clazz, DataPermission.class); | |||||
Set<String> ignores = Sets.newHashSet(dataPermission.ignores()); | |||||
for (Method method : methods) { | |||||
if (ignores.contains(method.getName())) { | |||||
continue; | |||||
} | |||||
Set<String> permission = getDataPermission(method); | |||||
dataFilters.put(clazz.getName() + PACKAGE_SEPARATOR + method.getName(), permission); | |||||
} | |||||
} | |||||
/** | |||||
* 获取方法上权限注解 | |||||
* 权限注解包含 | |||||
* 1.用户拥有指定权限才可以执行该方法:比如 PermissionConstant.SELECT 表示用户必须拥有select权限,才可以使用该方法 | |||||
* 2.方法权限校验排除:比如 ignores = {"insert"} 表示insert方法不做权限处理 | |||||
* | |||||
* @param method 方法对象 | |||||
* @return | |||||
*/ | |||||
private Set<String> getDataPermission(Method method) { | |||||
DataPermission dataPermission = AnnotationUtils.findAnnotation(method, DataPermission.class); | |||||
// 无注解时以方法名判断 | |||||
if (dataPermission == null) { | |||||
if (method.getName().contains(SELECT_STR)) { | |||||
return SELECT_PERMISSION; | |||||
} | |||||
return UPDATE_DELETE_PERMISSION; | |||||
} | |||||
return Sets.newHashSet(dataPermission.permission()); | |||||
} | |||||
} | } | ||||
@@ -0,0 +1,62 @@ | |||||
/** | |||||
* Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||||
* | |||||
* 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.dubhe.config; | |||||
import lombok.Data; | |||||
import org.springframework.boot.context.properties.ConfigurationProperties; | |||||
import org.springframework.stereotype.Component; | |||||
/** | |||||
* @description 垃圾回收机制配置常量 | |||||
* @date 2020-09-21 | |||||
*/ | |||||
@Data | |||||
@Component | |||||
@ConfigurationProperties(prefix = "recycle.timeout") | |||||
public class RecycleConfig { | |||||
/** | |||||
* 回收无效文件的默认有效时长 | |||||
*/ | |||||
private Integer date; | |||||
/** | |||||
* 用户上传文件至临时路径下后文件最大有效时长,以小时为单位 | |||||
*/ | |||||
private Integer fileValid; | |||||
/** | |||||
* 用户删除某一算法后,其算法文件最大有效时长,以天为单位 | |||||
*/ | |||||
private Integer algorithmValid; | |||||
/** | |||||
* 用户删除某一模型后,其模型文件最大有效时长,以天为单位 | |||||
*/ | |||||
private Integer modelValid; | |||||
/** | |||||
* 用户删除训练任务后,其训练管理文件最大有效时长,以天为单位 | |||||
*/ | |||||
private Integer trainValid; | |||||
/** | |||||
* 删除服务器无效文件(大文件) | |||||
* 示例:rsync --delete-before -d /空目录 /需要回收的源目录 | |||||
*/ | |||||
public static final String DEL_COMMAND = "ssh %s@%s \"mkdir -p %s; rsync --delete-before -d %s %s; rmdir %s %s\""; | |||||
} |
@@ -15,77 +15,71 @@ | |||||
* ============================================================= | * ============================================================= | ||||
*/ | */ | ||||
package org.dubhe.constant; | |||||
package org.dubhe.config; | |||||
import lombok.Data; | import lombok.Data; | ||||
import org.springframework.beans.factory.annotation.Value; | |||||
import org.springframework.boot.context.properties.ConfigurationProperties; | |||||
import org.springframework.stereotype.Component; | import org.springframework.stereotype.Component; | ||||
/** | /** | ||||
* @description 训练常量 | * @description 训练常量 | ||||
* @create: 2020-05-12 | |||||
* @date 2020-05-12 | |||||
*/ | */ | ||||
@Component | @Component | ||||
@Data | @Data | ||||
public class TrainJobConstant { | |||||
@ConfigurationProperties(prefix = "train-job") | |||||
public class TrainJobConfig { | |||||
@Value("${train-job.namespace}") | |||||
private String namespace; | private String namespace; | ||||
@Value("${train-job.version-label}") | |||||
private String versionLabel; | private String versionLabel; | ||||
@Value("${train-job.separator}") | |||||
private String separator; | private String separator; | ||||
@Value("${train-job.pod-name}") | |||||
private String podName; | private String podName; | ||||
@Value("${train-job.python-format}") | |||||
private String pythonFormat; | private String pythonFormat; | ||||
@Value("${train-job.manage}") | |||||
private String manage; | private String manage; | ||||
@Value("${train-job.out-path}") | |||||
private String outPath; | private String outPath; | ||||
@Value("${train-job.log-path}") | |||||
private String logPath; | private String logPath; | ||||
@Value("${train-job.visualized-log-path}") | |||||
private String visualizedLogPath; | private String visualizedLogPath; | ||||
@Value("${train-job.docker-dataset-path}") | |||||
private String dockerDatasetPath; | private String dockerDatasetPath; | ||||
@Value("${train-job.docker-train-path}") | |||||
private String dockerTrainPath; | private String dockerTrainPath; | ||||
@Value("${train-job.docker-out-path}") | |||||
private String dockerOutPath; | private String dockerOutPath; | ||||
@Value("${train-job.docker-log-path}") | |||||
private String dockerLogPath; | private String dockerLogPath; | ||||
@Value("${train-job.docker-dataset}") | |||||
private String dockerDataset; | private String dockerDataset; | ||||
@Value("${train-job.docker-visualized-log-path}") | |||||
private String dockerModelPath; | |||||
private String dockerValDatasetPath; | |||||
private String loadValDatasetKey; | |||||
private String dockerVisualizedLogPath; | private String dockerVisualizedLogPath; | ||||
@Value("${train-job.load-path}") | |||||
private String loadPath; | private String loadPath; | ||||
@Value("${train-job.load-key}") | |||||
private String loadKey; | private String loadKey; | ||||
@Value("${train-job.eight}") | |||||
private String eight; | private String eight; | ||||
@Value("${train-job.plus-eight}") | |||||
private String plusEight; | private String plusEight; | ||||
private String nodeIps; | |||||
private String nodeNum; | |||||
private String gpuNumPerNode; | |||||
public static final String TRAIN_ID = "trainId"; | public static final String TRAIN_ID = "trainId"; | ||||
public static final String TRAIN_VERSION = "trainVersion"; | public static final String TRAIN_VERSION = "trainVersion"; | ||||
@@ -97,4 +91,5 @@ public class TrainJobConstant { | |||||
public static final String CREATE_TIME = "createTime"; | public static final String CREATE_TIME = "createTime"; | ||||
public static final String ALGORITHM_NAME = "algorithmName"; | public static final String ALGORITHM_NAME = "algorithmName"; | ||||
} | } |
@@ -16,9 +16,13 @@ | |||||
*/ | */ | ||||
package org.dubhe.config; | package org.dubhe.config; | ||||
import org.dubhe.enums.LogEnum; | |||||
import org.dubhe.utils.LogUtil; | |||||
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler; | |||||
import org.springframework.beans.factory.annotation.Value; | import org.springframework.beans.factory.annotation.Value; | ||||
import org.springframework.context.annotation.Bean; | import org.springframework.context.annotation.Bean; | ||||
import org.springframework.context.annotation.Configuration; | import org.springframework.context.annotation.Configuration; | ||||
import org.springframework.scheduling.annotation.AsyncConfigurer; | |||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; | import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; | ||||
import java.util.concurrent.Executor; | import java.util.concurrent.Executor; | ||||
@@ -29,7 +33,7 @@ import java.util.concurrent.ThreadPoolExecutor; | |||||
* @date 2020-07-17 | * @date 2020-07-17 | ||||
*/ | */ | ||||
@Configuration | @Configuration | ||||
public class TrainPoolConfig { | |||||
public class TrainPoolConfig implements AsyncConfigurer { | |||||
@Value("${basepool.corePoolSize:40}") | @Value("${basepool.corePoolSize:40}") | ||||
private Integer corePoolSize; | private Integer corePoolSize; | ||||
@@ -44,8 +48,9 @@ public class TrainPoolConfig { | |||||
* 训练任务异步处理线程池 | * 训练任务异步处理线程池 | ||||
* @return Executor 线程实例 | * @return Executor 线程实例 | ||||
*/ | */ | ||||
@Bean | |||||
public Executor trainJobAsyncExecutor() { | |||||
@Bean("trainExecutor") | |||||
@Override | |||||
public Executor getAsyncExecutor() { | |||||
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor(); | ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor(); | ||||
//核心线程数 | //核心线程数 | ||||
taskExecutor.setCorePoolSize(corePoolSize); | taskExecutor.setCorePoolSize(corePoolSize); | ||||
@@ -57,10 +62,18 @@ public class TrainPoolConfig { | |||||
//配置队列大小 | //配置队列大小 | ||||
taskExecutor.setQueueCapacity(blockQueueSize); | taskExecutor.setQueueCapacity(blockQueueSize); | ||||
//配置线程池前缀 | //配置线程池前缀 | ||||
taskExecutor.setThreadNamePrefix("async-train-job-"); | |||||
taskExecutor.setThreadNamePrefix("async-train-"); | |||||
//拒绝策略 | //拒绝策略 | ||||
taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy()); | taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy()); | ||||
taskExecutor.initialize(); | taskExecutor.initialize(); | ||||
return taskExecutor; | return taskExecutor; | ||||
} | } | ||||
@Override | |||||
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { | |||||
LogUtil.error(LogEnum.BIZ_TRAIN, "开始捕获训练管理异步任务异常信息-----》》》"); | |||||
return (ex, method, params) -> { | |||||
LogUtil.error(LogEnum.BIZ_TRAIN, "训练管理方法名{}的异步任务执行失败,参数信息:{},异常信息:{}", method.getName(), params, ex); | |||||
}; | |||||
} | |||||
} | } |
@@ -18,8 +18,8 @@ | |||||
package org.dubhe.constant; | package org.dubhe.constant; | ||||
/** | /** | ||||
* @Description 数字常量 | |||||
* @Date 2020-6-9 | |||||
* @description 数字常量 | |||||
* @date 2020-06-09 | |||||
*/ | */ | ||||
public class NumberConstant { | public class NumberConstant { | ||||
@@ -32,6 +32,8 @@ public class NumberConstant { | |||||
public final static int NUMBER_30 = 30; | public final static int NUMBER_30 = 30; | ||||
public final static int NUMBER_50 = 50; | public final static int NUMBER_50 = 50; | ||||
public final static int NUMBER_60 = 60; | public final static int NUMBER_60 = 60; | ||||
public final static int NUMBER_1024 = 1024; | |||||
public final static int NUMBER_1000 = 1000; | |||||
public final static int HOUR_SECOND = 60 * 60; | public final static int HOUR_SECOND = 60 * 60; | ||||
public final static int DAY_SECOND = 60 * 60 * 24; | public final static int DAY_SECOND = 60 * 60 * 24; | ||||
public final static int WEEK_SECOND = 60 * 60 * 24 * 7; | public final static int WEEK_SECOND = 60 * 60 * 24 * 7; | ||||
@@ -21,8 +21,8 @@ import lombok.Data; | |||||
import org.springframework.stereotype.Component; | import org.springframework.stereotype.Component; | ||||
/** | /** | ||||
* @description: 权限常量 | |||||
* @since: 2020-05-25 14:39 | |||||
* @description 权限常量 | |||||
* @date 2020-05-25 | |||||
*/ | */ | ||||
@Component | @Component | ||||
@Data | @Data | ||||
@@ -32,9 +32,10 @@ public class PermissionConstant { | |||||
* 超级用户 | * 超级用户 | ||||
*/ | */ | ||||
public static final long ADMIN_USER_ID = 1L; | public static final long ADMIN_USER_ID = 1L; | ||||
public static final long ANONYMOUS_USER = -1L; | |||||
public static final String SELECT = "select"; | |||||
public static final String UPDATE = "update"; | |||||
public static final String DELETE = "delete"; | |||||
/** | |||||
* 数据集模块类型 | |||||
*/ | |||||
public static final Integer RESOURCE_DATA_MODEL = 1; | |||||
} | } |
@@ -23,24 +23,29 @@ package org.dubhe.constant; | |||||
*/ | */ | ||||
public final class StringConstant { | public final class StringConstant { | ||||
public static final String MSIE = "MSIE"; | |||||
public static final String MOZILLA = "Mozilla"; | |||||
public static final String MSIE = "MSIE"; | |||||
public static final String MOZILLA = "Mozilla"; | |||||
public static final String REQUEST_METHOD_GET = "GET"; | |||||
/** | |||||
* 公共字段 | |||||
*/ | |||||
public static final String CREATE_TIME = "createTime"; | |||||
public static final String UPDATE_TIME = "updateTime"; | |||||
public static final String UPDATE_USER_ID = "updateUserId"; | |||||
public static final String CREATE_USER_ID = "createUserId"; | |||||
public static final String DELETED = "deleted"; | |||||
public static final String UTF8 = "utf-8"; | |||||
/** | |||||
* 公共字段 | |||||
*/ | |||||
public static final String CREATE_TIME = "createTime"; | |||||
public static final String UPDATE_TIME = "updateTime"; | |||||
public static final String UPDATE_USER_ID = "updateUserId"; | |||||
public static final String CREATE_USER_ID = "createUserId"; | |||||
public static final String ORIGIN_USER_ID = "originUserId"; | |||||
public static final String DELETED = "deleted"; | |||||
public static final String UTF8 = "utf-8"; | |||||
public static final String JSON_REQUEST = "application/json"; | |||||
public static final String K8S_CALLBACK_URI = "/api/k8s/callback/pod"; | |||||
public static final String MULTIPART = "multipart/form-data"; | |||||
/** | |||||
* 测试环境 | |||||
*/ | |||||
public static final String PROFILE_ACTIVE_TEST = "test"; | |||||
/** | |||||
* 测试环境 | |||||
*/ | |||||
public static final String PROFILE_ACTIVE_TEST = "test"; | |||||
private StringConstant() { | |||||
} | |||||
private StringConstant() { | |||||
} | |||||
} | } |
@@ -19,7 +19,7 @@ package org.dubhe.constant; | |||||
/** | /** | ||||
* @description 符号常量 | * @description 符号常量 | ||||
* @Date 2020-5-29 | |||||
* @date 2020-5-29 | |||||
*/ | */ | ||||
public class SymbolConstant { | public class SymbolConstant { | ||||
public static final String SLASH = "/"; | public static final String SLASH = "/"; | ||||
@@ -40,6 +40,8 @@ public class SymbolConstant { | |||||
public static final String DOUBLE_MARK= "\"\""; | public static final String DOUBLE_MARK= "\"\""; | ||||
public static final String MARK= "\""; | public static final String MARK= "\""; | ||||
public static final String FLAG_EQUAL = "="; | |||||
private SymbolConstant() { | private SymbolConstant() { | ||||
} | } | ||||
@@ -17,15 +17,12 @@ | |||||
package org.dubhe.constant; | package org.dubhe.constant; | ||||
import org.springframework.stereotype.Component; | |||||
import lombok.Data; | import lombok.Data; | ||||
/** | /** | ||||
* @description 算法用途 | * @description 算法用途 | ||||
* @date: 2020-06-23 | |||||
* @date 2020-06-23 | |||||
*/ | */ | ||||
@Component | |||||
@Data | @Data | ||||
public class UserAuxiliaryInfoConstant { | public class UserAuxiliaryInfoConstant { | ||||
@@ -0,0 +1,52 @@ | |||||
/** | |||||
* Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||||
* | |||||
* 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.dubhe.domain.dto; | |||||
import lombok.AllArgsConstructor; | |||||
import lombok.Builder; | |||||
import lombok.Data; | |||||
import lombok.NoArgsConstructor; | |||||
import java.io.Serializable; | |||||
import java.util.Set; | |||||
/** | |||||
* @description 公共权限信息DTO | |||||
* @date 2020-09-24 | |||||
*/ | |||||
@AllArgsConstructor | |||||
@NoArgsConstructor | |||||
@Builder | |||||
@Data | |||||
public class CommonPermissionDataDTO implements Serializable { | |||||
/** | |||||
* 资源拥有者ID | |||||
*/ | |||||
private Long id; | |||||
/** | |||||
* 公共类型 | |||||
*/ | |||||
private Boolean type; | |||||
/** | |||||
* 资源所属用户ids | |||||
*/ | |||||
private Set<Long> resourceUserIds; | |||||
} |
@@ -16,15 +16,14 @@ | |||||
*/ | */ | ||||
package org.dubhe.domain.entity; | package org.dubhe.domain.entity; | ||||
import java.io.Serializable; | |||||
import org.dubhe.base.MagicNumConstant; | |||||
import com.alibaba.fastjson.annotation.JSONField; | |||||
import cn.hutool.core.date.DateUtil; | import cn.hutool.core.date.DateUtil; | ||||
import com.alibaba.fastjson.annotation.JSONField; | |||||
import lombok.Data; | import lombok.Data; | ||||
import lombok.experimental.Accessors; | import lombok.experimental.Accessors; | ||||
import org.dubhe.base.MagicNumConstant; | |||||
import java.io.Serializable; | |||||
/** | /** | ||||
* @description 日志对象封装类 | * @description 日志对象封装类 | ||||
@@ -34,31 +33,27 @@ import lombok.experimental.Accessors; | |||||
@Accessors(chain = true) | @Accessors(chain = true) | ||||
public class LogInfo implements Serializable { | public class LogInfo implements Serializable { | ||||
@JSONField(ordinal = MagicNumConstant.ONE) | |||||
private String traceId; | |||||
private static final long serialVersionUID = 5250395474667395607L; | |||||
@JSONField(ordinal = MagicNumConstant.ONE) | |||||
private String traceId; | |||||
@JSONField(ordinal = MagicNumConstant.TWO) | |||||
private String type; | |||||
@JSONField(ordinal = MagicNumConstant.TWO) | |||||
private String type; | |||||
@JSONField(ordinal = MagicNumConstant.THREE) | |||||
private String level; | |||||
@JSONField(ordinal = MagicNumConstant.THREE) | |||||
private String level; | |||||
@JSONField(ordinal = MagicNumConstant.FOUR) | |||||
private String cName; | |||||
@JSONField(ordinal = MagicNumConstant.FOUR) | |||||
private String location; | |||||
@JSONField(ordinal = MagicNumConstant.FIVE) | |||||
private String mName; | |||||
@JSONField(ordinal = MagicNumConstant.SIX) | |||||
private String line; | |||||
@JSONField(ordinal = MagicNumConstant.SEVEN) | |||||
private String time = DateUtil.now(); | |||||
@JSONField(ordinal = MagicNumConstant.FIVE) | |||||
private String time = DateUtil.now(); | |||||
@JSONField(ordinal = MagicNumConstant.EIGHT) | |||||
private Object info; | |||||
@JSONField(ordinal = MagicNumConstant.SIX) | |||||
private Object info; | |||||
public void setInfo(Object info) { | |||||
this.info = info; | |||||
} | |||||
public void setInfo(Object info) { | |||||
this.info = info; | |||||
} | |||||
} | } |
@@ -22,12 +22,9 @@ import lombok.Builder; | |||||
import lombok.Data; | import lombok.Data; | ||||
import lombok.NoArgsConstructor; | import lombok.NoArgsConstructor; | ||||
import org.dubhe.base.BaseEntity; | import org.dubhe.base.BaseEntity; | ||||
import org.hibernate.validator.constraints.Length; | |||||
import javax.validation.constraints.NotBlank; | import javax.validation.constraints.NotBlank; | ||||
import javax.validation.constraints.NotNull; | |||||
import java.io.Serializable; | import java.io.Serializable; | ||||
import java.sql.Timestamp; | |||||
import java.util.Objects; | import java.util.Objects; | ||||
/** | /** | ||||
@@ -22,12 +22,7 @@ import lombok.Builder; | |||||
import lombok.Data; | import lombok.Data; | ||||
import lombok.NoArgsConstructor; | import lombok.NoArgsConstructor; | ||||
import org.dubhe.base.BaseEntity; | import org.dubhe.base.BaseEntity; | ||||
import org.hibernate.validator.constraints.Length; | |||||
import javax.validation.constraints.NotBlank; | |||||
import javax.validation.constraints.NotEmpty; | |||||
import java.io.Serializable; | import java.io.Serializable; | ||||
import java.sql.Timestamp; | |||||
import java.util.Objects; | import java.util.Objects; | ||||
import java.util.Set; | import java.util.Set; | ||||
@@ -0,0 +1,73 @@ | |||||
/** | |||||
* Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||||
* | |||||
* 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.dubhe.dto; | |||||
import lombok.Data; | |||||
/** | |||||
* @description 全局请求日志信息 | |||||
* @date 2020-08-13 | |||||
*/ | |||||
@Data | |||||
public class GlobalRequestRecordDTO { | |||||
/** | |||||
* 客户主机地址 | |||||
*/ | |||||
private String clientHost; | |||||
/** | |||||
* 请求地址 | |||||
*/ | |||||
private String uri; | |||||
/** | |||||
* 授权信息 | |||||
*/ | |||||
private String authorization; | |||||
/** | |||||
* 用户名 | |||||
*/ | |||||
private String username; | |||||
/** | |||||
* form参数 | |||||
*/ | |||||
private String params; | |||||
/** | |||||
* 返回值类型 | |||||
*/ | |||||
private String contentType; | |||||
/** | |||||
* 返回状态 | |||||
*/ | |||||
private Integer status; | |||||
/** | |||||
* 时间耗费 | |||||
*/ | |||||
private Long timeCost; | |||||
/** | |||||
* 请求方式 | |||||
*/ | |||||
private String method; | |||||
/** | |||||
* 请求体body参数 | |||||
*/ | |||||
private String requestBody; | |||||
/** | |||||
* 返回值json数据 | |||||
*/ | |||||
private String responseBody; | |||||
} |
@@ -44,6 +44,14 @@ public class BaseK8sPodCallbackCreateDTO { | |||||
@NotEmpty(message = "podName 不能为空!") | @NotEmpty(message = "podName 不能为空!") | ||||
private String podName; | private String podName; | ||||
@ApiModelProperty(required = true,value = "k8s pod parent type") | |||||
@NotEmpty(message = "podParentType 不能为空!") | |||||
private String podParentType; | |||||
@ApiModelProperty(required = true,value = "k8s pod parent name") | |||||
@NotEmpty(message = "podParentName 不能为空!") | |||||
private String podParentName; | |||||
@ApiModelProperty(value = "k8s pod phase",notes = "对应PodPhaseEnum") | @ApiModelProperty(value = "k8s pod phase",notes = "对应PodPhaseEnum") | ||||
@NotEmpty(message = "phase 不能为空!") | @NotEmpty(message = "phase 不能为空!") | ||||
private String phase; | private String phase; | ||||
@@ -55,10 +63,12 @@ public class BaseK8sPodCallbackCreateDTO { | |||||
} | } | ||||
public BaseK8sPodCallbackCreateDTO(String namespace,String resourceName,String podName,String phase,String messages){ | |||||
public BaseK8sPodCallbackCreateDTO(String namespace,String resourceName,String podName,String podParentType,String podParentName,String phase,String messages){ | |||||
this.namespace = namespace; | this.namespace = namespace; | ||||
this.resourceName = resourceName; | this.resourceName = resourceName; | ||||
this.podName = podName; | this.podName = podName; | ||||
this.podParentType = podParentType; | |||||
this.podParentName = podParentName; | |||||
this.phase = phase; | this.phase = phase; | ||||
this.messages = messages; | this.messages = messages; | ||||
} | } | ||||
@@ -69,6 +79,8 @@ public class BaseK8sPodCallbackCreateDTO { | |||||
"namespace='" + namespace + '\'' + | "namespace='" + namespace + '\'' + | ||||
", resourceName='" + resourceName + '\'' + | ", resourceName='" + resourceName + '\'' + | ||||
", podName='" + podName + '\'' + | ", podName='" + podName + '\'' + | ||||
", podParentType='" + podParentType + '\'' + | |||||
", podParentName='" + podParentName + '\'' + | |||||
", phase='" + phase + '\'' + | ", phase='" + phase + '\'' + | ||||
", messages=" + messages + | ", messages=" + messages + | ||||
'}'; | '}'; | ||||
@@ -23,9 +23,8 @@ import java.util.HashMap; | |||||
import java.util.Map; | import java.util.Map; | ||||
/** | /** | ||||
* @desc: 业务模块 | |||||
* | |||||
* @date 2020.05.25 | |||||
* @description 业务模块 | |||||
* @date 2020-05-25 | |||||
*/ | */ | ||||
@Getter | @Getter | ||||
public enum BizEnum { | public enum BizEnum { | ||||
@@ -38,6 +37,10 @@ public enum BizEnum { | |||||
* 算法管理 | * 算法管理 | ||||
*/ | */ | ||||
ALGORITHM("算法管理","algorithm",1), | ALGORITHM("算法管理","algorithm",1), | ||||
/** | |||||
* 模型管理 | |||||
*/ | |||||
MODEL("模型管理","model",2), | |||||
; | ; | ||||
/** | /** | ||||
@@ -21,8 +21,8 @@ import java.util.HashMap; | |||||
import java.util.Map; | import java.util.Map; | ||||
/** | /** | ||||
* @desc: 业务NFS路径枚举 | |||||
* @date 2020.05.13 | |||||
* @description 业务NFS路径枚举 | |||||
* @date 2020-05-13 | |||||
*/ | */ | ||||
public enum BizNfsEnum { | public enum BizNfsEnum { | ||||
/** | /** | ||||
@@ -33,6 +33,10 @@ public enum BizNfsEnum { | |||||
* 算法管理 NFS 路径命名 | * 算法管理 NFS 路径命名 | ||||
*/ | */ | ||||
ALGORITHM(BizEnum.ALGORITHM, "algorithm-manage"), | ALGORITHM(BizEnum.ALGORITHM, "algorithm-manage"), | ||||
/** | |||||
* 模型管理 NFS 路径命名 | |||||
*/ | |||||
MODEL(BizEnum.MODEL, "model"), | |||||
; | ; | ||||
BizNfsEnum(BizEnum bizEnum, String bizNfsPath) { | BizNfsEnum(BizEnum bizEnum, String bizNfsPath) { | ||||
@@ -81,11 +85,11 @@ public enum BizNfsEnum { | |||||
return bizNfsPath; | return bizNfsPath; | ||||
} | } | ||||
public BizEnum getBizEnum(){ | |||||
public BizEnum getBizEnum() { | |||||
return bizEnum; | return bizEnum; | ||||
} | } | ||||
public String getBizCode() { | public String getBizCode() { | ||||
return bizEnum == null ? null :bizEnum.getBizCode(); | |||||
return bizEnum == null ? null : bizEnum.getBizCode(); | |||||
} | } | ||||
} | } |
@@ -15,7 +15,7 @@ | |||||
* ============================================================= | * ============================================================= | ||||
*/ | */ | ||||
package org.dubhe.data.constant; | |||||
package org.dubhe.enums; | |||||
import lombok.Getter; | import lombok.Getter; | ||||
@@ -26,36 +26,52 @@ import lombok.Getter; | |||||
@Getter | @Getter | ||||
public enum LogEnum { | public enum LogEnum { | ||||
// 系统报错日志 | |||||
SYS_ERR, | |||||
// 用户请求日志 | |||||
REST_REQ, | |||||
// 训练模块 | |||||
BIZ_TRAIN, | |||||
// 系统模块 | |||||
BIZ_SYS, | |||||
// 模型模块 | |||||
BIZ_MODEL, | |||||
// 数据集模块 | |||||
BIZ_DATASET, | |||||
// k8s模块 | |||||
BIZ_K8S, | |||||
//note book | |||||
NOTE_BOOK, | |||||
//NFS UTILS | |||||
NFS_UTIL; | |||||
// 系统报错日志 | |||||
SYS_ERR, | |||||
// 用户请求日志 | |||||
REST_REQ, | |||||
//全局请求日志 | |||||
GLOBAL_REQ, | |||||
// 训练模块 | |||||
BIZ_TRAIN, | |||||
// 系统模块 | |||||
BIZ_SYS, | |||||
// 模型模块 | |||||
BIZ_MODEL, | |||||
// 数据集模块 | |||||
BIZ_DATASET, | |||||
// k8s模块 | |||||
BIZ_K8S, | |||||
//note book | |||||
NOTE_BOOK, | |||||
//NFS UTILS | |||||
NFS_UTIL, | |||||
//localFileUtil | |||||
LOCAL_FILE_UTIL, | |||||
//FILE UTILS | |||||
FILE_UTIL, | |||||
//FILE UTILS | |||||
UPLOAD_TEMP, | |||||
//STATE MACHINE | |||||
STATE_MACHINE, | |||||
//全局垃圾回收 | |||||
GARBAGE_RECYCLE, | |||||
//DATA_SEQUENCE | |||||
DATA_SEQUENCE, | |||||
//IO UTIL | |||||
IO_UTIL; | |||||
/** | |||||
* 判断日志类型不能为空 | |||||
* | |||||
* @param logType 日志类型 | |||||
* @return boolean 返回类型 | |||||
*/ | |||||
public static boolean isLogType(LogEnum logType) { | |||||
/** | |||||
* 判断日志类型不能为空 | |||||
* | |||||
* @param logType 日志类型 | |||||
* @return boolean 返回类型 | |||||
*/ | |||||
public static boolean isLogType(LogEnum logType) { | |||||
if (logType != null) { | |||||
return true; | |||||
} | |||||
return false; | |||||
} | |||||
if (logType != null) { | |||||
return true; | |||||
} | |||||
return false; | |||||
} | |||||
} | } |
@@ -0,0 +1,72 @@ | |||||
/** | |||||
* Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||||
* | |||||
* 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.dubhe.enums; | |||||
import lombok.Getter; | |||||
import lombok.ToString; | |||||
/** | |||||
* @Description 操作类型枚举 | |||||
* @Date 2020-08-24 | |||||
*/ | |||||
@ToString | |||||
@Getter | |||||
public enum OperationTypeEnum { | |||||
/** | |||||
* SELECT 查询类型 | |||||
*/ | |||||
SELECT("select", "查询"), | |||||
/** | |||||
* UPDATE 修改类型 | |||||
*/ | |||||
UPDATE("update", "修改"), | |||||
/** | |||||
* DELETE 删除类型 | |||||
*/ | |||||
DELETE("delete", "删除"), | |||||
/** | |||||
* LIMIT 禁止操作类型 | |||||
*/ | |||||
LIMIT("limit", "禁止操作"), | |||||
/** | |||||
* INSERT 新增类型 | |||||
*/ | |||||
INSERT("insert", "新增类型"), | |||||
; | |||||
/** | |||||
* 操作类型值 | |||||
*/ | |||||
private String type; | |||||
/** | |||||
* 操作类型备注 | |||||
*/ | |||||
private String desc; | |||||
OperationTypeEnum(String type, String desc) { | |||||
this.type = type; | |||||
this.desc = desc; | |||||
} | |||||
} |
@@ -0,0 +1,54 @@ | |||||
/** | |||||
* Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||||
* | |||||
* 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.dubhe.enums; | |||||
import lombok.Getter; | |||||
import java.util.HashSet; | |||||
import java.util.Set; | |||||
/** | |||||
* @description 资源回收枚举类 | |||||
* @date 2020-10-10 | |||||
*/ | |||||
@Getter | |||||
public enum RecycleResourceEnum { | |||||
/** | |||||
* 数据集文件回收 | |||||
*/ | |||||
DATASET_RECYCLE_FILE("datasetRecycleFile", "数据集文件回收"), | |||||
/** | |||||
* 数据集版本文件回收 | |||||
*/ | |||||
DATASET_RECYCLE_VERSION_FILE("datasetRecycleVersionFile", "数据集版本文件回收"), | |||||
; | |||||
private String className; | |||||
private String message; | |||||
RecycleResourceEnum(String className, String message) { | |||||
this.className = className; | |||||
this.message = message; | |||||
} | |||||
} |
@@ -19,8 +19,8 @@ package org.dubhe.enums; | |||||
import lombok.Getter; | import lombok.Getter; | ||||
import java.util.Arrays; | |||||
import java.util.List; | |||||
import java.util.HashSet; | |||||
import java.util.Set; | |||||
/** | /** | ||||
* @description 训练任务枚举类 | * @description 训练任务枚举类 | ||||
@@ -72,7 +72,13 @@ public enum TrainJobStatusEnum { | |||||
this.message = message; | this.message = message; | ||||
} | } | ||||
public static TrainJobStatusEnum get(String msg) { | |||||
/** | |||||
* 根据信息获取枚举类对象 | |||||
* | |||||
* @param msg 信息 | |||||
* @return 枚举类对象 | |||||
*/ | |||||
public static TrainJobStatusEnum getByMessage(String msg) { | |||||
for (TrainJobStatusEnum statusEnum : values()) { | for (TrainJobStatusEnum statusEnum : values()) { | ||||
if (statusEnum.message.equalsIgnoreCase(msg)) { | if (statusEnum.message.equalsIgnoreCase(msg)) { | ||||
return statusEnum; | return statusEnum; | ||||
@@ -81,21 +87,63 @@ public enum TrainJobStatusEnum { | |||||
return UNKNOWN; | return UNKNOWN; | ||||
} | } | ||||
/** | |||||
* 回调状态转换 若是DELETED则转换为STOP,避免状态不统一 | |||||
* @param phase k8s pod phase | |||||
* @return | |||||
*/ | |||||
public static TrainJobStatusEnum transferStatus(String phase) { | |||||
TrainJobStatusEnum enums = getByMessage(phase); | |||||
if (enums != DELETED) { | |||||
return enums; | |||||
} | |||||
return STOP; | |||||
} | |||||
/** | |||||
* 根据状态获取枚举类对象 | |||||
* | |||||
* @param status 状态 | |||||
* @return 枚举类对象 | |||||
*/ | |||||
public static TrainJobStatusEnum getByStatus(Integer status) { | |||||
for (TrainJobStatusEnum statusEnum : values()) { | |||||
if (statusEnum.status.equals(status)) { | |||||
return statusEnum; | |||||
} | |||||
} | |||||
return UNKNOWN; | |||||
} | |||||
/** | |||||
* 结束状态枚举集合 | |||||
*/ | |||||
public static final Set<TrainJobStatusEnum> END_TRAIN_JOB_STATUS; | |||||
static { | |||||
END_TRAIN_JOB_STATUS = new HashSet<>(); | |||||
END_TRAIN_JOB_STATUS.add(SUCCEEDED); | |||||
END_TRAIN_JOB_STATUS.add(FAILED); | |||||
END_TRAIN_JOB_STATUS.add(STOP); | |||||
END_TRAIN_JOB_STATUS.add(CREATE_FAILED); | |||||
END_TRAIN_JOB_STATUS.add(DELETED); | |||||
} | |||||
public static boolean isEnd(String msg) { | public static boolean isEnd(String msg) { | ||||
List<String> endList = Arrays.asList("SUCCEEDED", "FAILED", "STOP", "CREATE_FAILED"); | |||||
return endList.stream().anyMatch(s -> s.equalsIgnoreCase(msg)); | |||||
return END_TRAIN_JOB_STATUS.contains(getByMessage(msg)); | |||||
} | } | ||||
public static boolean isEnd(Integer num) { | |||||
List<Integer> endList = Arrays.asList(2, 3, 4, 7); | |||||
return endList.stream().anyMatch(s -> s.equals(num)); | |||||
public static boolean isEnd(Integer status) { | |||||
return END_TRAIN_JOB_STATUS.contains(getByStatus(status)); | |||||
} | } | ||||
public static boolean checkStopStatus(Integer num) { | public static boolean checkStopStatus(Integer num) { | ||||
return SUCCEEDED.getStatus().equals(num) || | |||||
FAILED.getStatus().equals(num) || | |||||
STOP.getStatus().equals(num) || | |||||
CREATE_FAILED.getStatus().equals(num) || | |||||
DELETED.getStatus().equals(num); | |||||
return isEnd(num); | |||||
} | |||||
public static boolean checkRunStatus(Integer num) { | |||||
return PENDING.getStatus().equals(num) || | |||||
RUNNING.getStatus().equals(num); | |||||
} | } | ||||
} | } |
@@ -54,6 +54,7 @@ public enum BaseErrorCode implements ErrorCode { | |||||
SYSTEM_USER_CANNOT_DELETE(20014, "系统默认用户不可删除!"), | SYSTEM_USER_CANNOT_DELETE(20014, "系统默认用户不可删除!"), | ||||
SYSTEM_ROLE_CANNOT_DELETE(20015, "系统默认角色不可删除!"), | SYSTEM_ROLE_CANNOT_DELETE(20015, "系统默认角色不可删除!"), | ||||
DATASET_ADMIN_PERMISSION_ERROR(1310,"无此权限,请联系管理员"), | |||||
; | ; | ||||
@@ -0,0 +1,42 @@ | |||||
/** | |||||
* Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||||
* | |||||
* 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.dubhe.exception; | |||||
import lombok.Getter; | |||||
/** | |||||
* @description 获取序列异常 | |||||
* @date 2020-09-23 | |||||
*/ | |||||
@Getter | |||||
public class DataSequenceException extends BusinessException { | |||||
private static final long serialVersionUID = 1L; | |||||
public DataSequenceException(String msg) { | |||||
super(msg); | |||||
} | |||||
public DataSequenceException(String msg, Throwable cause) { | |||||
super(msg,cause); | |||||
} | |||||
public DataSequenceException(Throwable cause) { | |||||
super(cause); | |||||
} | |||||
} |
@@ -20,8 +20,7 @@ package org.dubhe.exception; | |||||
import lombok.Getter; | import lombok.Getter; | ||||
/** | /** | ||||
* @description: Notebook 业务处理异常 | |||||
* | |||||
* @description Notebook 业务处理异常 | |||||
* @date 2020.04.27 | * @date 2020.04.27 | ||||
*/ | */ | ||||
@Getter | @Getter | ||||
@@ -17,8 +17,8 @@ | |||||
package org.dubhe.exception.handler; | package org.dubhe.exception.handler; | ||||
import java.util.Objects; | |||||
import lombok.extern.slf4j.Slf4j; | |||||
import org.apache.ibatis.exceptions.IbatisException; | |||||
import org.apache.shiro.ShiroException; | import org.apache.shiro.ShiroException; | ||||
import org.apache.shiro.authc.AuthenticationException; | import org.apache.shiro.authc.AuthenticationException; | ||||
import org.apache.shiro.authc.IncorrectCredentialsException; | import org.apache.shiro.authc.IncorrectCredentialsException; | ||||
@@ -27,11 +27,7 @@ import org.apache.shiro.authc.UnknownAccountException; | |||||
import org.dubhe.base.DataResponseBody; | import org.dubhe.base.DataResponseBody; | ||||
import org.dubhe.base.ResponseCode; | import org.dubhe.base.ResponseCode; | ||||
import org.dubhe.enums.LogEnum; | import org.dubhe.enums.LogEnum; | ||||
import org.dubhe.exception.BusinessException; | |||||
import org.dubhe.exception.CaptchaException; | |||||
import org.dubhe.exception.LoginException; | |||||
import org.dubhe.exception.NotebookBizException; | |||||
import org.dubhe.exception.UnauthorizedException; | |||||
import org.dubhe.exception.*; | |||||
import org.dubhe.utils.LogUtil; | import org.dubhe.utils.LogUtil; | ||||
import org.springframework.http.HttpStatus; | import org.springframework.http.HttpStatus; | ||||
import org.springframework.http.ResponseEntity; | import org.springframework.http.ResponseEntity; | ||||
@@ -41,7 +37,7 @@ import org.springframework.web.bind.MethodArgumentNotValidException; | |||||
import org.springframework.web.bind.annotation.ExceptionHandler; | import org.springframework.web.bind.annotation.ExceptionHandler; | ||||
import org.springframework.web.bind.annotation.RestControllerAdvice; | import org.springframework.web.bind.annotation.RestControllerAdvice; | ||||
import lombok.extern.slf4j.Slf4j; | |||||
import java.util.Objects; | |||||
/** | /** | ||||
* @description 处理异常 | * @description 处理异常 | ||||
@@ -51,140 +47,144 @@ import lombok.extern.slf4j.Slf4j; | |||||
@RestControllerAdvice | @RestControllerAdvice | ||||
public class GlobalExceptionHandler { | public class GlobalExceptionHandler { | ||||
/** | |||||
* 处理所有不可知的异常 | |||||
*/ | |||||
@ExceptionHandler(Throwable.class) | |||||
public ResponseEntity<DataResponseBody> handleException(Throwable e) { | |||||
// 打印堆栈信息 | |||||
LogUtil.error(LogEnum.SYS_ERR, e); | |||||
return buildResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR, | |||||
new DataResponseBody(ResponseCode.ERROR, e.getMessage())); | |||||
} | |||||
/** | |||||
* UnauthorizedException | |||||
*/ | |||||
@ExceptionHandler(UnauthorizedException.class) | |||||
public ResponseEntity<DataResponseBody> badCredentialsException(UnauthorizedException e) { | |||||
// 打印堆栈信息 | |||||
LogUtil.error(LogEnum.SYS_ERR, e); | |||||
String message = "坏的凭证".equals(e.getMessage()) ? "用户名或密码不正确" : e.getMessage(); | |||||
return buildResponseEntity(HttpStatus.UNAUTHORIZED, new DataResponseBody(ResponseCode.ERROR, message)); | |||||
} | |||||
/** | |||||
* 处理自定义异常 | |||||
*/ | |||||
@ExceptionHandler(value = BusinessException.class) | |||||
public ResponseEntity<DataResponseBody> badRequestException(BusinessException e) { | |||||
// 打印堆栈信息 | |||||
LogUtil.error(LogEnum.SYS_ERR, e); | |||||
return buildResponseEntity(HttpStatus.OK, e.getResponseBody()); | |||||
} | |||||
/** | |||||
* 处理自定义异常 | |||||
*/ | |||||
@ExceptionHandler(value = AuthenticationException.class) | |||||
public ResponseEntity<DataResponseBody> badRequestException(AuthenticationException e) { | |||||
// 打印堆栈信息 | |||||
LogUtil.error(LogEnum.SYS_ERR, e); | |||||
return buildResponseEntity(HttpStatus.OK, new DataResponseBody(ResponseCode.UNAUTHORIZED, "无权访问")); | |||||
} | |||||
/** | |||||
* shiro 异常捕捉 | |||||
*/ | |||||
@ExceptionHandler(value = ShiroException.class) | |||||
public ResponseEntity<DataResponseBody> accountException(ShiroException e) { | |||||
// 打印堆栈信息 | |||||
LogUtil.error(LogEnum.SYS_ERR, e); | |||||
ResponseEntity<DataResponseBody> responseEntity; | |||||
if (e instanceof IncorrectCredentialsException) { | |||||
responseEntity = buildResponseEntity(HttpStatus.OK, new DataResponseBody(ResponseCode.ERROR, "密码不正确")); | |||||
} else if (e instanceof UnknownAccountException) { | |||||
responseEntity = buildResponseEntity(HttpStatus.OK, new DataResponseBody(ResponseCode.ERROR, "此账户不存在")); | |||||
} | |||||
else if (e instanceof LockedAccountException) { | |||||
responseEntity = buildResponseEntity(HttpStatus.OK, new DataResponseBody(ResponseCode.ERROR, "未知的账号")); | |||||
} | |||||
else if (e instanceof UnknownAccountException) { | |||||
responseEntity = buildResponseEntity(HttpStatus.OK, new DataResponseBody(ResponseCode.ERROR, "账户已被禁用")); | |||||
} | |||||
else { | |||||
responseEntity = buildResponseEntity(HttpStatus.OK, | |||||
new DataResponseBody(ResponseCode.UNAUTHORIZED, "无权访问")); | |||||
} | |||||
return responseEntity; | |||||
} | |||||
/** | |||||
* 处理自定义异常 | |||||
*/ | |||||
@ExceptionHandler(value = LoginException.class) | |||||
public ResponseEntity<DataResponseBody> loginException(LoginException e) { | |||||
// 打印堆栈信息 | |||||
LogUtil.error(LogEnum.SYS_ERR, e); | |||||
return buildResponseEntity(HttpStatus.UNAUTHORIZED, e.getResponseBody()); | |||||
} | |||||
/** | |||||
* 处理自定义异常 | |||||
*/ | |||||
@ExceptionHandler(value = CaptchaException.class) | |||||
public ResponseEntity<DataResponseBody> captchaException(CaptchaException e) { | |||||
// 打印堆栈信息 | |||||
LogUtil.error(LogEnum.SYS_ERR, e); | |||||
return buildResponseEntity(HttpStatus.OK, e.getResponseBody()); | |||||
} | |||||
/** | |||||
* 处理自定义异常 | |||||
*/ | |||||
@ExceptionHandler(value = NotebookBizException.class) | |||||
public ResponseEntity<DataResponseBody> captchaException(NotebookBizException e) { | |||||
// 打印堆栈信息 | |||||
LogUtil.error(LogEnum.SYS_ERR, e); | |||||
return buildResponseEntity(HttpStatus.OK, e.getResponseBody()); | |||||
} | |||||
/** | |||||
* 处理所有接口数据验证异常 | |||||
*/ | |||||
@ExceptionHandler(MethodArgumentNotValidException.class) | |||||
public ResponseEntity<DataResponseBody> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) { | |||||
// 打印堆栈信息 | |||||
LogUtil.error(LogEnum.SYS_ERR, e); | |||||
String[] str = Objects.requireNonNull(e.getBindingResult().getAllErrors().get(0).getCodes())[1].split("\\."); | |||||
String message = e.getBindingResult().getAllErrors().get(0).getDefaultMessage(); | |||||
String msg = "不能为空"; | |||||
if (msg.equals(message)) { | |||||
message = str[1] + ":" + message; | |||||
} | |||||
return buildResponseEntity(HttpStatus.BAD_REQUEST, new DataResponseBody(ResponseCode.ERROR, message)); | |||||
} | |||||
@ExceptionHandler(BindException.class) | |||||
public ResponseEntity<DataResponseBody> bindException(BindException e) { | |||||
// 打印堆栈信息 | |||||
LogUtil.error(LogEnum.SYS_ERR, e); | |||||
ObjectError error = e.getAllErrors().get(0); | |||||
return buildResponseEntity(HttpStatus.BAD_REQUEST, | |||||
new DataResponseBody(ResponseCode.ERROR, error.getDefaultMessage())); | |||||
} | |||||
/** | |||||
* 统一返回 | |||||
* | |||||
* @param httpStatus | |||||
* @param responseBody | |||||
* @return | |||||
*/ | |||||
private ResponseEntity<DataResponseBody> buildResponseEntity(HttpStatus httpStatus, DataResponseBody responseBody) { | |||||
return new ResponseEntity<>(responseBody, httpStatus); | |||||
} | |||||
/** | |||||
* 处理所有不可知的异常 | |||||
*/ | |||||
@ExceptionHandler(Throwable.class) | |||||
public ResponseEntity<DataResponseBody> handleException(Throwable e) { | |||||
// 打印堆栈信息 | |||||
LogUtil.error(LogEnum.SYS_ERR, "引起异常的堆栈信息:{}", e); | |||||
return buildResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR, | |||||
new DataResponseBody(ResponseCode.ERROR, e.getMessage())); | |||||
} | |||||
/** | |||||
* UnauthorizedException | |||||
*/ | |||||
@ExceptionHandler(UnauthorizedException.class) | |||||
public ResponseEntity<DataResponseBody> badCredentialsException(UnauthorizedException e) { | |||||
// 打印堆栈信息 | |||||
LogUtil.error(LogEnum.SYS_ERR, "引起异常的堆栈信息:{}", e); | |||||
String message = "坏的凭证".equals(e.getMessage()) ? "用户名或密码不正确" : e.getMessage(); | |||||
return buildResponseEntity(HttpStatus.UNAUTHORIZED, new DataResponseBody(ResponseCode.ERROR, message)); | |||||
} | |||||
/** | |||||
* 处理自定义异常 | |||||
*/ | |||||
@ExceptionHandler(value = BusinessException.class) | |||||
public ResponseEntity<DataResponseBody> badRequestException(BusinessException e) { | |||||
// 打印堆栈信息 | |||||
LogUtil.error(LogEnum.SYS_ERR, "引起异常的堆栈信息:{}", e); | |||||
return buildResponseEntity(HttpStatus.OK, e.getResponseBody()); | |||||
} | |||||
/** | |||||
* 处理自定义异常 | |||||
*/ | |||||
@ExceptionHandler(value = IbatisException.class) | |||||
public ResponseEntity<DataResponseBody> persistenceException(IbatisException e) { | |||||
// 打印堆栈信息 | |||||
LogUtil.error(LogEnum.SYS_ERR, "引起异常的堆栈信息:{}", e); | |||||
return buildResponseEntity(HttpStatus.OK, new DataResponseBody(ResponseCode.ERROR, e.getMessage())); | |||||
} | |||||
/** | |||||
* 处理自定义异常 | |||||
*/ | |||||
@ExceptionHandler(value = AuthenticationException.class) | |||||
public ResponseEntity<DataResponseBody> badRequestException(AuthenticationException e) { | |||||
// 打印堆栈信息 | |||||
LogUtil.error(LogEnum.SYS_ERR, "引起异常的堆栈信息:{}", e); | |||||
return buildResponseEntity(HttpStatus.OK, new DataResponseBody(ResponseCode.UNAUTHORIZED, "无权访问")); | |||||
} | |||||
/** | |||||
* shiro 异常捕捉 | |||||
*/ | |||||
@ExceptionHandler(value = ShiroException.class) | |||||
public ResponseEntity<DataResponseBody> accountException(ShiroException e) { | |||||
// 打印堆栈信息 | |||||
LogUtil.error(LogEnum.SYS_ERR, "引起异常的堆栈信息:{}", e); | |||||
ResponseEntity<DataResponseBody> responseEntity; | |||||
if (e instanceof IncorrectCredentialsException) { | |||||
responseEntity = buildResponseEntity(HttpStatus.OK, new DataResponseBody(ResponseCode.ERROR, "密码不正确")); | |||||
} else if (e instanceof UnknownAccountException) { | |||||
responseEntity = buildResponseEntity(HttpStatus.OK, new DataResponseBody(ResponseCode.ERROR, "此账户不存在")); | |||||
} else if (e instanceof LockedAccountException) { | |||||
responseEntity = buildResponseEntity(HttpStatus.OK, new DataResponseBody(ResponseCode.ERROR, "未知的账号")); | |||||
} else if (e instanceof UnknownAccountException) { | |||||
responseEntity = buildResponseEntity(HttpStatus.OK, new DataResponseBody(ResponseCode.ERROR, "账户已被禁用")); | |||||
} else { | |||||
responseEntity = buildResponseEntity(HttpStatus.OK, | |||||
new DataResponseBody(ResponseCode.UNAUTHORIZED, "无权访问")); | |||||
} | |||||
return responseEntity; | |||||
} | |||||
/** | |||||
* 处理自定义异常 | |||||
*/ | |||||
@ExceptionHandler(value = LoginException.class) | |||||
public ResponseEntity<DataResponseBody> loginException(LoginException e) { | |||||
// 打印堆栈信息 | |||||
LogUtil.error(LogEnum.SYS_ERR, "引起异常的堆栈信息:{}", e); | |||||
return buildResponseEntity(HttpStatus.UNAUTHORIZED, e.getResponseBody()); | |||||
} | |||||
/** | |||||
* 处理自定义异常 | |||||
*/ | |||||
@ExceptionHandler(value = CaptchaException.class) | |||||
public ResponseEntity<DataResponseBody> captchaException(CaptchaException e) { | |||||
// 打印堆栈信息 | |||||
LogUtil.error(LogEnum.SYS_ERR, "引起异常的堆栈信息:{}", e); | |||||
return buildResponseEntity(HttpStatus.OK, e.getResponseBody()); | |||||
} | |||||
/** | |||||
* 处理自定义异常 | |||||
*/ | |||||
@ExceptionHandler(value = NotebookBizException.class) | |||||
public ResponseEntity<DataResponseBody> captchaException(NotebookBizException e) { | |||||
// 打印堆栈信息 | |||||
LogUtil.error(LogEnum.SYS_ERR, "引起异常的堆栈信息:{}", e); | |||||
return buildResponseEntity(HttpStatus.OK, e.getResponseBody()); | |||||
} | |||||
/** | |||||
* 处理所有接口数据验证异常 | |||||
*/ | |||||
@ExceptionHandler(MethodArgumentNotValidException.class) | |||||
public ResponseEntity<DataResponseBody> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) { | |||||
// 打印堆栈信息 | |||||
LogUtil.error(LogEnum.SYS_ERR, "引起异常的堆栈信息:{}", e); | |||||
String[] str = Objects.requireNonNull(e.getBindingResult().getAllErrors().get(0).getCodes())[1].split("\\."); | |||||
String message = e.getBindingResult().getAllErrors().get(0).getDefaultMessage(); | |||||
String msg = "不能为空"; | |||||
if (msg.equals(message)) { | |||||
message = str[1] + ":" + message; | |||||
} | |||||
return buildResponseEntity(HttpStatus.BAD_REQUEST, new DataResponseBody(ResponseCode.ERROR, message)); | |||||
} | |||||
@ExceptionHandler(BindException.class) | |||||
public ResponseEntity<DataResponseBody> bindException(BindException e) { | |||||
// 打印堆栈信息 | |||||
LogUtil.error(LogEnum.SYS_ERR, "引起异常的堆栈信息:{}", e); | |||||
ObjectError error = e.getAllErrors().get(0); | |||||
return buildResponseEntity(HttpStatus.BAD_REQUEST, | |||||
new DataResponseBody(ResponseCode.ERROR, error.getDefaultMessage())); | |||||
} | |||||
/** | |||||
* 统一返回 | |||||
* | |||||
* @param httpStatus | |||||
* @param responseBody | |||||
* @return | |||||
*/ | |||||
private ResponseEntity<DataResponseBody> buildResponseEntity(HttpStatus httpStatus, DataResponseBody responseBody) { | |||||
return new ResponseEntity<>(responseBody, httpStatus); | |||||
} | |||||
} | } |
@@ -0,0 +1,74 @@ | |||||
/** | |||||
* Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||||
* | |||||
* 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.dubhe.filter; | |||||
import ch.qos.logback.classic.Level; | |||||
import ch.qos.logback.classic.spi.ILoggingEvent; | |||||
import ch.qos.logback.core.filter.AbstractMatcherFilter; | |||||
import ch.qos.logback.core.spi.FilterReply; | |||||
import cn.hutool.core.util.StrUtil; | |||||
import org.slf4j.Marker; | |||||
/** | |||||
* @description 自定义日志过滤器 | |||||
* @date 2020-07-21 | |||||
*/ | |||||
public class BaseLogFilter extends AbstractMatcherFilter<ILoggingEvent> { | |||||
Level level; | |||||
/** | |||||
* 重写decide方法 | |||||
* | |||||
* @param iLoggingEvent event to decide upon. | |||||
* @return FilterReply | |||||
*/ | |||||
@Override | |||||
public FilterReply decide(ILoggingEvent iLoggingEvent) { | |||||
if (!isStarted()) { | |||||
return FilterReply.NEUTRAL; | |||||
} | |||||
final String msg = iLoggingEvent.getMessage(); | |||||
//自定义级别 | |||||
if (checkLevel(iLoggingEvent) && msg != null && msg.startsWith(StrUtil.DELIM_START) && msg.endsWith(StrUtil.DELIM_END)) { | |||||
final Marker marker = iLoggingEvent.getMarker(); | |||||
if (marker != null && this.getName() != null && this.getName().contains(marker.getName())) { | |||||
return onMatch; | |||||
} | |||||
} | |||||
return onMismatch; | |||||
} | |||||
protected boolean checkLevel(ILoggingEvent iLoggingEvent) { | |||||
return this.level != null | |||||
&& iLoggingEvent.getLevel() != null | |||||
&& iLoggingEvent.getLevel().toInt() == this.level.toInt(); | |||||
} | |||||
public void setLevel(Level level) { | |||||
this.level = level; | |||||
} | |||||
@Override | |||||
public void start() { | |||||
if (this.level != null) { | |||||
super.start(); | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,49 @@ | |||||
/** | |||||
* Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||||
* | |||||
* 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.dubhe.filter; | |||||
import ch.qos.logback.classic.spi.ILoggingEvent; | |||||
import ch.qos.logback.core.spi.FilterReply; | |||||
import org.dubhe.utils.LogUtil; | |||||
import org.slf4j.MarkerFactory; | |||||
/** | |||||
* @description 自定义日志过滤器 | |||||
* @date 2020-07-21 | |||||
*/ | |||||
public class ConsoleLogFilter extends BaseLogFilter { | |||||
@Override | |||||
public FilterReply decide(ILoggingEvent iLoggingEvent) { | |||||
if (!isStarted()) { | |||||
return FilterReply.NEUTRAL; | |||||
} | |||||
return checkLevel(iLoggingEvent) ? onMatch : onMismatch; | |||||
} | |||||
protected boolean checkLevel(ILoggingEvent iLoggingEvent) { | |||||
return this.level != null | |||||
&& iLoggingEvent.getLevel() != null | |||||
&& iLoggingEvent.getLevel().toInt() >= this.level.toInt() | |||||
&& !MarkerFactory.getMarker(LogUtil.K8S_CALLBACK_LEVEL).equals(iLoggingEvent.getMarker()) | |||||
&& !MarkerFactory.getMarker(LogUtil.SCHEDULE_LEVEL).equals(iLoggingEvent.getMarker()) | |||||
&& !"log4jdbc.log4j2".equals(iLoggingEvent.getLoggerName()); | |||||
} | |||||
} |
@@ -1,60 +0,0 @@ | |||||
/** | |||||
* Copyright 2019-2020 Zheng Jie | |||||
* | |||||
* 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.dubhe.filter; | |||||
import ch.qos.logback.classic.Level; | |||||
import ch.qos.logback.classic.spi.ILoggingEvent; | |||||
import ch.qos.logback.core.filter.AbstractMatcherFilter; | |||||
import ch.qos.logback.core.spi.FilterReply; | |||||
/** | |||||
* @description 自定义日志过滤器 | |||||
* @date 2020-07-21 | |||||
*/ | |||||
public class FileLogFilter extends AbstractMatcherFilter<ILoggingEvent> { | |||||
Level level; | |||||
/** | |||||
* 重写decide方法 | |||||
* | |||||
* @param iLoggingEvent event to decide upon. | |||||
* @return FilterReply | |||||
*/ | |||||
@Override | |||||
public FilterReply decide(ILoggingEvent iLoggingEvent) { | |||||
if (!isStarted()) { | |||||
return FilterReply.NEUTRAL; | |||||
} | |||||
if (iLoggingEvent.getLevel().equals(level) && iLoggingEvent.getMessage() != null | |||||
&& iLoggingEvent.getMessage().startsWith("{") && iLoggingEvent.getMessage().endsWith("}")) { | |||||
return onMatch; | |||||
} | |||||
return onMismatch; | |||||
} | |||||
public void setLevel(Level level) { | |||||
this.level = level; | |||||
} | |||||
@Override | |||||
public void start() { | |||||
if (this.level != null) { | |||||
super.start(); | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,34 @@ | |||||
/** | |||||
* Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||||
* | |||||
* 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.dubhe.filter; | |||||
import ch.qos.logback.classic.spi.ILoggingEvent; | |||||
/** | |||||
* @description 全局请求 日志过滤器 | |||||
* @date 2020-08-13 | |||||
*/ | |||||
public class GlobalRequestLogFilter extends BaseLogFilter { | |||||
@Override | |||||
public boolean checkLevel(ILoggingEvent iLoggingEvent) { | |||||
return this.level != null; | |||||
} | |||||
} |
@@ -0,0 +1,113 @@ | |||||
/** | |||||
* Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||||
* | |||||
* 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.dubhe.interceptor; | |||||
import org.apache.ibatis.executor.statement.StatementHandler; | |||||
import org.apache.ibatis.mapping.BoundSql; | |||||
import org.apache.ibatis.mapping.MappedStatement; | |||||
import org.apache.ibatis.plugin.*; | |||||
import org.apache.ibatis.reflection.DefaultReflectorFactory; | |||||
import org.apache.ibatis.reflection.MetaObject; | |||||
import org.apache.ibatis.reflection.SystemMetaObject; | |||||
import org.dubhe.annotation.DataPermission; | |||||
import org.dubhe.base.DataContext; | |||||
import org.dubhe.domain.dto.UserDTO; | |||||
import org.dubhe.enums.OperationTypeEnum; | |||||
import org.dubhe.utils.JwtUtils; | |||||
import org.dubhe.utils.SqlUtil; | |||||
import org.springframework.stereotype.Component; | |||||
import java.lang.reflect.Field; | |||||
import java.sql.Connection; | |||||
import java.util.Arrays; | |||||
import java.util.Objects; | |||||
import java.util.Properties; | |||||
/** | |||||
* @description mybatis拦截器 | |||||
* @date 2020-06-10 | |||||
*/ | |||||
@Component | |||||
@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})}) | |||||
public class MySqlInterceptor implements Interceptor { | |||||
@Override | |||||
public Object intercept(Invocation invocation) throws Throwable { | |||||
StatementHandler statementHandler = (StatementHandler) invocation.getTarget(); | |||||
MetaObject metaObject = MetaObject.forObject(statementHandler, SystemMetaObject.DEFAULT_OBJECT_FACTORY, | |||||
SystemMetaObject.DEFAULT_OBJECT_WRAPPER_FACTORY, new DefaultReflectorFactory()); | |||||
/* | |||||
* 先拦截到RoutingStatementHandler,里面有个StatementHandler类型的delegate变量,其实现类是BaseStatementHandler, | |||||
* 然后就到BaseStatementHandler的成员变量mappedStatement | |||||
*/ | |||||
MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement"); | |||||
//id为执行的mapper方法的全路径名,如com.uv.dao.UserDao.selectPageVo | |||||
String id = mappedStatement.getId(); | |||||
//sql语句类型 select、delete、insert、update | |||||
String sqlCommandType = mappedStatement.getSqlCommandType().toString(); | |||||
BoundSql boundSql = statementHandler.getBoundSql(); | |||||
//获取到原始sql语句 | |||||
String sql = boundSql.getSql(); | |||||
String mSql = sql; | |||||
//注解逻辑判断 添加注解了才拦截 | |||||
Class<?> classType = Class.forName(mappedStatement.getId().substring(0, mappedStatement.getId().lastIndexOf("."))); | |||||
String mName = mappedStatement.getId().substring(mappedStatement.getId().lastIndexOf(".") + 1, mappedStatement.getId().length()); | |||||
UserDTO currentUserDto = JwtUtils.getCurrentUserDto(); | |||||
//获取类注解 获取需要忽略拦截的方法名称 | |||||
DataPermission dataAnnotation = classType.getAnnotation(DataPermission.class); | |||||
if (!Objects.isNull(dataAnnotation)) { | |||||
String[] ignores = dataAnnotation.ignoresMethod(); | |||||
//校验拦截忽略方法名 忽略新增方法 忽略回调/定时方法 | |||||
if ((!Objects.isNull(ignores) && Arrays.asList(ignores).contains(mName)) | |||||
|| OperationTypeEnum.INSERT.getType().equals(sqlCommandType.toLowerCase()) | |||||
|| Objects.isNull(currentUserDto) | |||||
|| (!Objects.isNull(DataContext.get()) && DataContext.get().getType()) | |||||
) { | |||||
return invocation.proceed(); | |||||
} else { | |||||
//拦截所有sql操作类型 | |||||
mSql = SqlUtil.buildTargetSql(sql, SqlUtil.getResourceIds()); | |||||
} | |||||
} | |||||
//通过反射修改sql语句 | |||||
Field field = boundSql.getClass().getDeclaredField("sql"); | |||||
field.setAccessible(true); | |||||
field.set(boundSql, mSql); | |||||
return invocation.proceed(); | |||||
} | |||||
@Override | |||||
public Object plugin(Object target) { | |||||
if (target instanceof StatementHandler) { | |||||
return Plugin.wrap(target, this); | |||||
} else { | |||||
return target; | |||||
} | |||||
} | |||||
@Override | |||||
public void setProperties(Properties properties) { | |||||
} | |||||
} |
@@ -0,0 +1,457 @@ | |||||
/** | |||||
* Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||||
* | |||||
* 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.dubhe.interceptor; | |||||
import com.baomidou.mybatisplus.annotation.DbType; | |||||
import com.baomidou.mybatisplus.core.MybatisDefaultParameterHandler; | |||||
import com.baomidou.mybatisplus.core.metadata.IPage; | |||||
import com.baomidou.mybatisplus.core.metadata.OrderItem; | |||||
import com.baomidou.mybatisplus.core.parser.ISqlParser; | |||||
import com.baomidou.mybatisplus.core.parser.SqlInfo; | |||||
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; | |||||
import com.baomidou.mybatisplus.core.toolkit.ExceptionUtils; | |||||
import com.baomidou.mybatisplus.core.toolkit.PluginUtils; | |||||
import com.baomidou.mybatisplus.core.toolkit.StringUtils; | |||||
import com.baomidou.mybatisplus.extension.handlers.AbstractSqlParserHandler; | |||||
import com.baomidou.mybatisplus.extension.plugins.pagination.DialectFactory; | |||||
import com.baomidou.mybatisplus.extension.plugins.pagination.DialectModel; | |||||
import com.baomidou.mybatisplus.extension.plugins.pagination.dialects.IDialect; | |||||
import com.baomidou.mybatisplus.extension.toolkit.JdbcUtils; | |||||
import com.baomidou.mybatisplus.extension.toolkit.SqlParserUtils; | |||||
import net.sf.jsqlparser.JSQLParserException; | |||||
import net.sf.jsqlparser.parser.CCJSqlParserUtil; | |||||
import net.sf.jsqlparser.schema.Column; | |||||
import net.sf.jsqlparser.statement.select.*; | |||||
import org.apache.ibatis.executor.statement.StatementHandler; | |||||
import org.apache.ibatis.logging.Log; | |||||
import org.apache.ibatis.logging.LogFactory; | |||||
import org.apache.ibatis.mapping.*; | |||||
import org.apache.ibatis.plugin.*; | |||||
import org.apache.ibatis.reflection.MetaObject; | |||||
import org.apache.ibatis.reflection.SystemMetaObject; | |||||
import org.apache.ibatis.scripting.defaults.DefaultParameterHandler; | |||||
import org.apache.ibatis.session.Configuration; | |||||
import org.dubhe.annotation.DataPermission; | |||||
import org.dubhe.base.DataContext; | |||||
import org.dubhe.domain.dto.UserDTO; | |||||
import org.dubhe.enums.OperationTypeEnum; | |||||
import org.dubhe.utils.JwtUtils; | |||||
import org.dubhe.utils.SqlUtil; | |||||
import java.sql.Connection; | |||||
import java.sql.PreparedStatement; | |||||
import java.sql.ResultSet; | |||||
import java.util.*; | |||||
import java.util.stream.Collectors; | |||||
/** | |||||
* @description MybatisPlus 分页拦截器 | |||||
* @date 2020-10-09 | |||||
*/ | |||||
@Intercepts({@Signature( | |||||
type = StatementHandler.class, | |||||
method = "prepare", | |||||
args = {Connection.class, Integer.class} | |||||
)}) | |||||
public class PaginationInterceptor extends AbstractSqlParserHandler implements Interceptor { | |||||
protected static final Log logger = LogFactory.getLog(PaginationInterceptor.class); | |||||
/** | |||||
* COUNT SQL 解析 | |||||
*/ | |||||
protected ISqlParser countSqlParser; | |||||
/** | |||||
* 溢出总页数,设置第一页 | |||||
*/ | |||||
protected boolean overflow = false; | |||||
/** | |||||
* 单页限制 500 条,小于 0 如 -1 不受限制 | |||||
*/ | |||||
protected long limit = 500L; | |||||
/** | |||||
* 数据类型 | |||||
*/ | |||||
private DbType dbType; | |||||
/** | |||||
* 方言 | |||||
*/ | |||||
private IDialect dialect; | |||||
/** | |||||
* 方言类型 | |||||
*/ | |||||
@Deprecated | |||||
protected String dialectType; | |||||
/** | |||||
* 方言实现类 | |||||
*/ | |||||
@Deprecated | |||||
protected String dialectClazz; | |||||
public PaginationInterceptor() { | |||||
} | |||||
/** | |||||
* 构建分页sql | |||||
* | |||||
* @param originalSql 原生sql | |||||
* @param page 分页参数 | |||||
* @return 构建后 sql | |||||
*/ | |||||
public static String concatOrderBy(String originalSql, IPage<?> page) { | |||||
if (CollectionUtils.isNotEmpty(page.orders())) { | |||||
try { | |||||
List<OrderItem> orderList = page.orders(); | |||||
Select selectStatement = (Select) CCJSqlParserUtil.parse(originalSql); | |||||
List orderByElements; | |||||
List orderByElementsReturn; | |||||
if (selectStatement.getSelectBody() instanceof PlainSelect) { | |||||
PlainSelect plainSelect = (PlainSelect) selectStatement.getSelectBody(); | |||||
orderByElements = plainSelect.getOrderByElements(); | |||||
orderByElementsReturn = addOrderByElements(orderList, orderByElements); | |||||
plainSelect.setOrderByElements(orderByElementsReturn); | |||||
return plainSelect.toString(); | |||||
} | |||||
if (selectStatement.getSelectBody() instanceof SetOperationList) { | |||||
SetOperationList setOperationList = (SetOperationList) selectStatement.getSelectBody(); | |||||
orderByElements = setOperationList.getOrderByElements(); | |||||
orderByElementsReturn = addOrderByElements(orderList, orderByElements); | |||||
setOperationList.setOrderByElements(orderByElementsReturn); | |||||
return setOperationList.toString(); | |||||
} | |||||
if (selectStatement.getSelectBody() instanceof WithItem) { | |||||
return originalSql; | |||||
} | |||||
return originalSql; | |||||
} catch (JSQLParserException var7) { | |||||
logger.error("failed to concat orderBy from IPage, exception=", var7); | |||||
} | |||||
} | |||||
return originalSql; | |||||
} | |||||
/** | |||||
* 添加分页排序规则 | |||||
* | |||||
* @param orderList 分页规则 | |||||
* @param orderByElements 分页排序元素 | |||||
* @return 分页规则 | |||||
*/ | |||||
private static List<OrderByElement> addOrderByElements(List<OrderItem> orderList, List<OrderByElement> orderByElements) { | |||||
orderByElements = CollectionUtils.isEmpty(orderByElements) ? new ArrayList(orderList.size()) : orderByElements; | |||||
List<OrderByElement> orderByElementList = (List) orderList.stream().filter((item) -> { | |||||
return StringUtils.isNotBlank(item.getColumn()); | |||||
}).map((item) -> { | |||||
OrderByElement element = new OrderByElement(); | |||||
element.setExpression(new Column(item.getColumn())); | |||||
element.setAsc(item.isAsc()); | |||||
element.setAscDescPresent(true); | |||||
return element; | |||||
}).collect(Collectors.toList()); | |||||
((List) orderByElements).addAll(orderByElementList); | |||||
return (List) orderByElements; | |||||
} | |||||
/** | |||||
* 执行sql查询逻辑 | |||||
* | |||||
* @param invocation mybatis 调用类 | |||||
* @return | |||||
* @throws Throwable | |||||
*/ | |||||
@Override | |||||
public Object intercept(Invocation invocation) throws Throwable { | |||||
StatementHandler statementHandler = (StatementHandler) PluginUtils.realTarget(invocation.getTarget()); | |||||
MetaObject metaObject = SystemMetaObject.forObject(statementHandler); | |||||
this.sqlParser(metaObject); | |||||
MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement"); | |||||
if (SqlCommandType.SELECT == mappedStatement.getSqlCommandType() && StatementType.CALLABLE != mappedStatement.getStatementType()) { | |||||
BoundSql boundSql = (BoundSql) metaObject.getValue("delegate.boundSql"); | |||||
Object paramObj = boundSql.getParameterObject(); | |||||
IPage<?> page = null; | |||||
if (paramObj instanceof IPage) { | |||||
page = (IPage) paramObj; | |||||
} else if (paramObj instanceof Map) { | |||||
Iterator var8 = ((Map) paramObj).values().iterator(); | |||||
while (var8.hasNext()) { | |||||
Object arg = var8.next(); | |||||
if (arg instanceof IPage) { | |||||
page = (IPage) arg; | |||||
break; | |||||
} | |||||
} | |||||
} | |||||
if (null != page && page.getSize() >= 0L) { | |||||
if (this.limit > 0L && this.limit <= page.getSize()) { | |||||
this.handlerLimit(page); | |||||
} | |||||
String originalSql = boundSql.getSql(); | |||||
//注解逻辑判断 添加注解了才拦截 | |||||
Class<?> classType = Class.forName(mappedStatement.getId().substring(0, mappedStatement.getId().lastIndexOf("."))); | |||||
String mName = mappedStatement.getId().substring(mappedStatement.getId().lastIndexOf(".") + 1, mappedStatement.getId().length()); | |||||
UserDTO currentUserDto = JwtUtils.getCurrentUserDto(); | |||||
String sqlCommandType = mappedStatement.getSqlCommandType().toString(); | |||||
//获取类注解 获取需要忽略拦截的方法名称 | |||||
DataPermission dataAnnotation = classType.getAnnotation(DataPermission.class); | |||||
if (!Objects.isNull(dataAnnotation)) { | |||||
String[] ignores = dataAnnotation.ignoresMethod(); | |||||
//校验拦截忽略方法名 忽略新增方法 忽略回调/定时方法 | |||||
if (!((!Objects.isNull(ignores) && Arrays.asList(ignores).contains(mName)) | |||||
|| OperationTypeEnum.INSERT.getType().equals(sqlCommandType.toLowerCase()) | |||||
|| Objects.isNull(currentUserDto) | |||||
|| (!Objects.isNull(DataContext.get()) && DataContext.get().getType())) | |||||
) { | |||||
originalSql = SqlUtil.buildTargetSql(originalSql, SqlUtil.getResourceIds()); | |||||
} | |||||
} | |||||
Connection connection = (Connection) invocation.getArgs()[0]; | |||||
if (page.isSearchCount() && !page.isHitCount()) { | |||||
SqlInfo sqlInfo = SqlParserUtils.getOptimizeCountSql(page.optimizeCountSql(), this.countSqlParser, originalSql); | |||||
this.queryTotal(sqlInfo.getSql(), mappedStatement, boundSql, page, connection); | |||||
if (page.getTotal() <= 0L) { | |||||
return null; | |||||
} | |||||
} | |||||
DbType dbType = Optional.ofNullable(this.dbType).orElse(JdbcUtils.getDbType(connection.getMetaData().getURL())); | |||||
IDialect dialect = Optional.ofNullable(this.dialect).orElse(DialectFactory.getDialect(dbType)); | |||||
String buildSql = concatOrderBy(originalSql, page); | |||||
DialectModel model = dialect.buildPaginationSql(buildSql, page.offset(), page.getSize()); | |||||
Configuration configuration = mappedStatement.getConfiguration(); | |||||
List<ParameterMapping> mappings = new ArrayList(boundSql.getParameterMappings()); | |||||
Map<String, Object> additionalParameters = (Map) metaObject.getValue("delegate.boundSql.additionalParameters"); | |||||
model.consumers(mappings, configuration, additionalParameters); | |||||
metaObject.setValue("delegate.boundSql.sql", model.getDialectSql()); | |||||
metaObject.setValue("delegate.boundSql.parameterMappings", mappings); | |||||
return invocation.proceed(); | |||||
} else { | |||||
return invocation.proceed(); | |||||
} | |||||
} else { | |||||
return invocation.proceed(); | |||||
} | |||||
} | |||||
/** | |||||
* 处理分页数量 | |||||
* | |||||
* @param page 分页参数 | |||||
*/ | |||||
protected void handlerLimit(IPage<?> page) { | |||||
page.setSize(this.limit); | |||||
} | |||||
/** | |||||
* 查询总数量 | |||||
* | |||||
* @param sql sql语句 | |||||
* @param mappedStatement 映射语句包装类 | |||||
* @param boundSql sql包装类 | |||||
* @param page 分页参数 | |||||
* @param connection JDBC连接包装类 | |||||
*/ | |||||
protected void queryTotal(String sql, MappedStatement mappedStatement, BoundSql boundSql, IPage<?> page, Connection connection) { | |||||
try { | |||||
PreparedStatement statement = connection.prepareStatement(sql); | |||||
Throwable var7 = null; | |||||
try { | |||||
DefaultParameterHandler parameterHandler = new MybatisDefaultParameterHandler(mappedStatement, boundSql.getParameterObject(), boundSql); | |||||
parameterHandler.setParameters(statement); | |||||
long total = 0L; | |||||
ResultSet resultSet = statement.executeQuery(); | |||||
Throwable var12 = null; | |||||
try { | |||||
if (resultSet.next()) { | |||||
total = resultSet.getLong(1); | |||||
} | |||||
} catch (Throwable var37) { | |||||
var12 = var37; | |||||
throw var37; | |||||
} finally { | |||||
if (resultSet != null) { | |||||
if (var12 != null) { | |||||
try { | |||||
resultSet.close(); | |||||
} catch (Throwable var36) { | |||||
var12.addSuppressed(var36); | |||||
} | |||||
} else { | |||||
resultSet.close(); | |||||
} | |||||
} | |||||
} | |||||
page.setTotal(total); | |||||
if (this.overflow && page.getCurrent() > page.getPages()) { | |||||
this.handlerOverflow(page); | |||||
} | |||||
} catch (Throwable var39) { | |||||
var7 = var39; | |||||
throw var39; | |||||
} finally { | |||||
if (statement != null) { | |||||
if (var7 != null) { | |||||
try { | |||||
statement.close(); | |||||
} catch (Throwable var35) { | |||||
var7.addSuppressed(var35); | |||||
} | |||||
} else { | |||||
statement.close(); | |||||
} | |||||
} | |||||
} | |||||
} catch (Exception var41) { | |||||
throw ExceptionUtils.mpe("Error: Method queryTotal execution error of sql : \n %s \n", var41, new Object[]{sql}); | |||||
} | |||||
} | |||||
/** | |||||
* 设置默认当前页 | |||||
* | |||||
* @param page 分页参数 | |||||
*/ | |||||
protected void handlerOverflow(IPage<?> page) { | |||||
page.setCurrent(1L); | |||||
} | |||||
/** | |||||
* MybatisPlus拦截器实现自定义插件 | |||||
* | |||||
* @param target 拦截目标对象 | |||||
* @return | |||||
*/ | |||||
@Override | |||||
public Object plugin(Object target) { | |||||
return target instanceof StatementHandler ? Plugin.wrap(target, this) : target; | |||||
} | |||||
/** | |||||
* MybatisPlus拦截器实现自定义属性设置 | |||||
* | |||||
* @param prop 属性参数 | |||||
*/ | |||||
@Override | |||||
public void setProperties(Properties prop) { | |||||
String dialectType = prop.getProperty("dialectType"); | |||||
String dialectClazz = prop.getProperty("dialectClazz"); | |||||
if (StringUtils.isNotBlank(dialectType)) { | |||||
this.setDialectType(dialectType); | |||||
} | |||||
if (StringUtils.isNotBlank(dialectClazz)) { | |||||
this.setDialectClazz(dialectClazz); | |||||
} | |||||
} | |||||
/** | |||||
* 设置数据源类型 | |||||
* | |||||
* @param dialectType 数据源类型 | |||||
*/ | |||||
@Deprecated | |||||
public void setDialectType(String dialectType) { | |||||
this.setDbType(DbType.getDbType(dialectType)); | |||||
} | |||||
/** | |||||
* 设置方言实现类配置 | |||||
* | |||||
* @param dialectClazz 方言实现类 | |||||
*/ | |||||
@Deprecated | |||||
public void setDialectClazz(String dialectClazz) { | |||||
this.setDialect(DialectFactory.getDialect(dialectClazz)); | |||||
} | |||||
/** | |||||
* 设置获取总数的sql解析器 | |||||
* | |||||
* @param countSqlParser 总数的sql解析器 | |||||
* @return 自定义MybatisPlus拦截器 | |||||
*/ | |||||
public PaginationInterceptor setCountSqlParser(final ISqlParser countSqlParser) { | |||||
this.countSqlParser = countSqlParser; | |||||
return this; | |||||
} | |||||
/** | |||||
* 溢出总页数,设置第一页 | |||||
* | |||||
* @param overflow 溢出总页数 | |||||
* @return 自定义MybatisPlus拦截器 | |||||
*/ | |||||
public PaginationInterceptor setOverflow(final boolean overflow) { | |||||
this.overflow = overflow; | |||||
return this; | |||||
} | |||||
/** | |||||
* 设置分页规则 | |||||
* | |||||
* @param limit 分页数量 | |||||
* @return 自定义MybatisPlus拦截器 | |||||
*/ | |||||
public PaginationInterceptor setLimit(final long limit) { | |||||
this.limit = limit; | |||||
return this; | |||||
} | |||||
/** | |||||
* 设置数据类型 | |||||
* | |||||
* @param dbType 数据类型 | |||||
* @return 自定义MybatisPlus拦截器 | |||||
*/ | |||||
public PaginationInterceptor setDbType(final DbType dbType) { | |||||
this.dbType = dbType; | |||||
return this; | |||||
} | |||||
/** | |||||
* 设置方言 | |||||
* | |||||
* @param dialect 方言 | |||||
* @return 自定义MybatisPlus拦截器 | |||||
*/ | |||||
public PaginationInterceptor setDialect(final IDialect dialect) { | |||||
this.dialect = dialect; | |||||
return this; | |||||
} | |||||
} | |||||
@@ -18,16 +18,25 @@ | |||||
package org.dubhe.utils; | package org.dubhe.utils; | ||||
import java.sql.Timestamp; | import java.sql.Timestamp; | ||||
import java.text.DateFormat; | |||||
import java.text.SimpleDateFormat; | |||||
import java.time.Instant; | import java.time.Instant; | ||||
import java.time.LocalDate; | import java.time.LocalDate; | ||||
import java.time.LocalDateTime; | import java.time.LocalDateTime; | ||||
import java.time.ZoneId; | import java.time.ZoneId; | ||||
import java.util.Date; | |||||
/** | /** | ||||
* @description 日期工具类 | * @description 日期工具类 | ||||
* @date 2020-6-10 | |||||
* @date 2020-06-10 | |||||
*/ | */ | ||||
public class DateUtil { | public class DateUtil { | ||||
private DateUtil(){ | |||||
} | |||||
/** | /** | ||||
* 获取当前时间戳 | * 获取当前时间戳 | ||||
* | * | ||||
@@ -77,4 +86,13 @@ public class DateUtil { | |||||
return (milli-l1); | return (milli-l1); | ||||
} | } | ||||
/** | |||||
* @return 当前字符串时间yyyy-MM-dd HH:mm:ss SSS | |||||
*/ | |||||
public static String getCurrentTimeStr(){ | |||||
Date date = new Date(); | |||||
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS"); | |||||
return dateFormat.format(date); | |||||
} | |||||
} | } |
@@ -19,10 +19,12 @@ package org.dubhe.utils; | |||||
import cn.hutool.core.codec.Base64; | import cn.hutool.core.codec.Base64; | ||||
import cn.hutool.core.io.IoUtil; | import cn.hutool.core.io.IoUtil; | ||||
import cn.hutool.core.util.CharsetUtil; | |||||
import cn.hutool.core.util.IdUtil; | import cn.hutool.core.util.IdUtil; | ||||
import cn.hutool.poi.excel.BigExcelWriter; | import cn.hutool.poi.excel.BigExcelWriter; | ||||
import cn.hutool.poi.excel.ExcelUtil; | import cn.hutool.poi.excel.ExcelUtil; | ||||
import org.apache.poi.util.IOUtils; | import org.apache.poi.util.IOUtils; | ||||
import org.dubhe.enums.LogEnum; | |||||
import org.dubhe.exception.BusinessException; | import org.dubhe.exception.BusinessException; | ||||
import org.springframework.web.multipart.MultipartFile; | import org.springframework.web.multipart.MultipartFile; | ||||
@@ -352,4 +354,56 @@ public class FileUtil extends cn.hutool.core.io.FileUtil { | |||||
return getMd5(getByte(file)); | return getMd5(getByte(file)); | ||||
} | } | ||||
/** | |||||
* 生成文件 | |||||
* @param filePath 文件绝对路径 | |||||
* @param content 文件内容 | |||||
* @param append 文件是否是追加 | |||||
* @return | |||||
*/ | |||||
public static boolean generateFile(String filePath,String content,boolean append){ | |||||
File file = new File(filePath); | |||||
FileOutputStream outputStream = null; | |||||
try { | |||||
if (!file.exists()){ | |||||
file.createNewFile(); | |||||
} | |||||
outputStream = new FileOutputStream(file,append); | |||||
outputStream.write(content.getBytes(CharsetUtil.defaultCharset())); | |||||
outputStream.flush(); | |||||
}catch (IOException e) { | |||||
LogUtil.error(LogEnum.FILE_UTIL,e); | |||||
return false; | |||||
}finally { | |||||
if (outputStream != null){ | |||||
try { | |||||
outputStream.close(); | |||||
} catch (IOException e) { | |||||
LogUtil.error(LogEnum.FILE_UTIL,e); | |||||
} | |||||
} | |||||
} | |||||
return true; | |||||
} | |||||
/** | |||||
* 压缩文件目录 | |||||
* | |||||
* @param zipDir 待压缩文件夹路径 | |||||
* @param zipFile 压缩完成zip文件绝对路径 | |||||
* @return | |||||
*/ | |||||
public static boolean zipPath(String zipDir,String zipFile) { | |||||
if (zipDir == null) { | |||||
return false; | |||||
} | |||||
File zip = new File(zipFile); | |||||
cn.hutool.core.util.ZipUtil.zip(zip, CharsetUtil.defaultCharset(), true, | |||||
(f) -> !f.isDirectory(), | |||||
new File(zipDir).listFiles()); | |||||
return true; | |||||
} | |||||
} | } |
@@ -20,6 +20,7 @@ import org.apache.commons.io.IOUtils; | |||||
import org.dubhe.enums.LogEnum; | import org.dubhe.enums.LogEnum; | ||||
import javax.net.ssl.HttpsURLConnection; | import javax.net.ssl.HttpsURLConnection; | ||||
import javax.net.ssl.SSLContext; | import javax.net.ssl.SSLContext; | ||||
import javax.net.ssl.SSLSocketFactory; | import javax.net.ssl.SSLSocketFactory; | ||||
@@ -31,13 +32,13 @@ import java.io.InputStreamReader; | |||||
import java.net.URL; | import java.net.URL; | ||||
import java.security.cert.CertificateException; | import java.security.cert.CertificateException; | ||||
import java.security.cert.X509Certificate; | import java.security.cert.X509Certificate; | ||||
import org.apache.commons.codec.binary.Base64; | |||||
import static org.dubhe.constant.StringConstant.UTF8; | import static org.dubhe.constant.StringConstant.UTF8; | ||||
import static org.dubhe.constant.SymbolConstant.BLANK; | import static org.dubhe.constant.SymbolConstant.BLANK; | ||||
/** | /** | ||||
* @description: httpClient工具类,不校验SSL证书 | |||||
* @date: 2020-5-21 | |||||
* @description httpClient工具类,不校验SSL证书 | |||||
* @date 2020-05-21 | |||||
*/ | */ | ||||
public class HttpClientUtils { | public class HttpClientUtils { | ||||
@@ -45,7 +46,7 @@ public class HttpClientUtils { | |||||
InputStream inputStream = null; | InputStream inputStream = null; | ||||
BufferedReader bufferedReader = null; | BufferedReader bufferedReader = null; | ||||
InputStreamReader inputStreamReader = null; | InputStreamReader inputStreamReader = null; | ||||
StringBuilder stringBuider = new StringBuilder(); | |||||
StringBuilder stringBuilder = new StringBuilder(); | |||||
String result = BLANK; | String result = BLANK; | ||||
HttpsURLConnection con = null; | HttpsURLConnection con = null; | ||||
try { | try { | ||||
@@ -59,10 +60,10 @@ public class HttpClientUtils { | |||||
String str = null; | String str = null; | ||||
while ((str = bufferedReader.readLine()) != null) { | while ((str = bufferedReader.readLine()) != null) { | ||||
stringBuider.append(str); | |||||
stringBuilder.append(str); | |||||
} | } | ||||
result = stringBuider.toString(); | |||||
result = stringBuilder.toString(); | |||||
LogUtil.info(LogEnum.BIZ_SYS,"Request path:{}, SUCCESS, result:{}", path, result); | LogUtil.info(LogEnum.BIZ_SYS,"Request path:{}, SUCCESS, result:{}", path, result); | ||||
} catch (Exception e) { | } catch (Exception e) { | ||||
@@ -74,17 +75,54 @@ public class HttpClientUtils { | |||||
return result; | return result; | ||||
} | } | ||||
public static String sendHttpsDelete(String path,String username,String password) { | |||||
InputStream inputStream = null; | |||||
BufferedReader bufferedReader = null; | |||||
InputStreamReader inputStreamReader = null; | |||||
StringBuilder stringBuilder = new StringBuilder(); | |||||
String result = BLANK; | |||||
HttpsURLConnection con = null; | |||||
try { | |||||
con = getConnection(path); | |||||
String input =username+ ":" +password; | |||||
String encoding=Base64.encodeBase64String(input.getBytes()); | |||||
con.setRequestProperty(JwtUtils.AUTH_HEADER, "Basic " + encoding); | |||||
con.setRequestMethod("DELETE"); | |||||
con.connect(); | |||||
/**将返回的输入流转换成字符串**/ | |||||
inputStream = con.getInputStream(); | |||||
inputStreamReader = new InputStreamReader(inputStream, UTF8); | |||||
bufferedReader = new BufferedReader(inputStreamReader); | |||||
private static void closeResource(BufferedReader bufferedReader,InputStreamReader inputStreamReader,InputStream inputStream,HttpsURLConnection con) { | |||||
String str = null; | |||||
while ((str = bufferedReader.readLine()) != null) { | |||||
stringBuilder.append(str); | |||||
} | |||||
IOUtils.closeQuietly(bufferedReader); | |||||
result = stringBuilder.toString(); | |||||
LogUtil.info(LogEnum.BIZ_SYS,"Request path:{}, SUCCESS, result:{}", path, result); | |||||
if (inputStreamReader != null) { | |||||
IOUtils.closeQuietly(inputStreamReader); | |||||
} catch (Exception e) { | |||||
LogUtil.error(LogEnum.BIZ_SYS,"Request path:{}, ERROR, exception:{}", path, e); | |||||
return result; | |||||
} finally { | |||||
closeResource(bufferedReader,inputStreamReader,inputStream,con); | |||||
} | } | ||||
return result; | |||||
} | |||||
private static void closeResource(BufferedReader bufferedReader,InputStreamReader inputStreamReader,InputStream inputStream,HttpsURLConnection con) { | |||||
if (inputStream != null) { | if (inputStream != null) { | ||||
IOUtils.closeQuietly(inputStream); | IOUtils.closeQuietly(inputStream); | ||||
} | } | ||||
if (inputStreamReader != null) { | |||||
IOUtils.closeQuietly(inputStreamReader); | |||||
} | |||||
if (bufferedReader != null) { | |||||
IOUtils.closeQuietly(bufferedReader); | |||||
} | |||||
if (con != null) { | if (con != null) { | ||||
con.disconnect(); | con.disconnect(); | ||||
} | } | ||||
@@ -20,8 +20,8 @@ package org.dubhe.utils; | |||||
import lombok.extern.slf4j.Slf4j; | import lombok.extern.slf4j.Slf4j; | ||||
/** | /** | ||||
* @description: HttpUtil | |||||
* @date 2020.04.30 | |||||
* @description HttpUtil | |||||
* @date 2020-04-30 | |||||
*/ | */ | ||||
@Slf4j | @Slf4j | ||||
public class HttpUtils { | public class HttpUtils { | ||||
@@ -0,0 +1,46 @@ | |||||
/** | |||||
* Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||||
* | |||||
* 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.dubhe.utils; | |||||
import org.dubhe.enums.LogEnum; | |||||
import java.io.Closeable; | |||||
import java.io.IOException; | |||||
/** | |||||
* @description IO流操作工具类 | |||||
* @date 2020-10-14 | |||||
*/ | |||||
public class IOUtil { | |||||
/** | |||||
* 循环的依次关闭流 | |||||
* | |||||
* @param closeableList 要被关闭的流集合 | |||||
*/ | |||||
public static void close(Closeable... closeableList) { | |||||
for (Closeable closeable : closeableList) { | |||||
try { | |||||
if (closeable != null) { | |||||
closeable.close(); | |||||
} | |||||
} catch (IOException e) { | |||||
LogUtil.error(LogEnum.IO_UTIL, "关闭流异常,异常信息:{}", e); | |||||
} | |||||
} | |||||
} | |||||
} |
@@ -139,7 +139,7 @@ public class JwtUtils { | |||||
public static boolean isTokenExpired(String token) { | public static boolean isTokenExpired(String token) { | ||||
Date now = Calendar.getInstance().getTime(); | Date now = Calendar.getInstance().getTime(); | ||||
DecodedJWT jwt = JWT.decode(token); | DecodedJWT jwt = JWT.decode(token); | ||||
return jwt.getExpiresAt().before(now); | |||||
return jwt.getExpiresAt() == null || jwt.getExpiresAt().before(now); | |||||
} | } | ||||
/** | /** | ||||
@@ -67,12 +67,12 @@ public class K8sNameTool { | |||||
} | } | ||||
/** | /** | ||||
* 生成 Notebook的NameSpace | |||||
* 生成 Notebook的Namespace | |||||
* | * | ||||
* @param userId | * @param userId | ||||
* @return namespace | * @return namespace | ||||
*/ | */ | ||||
public String generateNameSpace(long userId) { | |||||
public String generateNamespace(long userId) { | |||||
return this.k8sNameConfig.getNamespace() + SEPARATOR + userId; | return this.k8sNameConfig.getNamespace() + SEPARATOR + userId; | ||||
} | } | ||||
@@ -96,7 +96,7 @@ public class K8sNameTool { | |||||
* @param namespace | * @param namespace | ||||
* @return Long | * @return Long | ||||
*/ | */ | ||||
public Long getUserIdFromNameSpace(String namespace) { | |||||
public Long getUserIdFromNamespace(String namespace) { | |||||
if (StringUtils.isEmpty(namespace) || !namespace.contains(this.k8sNameConfig.getNamespace() + SEPARATOR)) { | if (StringUtils.isEmpty(namespace) || !namespace.contains(this.k8sNameConfig.getNamespace() + SEPARATOR)) { | ||||
return null; | return null; | ||||
} | } | ||||
@@ -0,0 +1,307 @@ | |||||
/** | |||||
* Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||||
* | |||||
* 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.dubhe.utils; | |||||
import cn.hutool.core.util.StrUtil; | |||||
import lombok.Getter; | |||||
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry; | |||||
import org.apache.commons.compress.archivers.zip.ZipFile; | |||||
import org.apache.commons.io.IOUtils; | |||||
import org.dubhe.base.MagicNumConstant; | |||||
import org.dubhe.config.NfsConfig; | |||||
import org.dubhe.enums.LogEnum; | |||||
import org.springframework.beans.factory.annotation.Autowired; | |||||
import org.springframework.beans.factory.annotation.Value; | |||||
import org.springframework.stereotype.Component; | |||||
import org.springframework.util.FileCopyUtils; | |||||
import java.io.*; | |||||
import java.util.Enumeration; | |||||
import java.util.zip.ZipEntry; | |||||
/** | |||||
* @description 本地文件操作工具类 | |||||
* @date 2020-08-19 | |||||
*/ | |||||
@Component | |||||
@Getter | |||||
public class LocalFileUtil { | |||||
@Autowired | |||||
private NfsConfig nfsConfig; | |||||
private static final String FILE_SEPARATOR = File.separator; | |||||
private static final String ZIP = ".zip"; | |||||
private static final String CHARACTER_GBK = "GBK"; | |||||
private static final String OS_NAME = "os.name"; | |||||
private static final String WINDOWS = "Windows"; | |||||
@Value("${k8s.nfs-root-path}") | |||||
private String nfsRootPath; | |||||
@Value("${k8s.nfs-root-windows-path}") | |||||
private String nfsRootWindowsPath; | |||||
/** | |||||
* windows 与 linux 的路径兼容 | |||||
* | |||||
* @param path linux下的路径 | |||||
* @return path 兼容windows后的路径 | |||||
*/ | |||||
private String compatiblePath(String path) { | |||||
if (path == null) { | |||||
return null; | |||||
} | |||||
if (System.getProperties().getProperty(OS_NAME).contains(WINDOWS)) { | |||||
path = path.replace(nfsRootPath, StrUtil.SLASH); | |||||
path = path.replace(StrUtil.SLASH, FILE_SEPARATOR); | |||||
path = nfsRootWindowsPath + path; | |||||
} | |||||
return path; | |||||
} | |||||
/** | |||||
* 本地解压zip包并删除压缩文件 | |||||
* | |||||
* @param sourcePath zip源文件 例如:/abc/z.zip | |||||
* @param targetPath 解压后的目标文件夹 例如:/abc/ | |||||
* @return boolean | |||||
*/ | |||||
public boolean unzipLocalPath(String sourcePath, String targetPath) { | |||||
if (StringUtils.isEmpty(sourcePath) || StringUtils.isEmpty(targetPath)) { | |||||
return false; | |||||
} | |||||
if (!sourcePath.toLowerCase().endsWith(ZIP)) { | |||||
return false; | |||||
} | |||||
//绝对路径 | |||||
String sourceAbsolutePath = nfsConfig.getRootDir() + sourcePath; | |||||
String targetPathAbsolutePath = nfsConfig.getRootDir() + targetPath; | |||||
ZipFile zipFile = null; | |||||
InputStream in = null; | |||||
OutputStream out = null; | |||||
File sourceFile = new File(compatiblePath(sourceAbsolutePath)); | |||||
File targetFileDir = new File(compatiblePath(targetPathAbsolutePath)); | |||||
if (!targetFileDir.exists()) { | |||||
boolean targetMkdir = targetFileDir.mkdirs(); | |||||
if (!targetMkdir) { | |||||
LogUtil.error(LogEnum.LOCAL_FILE_UTIL, "{}failed to create target folder before decompression", sourceAbsolutePath); | |||||
} | |||||
} | |||||
try { | |||||
zipFile = new ZipFile(sourceFile); | |||||
//判断压缩文件编码方式,并重新获取文件对象 | |||||
try { | |||||
zipFile.close(); | |||||
zipFile = new ZipFile(sourceFile, CHARACTER_GBK); | |||||
} catch (Exception e) { | |||||
zipFile.close(); | |||||
zipFile = new ZipFile(sourceFile); | |||||
LogUtil.error(LogEnum.LOCAL_FILE_UTIL, "{}the encoding mode of decompressed compressed file is changed to UTF-8:{}", sourceAbsolutePath, e); | |||||
} | |||||
ZipEntry entry; | |||||
Enumeration enumeration = zipFile.getEntries(); | |||||
while (enumeration.hasMoreElements()) { | |||||
entry = (ZipEntry) enumeration.nextElement(); | |||||
String entryName = entry.getName(); | |||||
File fileDir; | |||||
if (entry.isDirectory()) { | |||||
fileDir = new File(targetPathAbsolutePath + entry.getName()); | |||||
if (!fileDir.exists()) { | |||||
boolean fileMkdir = fileDir.mkdirs(); | |||||
if (!fileMkdir) { | |||||
LogUtil.error(LogEnum.LOCAL_FILE_UTIL, "failed to create folder {} while decompressing {}", fileDir, sourceAbsolutePath); | |||||
} | |||||
} | |||||
} else { | |||||
//若文件夹未创建则创建文件夹 | |||||
if (entryName.contains(FILE_SEPARATOR)) { | |||||
String zipDirName = entryName.substring(MagicNumConstant.ZERO, entryName.lastIndexOf(FILE_SEPARATOR)); | |||||
fileDir = new File(targetPathAbsolutePath + zipDirName); | |||||
if (!fileDir.exists()) { | |||||
boolean fileMkdir = fileDir.mkdirs(); | |||||
if (!fileMkdir) { | |||||
LogUtil.error(LogEnum.LOCAL_FILE_UTIL, "failed to create folder {} while decompressing {}", fileDir, sourceAbsolutePath); | |||||
} | |||||
} | |||||
} | |||||
in = zipFile.getInputStream((ZipArchiveEntry) entry); | |||||
out = new FileOutputStream(new File(targetPathAbsolutePath, entryName)); | |||||
IOUtils.copyLarge(in, out); | |||||
in.close(); | |||||
out.close(); | |||||
} | |||||
} | |||||
boolean deleteZipFile = sourceFile.delete(); | |||||
if (!deleteZipFile) { | |||||
LogUtil.error(LogEnum.LOCAL_FILE_UTIL, "{}compressed file deletion failed after decompression", sourceAbsolutePath); | |||||
} | |||||
return true; | |||||
} catch (IOException e) { | |||||
LogUtil.error(LogEnum.LOCAL_FILE_UTIL, "{}decompression failed: {}", sourceAbsolutePath, e); | |||||
return false; | |||||
} finally { | |||||
//关闭未关闭的io流 | |||||
closeIoFlow(sourceAbsolutePath, zipFile, in, out); | |||||
} | |||||
} | |||||
/** | |||||
* 关闭未关闭的io流 | |||||
* | |||||
* @param sourceAbsolutePath 源路径 | |||||
* @param zipFile 压缩文件对象 | |||||
* @param in 输入流 | |||||
* @param out 输出流 | |||||
*/ | |||||
private void closeIoFlow(String sourceAbsolutePath, ZipFile zipFile, InputStream in, OutputStream out) { | |||||
if (in != null) { | |||||
try { | |||||
in.close(); | |||||
} catch (IOException e) { | |||||
LogUtil.error(LogEnum.LOCAL_FILE_UTIL, "{}input stream shutdown failed: {}", sourceAbsolutePath, e); | |||||
} | |||||
} | |||||
if (out != null) { | |||||
try { | |||||
out.close(); | |||||
} catch (IOException e) { | |||||
LogUtil.error(LogEnum.LOCAL_FILE_UTIL, "{}output stream shutdown failed: {}", sourceAbsolutePath, e); | |||||
} | |||||
} | |||||
if (zipFile != null) { | |||||
try { | |||||
zipFile.close(); | |||||
} catch (IOException e) { | |||||
LogUtil.error(LogEnum.LOCAL_FILE_UTIL, "{}input stream shutdown failed: {}", sourceAbsolutePath, e); | |||||
} | |||||
} | |||||
} | |||||
/** | |||||
* NFS 复制目录到指定目录下 多个文件 包含目录与文件并存情况 | |||||
* | |||||
* 通过本地文件复制方式 | |||||
* | |||||
* @param sourcePath 需要复制的文件目录 例如:/abc/def | |||||
* @param targetPath 需要放置的目标目录 例如:/abc/dd | |||||
* @return boolean | |||||
*/ | |||||
public boolean copyPath(String sourcePath, String targetPath) { | |||||
if (StringUtils.isEmpty(sourcePath) || StringUtils.isEmpty(targetPath)) { | |||||
return false; | |||||
} | |||||
sourcePath = formatPath(sourcePath); | |||||
targetPath = formatPath(targetPath); | |||||
try { | |||||
return copyLocalPath(nfsConfig.getRootDir() + sourcePath, nfsConfig.getRootDir() + targetPath); | |||||
} catch (Exception e) { | |||||
LogUtil.error(LogEnum.LOCAL_FILE_UTIL, " failed to Copy file original path: {} ,target path: {} ,copyPath: {}", sourcePath, targetPath, e); | |||||
return false; | |||||
} | |||||
} | |||||
/** | |||||
* 复制文件到指定目录下 单个文件 | |||||
* | |||||
* @param sourcePath 需要复制的文件 例如:/abc/def/cc.txt | |||||
* @param targetPath 需要放置的目标目录 例如:/abc/dd | |||||
* @return boolean | |||||
*/ | |||||
private boolean copyLocalFile(String sourcePath, String targetPath) { | |||||
if (StringUtils.isEmpty(sourcePath) || StringUtils.isEmpty(targetPath)) { | |||||
return false; | |||||
} | |||||
sourcePath = formatPath(sourcePath); | |||||
targetPath = formatPath(targetPath); | |||||
try (InputStream input = new FileInputStream(sourcePath); | |||||
FileOutputStream output = new FileOutputStream(targetPath)) { | |||||
FileCopyUtils.copy(input, output); | |||||
return true; | |||||
} catch (IOException e) { | |||||
LogUtil.error(LogEnum.LOCAL_FILE_UTIL, " failed to copy file original path: {} ,target path: {} ,copyLocalFile:{} ", sourcePath, targetPath, e); | |||||
return false; | |||||
} | |||||
} | |||||
/** | |||||
* 复制文件 到指定目录下 多个文件 包含目录与文件并存情况 | |||||
* | |||||
* @param sourcePath 需要复制的文件目录 例如:/abc/def | |||||
* @param targetPath 需要放置的目标目录 例如:/abc/dd | |||||
* @return boolean | |||||
*/ | |||||
private boolean copyLocalPath(String sourcePath, String targetPath) { | |||||
if (!StringUtils.isEmpty(sourcePath) && !StringUtils.isEmpty(targetPath)) { | |||||
sourcePath = formatPath(sourcePath); | |||||
if (sourcePath.endsWith(FILE_SEPARATOR)) { | |||||
sourcePath = sourcePath.substring(MagicNumConstant.ZERO, sourcePath.lastIndexOf(FILE_SEPARATOR)); | |||||
} | |||||
targetPath = formatPath(targetPath); | |||||
File sourceFile = new File(sourcePath); | |||||
if (sourceFile.exists()) { | |||||
File[] files = sourceFile.listFiles(); | |||||
if (files != null && files.length != 0) { | |||||
for (File file : files) { | |||||
try { | |||||
if (file.isDirectory()) { | |||||
File fileDir = new File(targetPath + FILE_SEPARATOR + file.getName()); | |||||
if (!fileDir.exists()) { | |||||
fileDir.mkdirs(); | |||||
} | |||||
copyLocalPath(sourcePath + FILE_SEPARATOR + file.getName(), targetPath + FILE_SEPARATOR + file.getName()); | |||||
} | |||||
if (file.isFile()) { | |||||
File fileTargetPath = new File(targetPath); | |||||
if (!fileTargetPath.exists()) { | |||||
fileTargetPath.mkdirs(); | |||||
} | |||||
copyLocalFile(file.getAbsolutePath(), targetPath + FILE_SEPARATOR + file.getName()); | |||||
} | |||||
} catch (Exception e) { | |||||
LogUtil.error(LogEnum.LOCAL_FILE_UTIL, "failed to copy folder original path: {} , target path : {} ,copyLocalPath: {}", sourcePath, targetPath, e); | |||||
return false; | |||||
} | |||||
} | |||||
} | |||||
return true; | |||||
} | |||||
} | |||||
return false; | |||||
} | |||||
/** | |||||
* 替换路径中多余的 "/" | |||||
* | |||||
* @param path | |||||
* @return String | |||||
*/ | |||||
public String formatPath(String path) { | |||||
if (!StringUtils.isEmpty(path)) { | |||||
return path.replaceAll("///*", FILE_SEPARATOR); | |||||
} | |||||
return path; | |||||
} | |||||
} |
@@ -23,10 +23,10 @@ import lombok.extern.slf4j.Slf4j; | |||||
import org.apache.commons.lang3.exception.ExceptionUtils; | import org.apache.commons.lang3.exception.ExceptionUtils; | ||||
import org.dubhe.aspect.LogAspect; | import org.dubhe.aspect.LogAspect; | ||||
import org.dubhe.base.MagicNumConstant; | import org.dubhe.base.MagicNumConstant; | ||||
import org.dubhe.constant.SymbolConstant; | |||||
import org.dubhe.domain.entity.LogInfo; | import org.dubhe.domain.entity.LogInfo; | ||||
import org.dubhe.enums.LogEnum; | import org.dubhe.enums.LogEnum; | ||||
import org.slf4j.MDC; | import org.slf4j.MDC; | ||||
import org.slf4j.MarkerFactory; | |||||
import org.slf4j.helpers.MessageFormatter; | import org.slf4j.helpers.MessageFormatter; | ||||
import java.util.Arrays; | import java.util.Arrays; | ||||
@@ -38,218 +38,283 @@ import java.util.UUID; | |||||
*/ | */ | ||||
@Slf4j | @Slf4j | ||||
public class LogUtil { | public class LogUtil { | ||||
/** | |||||
* info级别的日志 | |||||
* | |||||
* @param logType 日志类型 | |||||
* @param object 打印的日志参数 | |||||
*/ | |||||
public static void info(LogEnum logType, Object... object) { | |||||
logHandle(logType, Level.INFO, object); | |||||
} | |||||
/** | |||||
* debug级别的日志 | |||||
* | |||||
* @param logType 日志类型 | |||||
* @param object 打印的日志参数 | |||||
*/ | |||||
public static void debug(LogEnum logType, Object... object) { | |||||
logHandle(logType, Level.DEBUG, object); | |||||
} | |||||
/** | |||||
* error级别的日志 | |||||
* | |||||
* @param logType 日志类型 | |||||
* @param object 打印的日志参数 | |||||
*/ | |||||
public static void error(LogEnum logType, Object... object) { | |||||
errorObjectHandle(object); | |||||
logHandle(logType, Level.ERROR, object); | |||||
} | |||||
/** | |||||
* warn级别的日志 | |||||
* | |||||
* @param logType 日志类型 | |||||
* @param object 打印的日志参数 | |||||
*/ | |||||
public static void warn(LogEnum logType, Object... object) { | |||||
logHandle(logType, Level.WARN, object); | |||||
} | |||||
/** | |||||
* trace级别的日志 | |||||
* | |||||
* @param logType 日志类型 | |||||
* @param object 打印的日志参数 | |||||
*/ | |||||
public static void trace(LogEnum logType, Object... object) { | |||||
logHandle(logType, Level.TRACE, object); | |||||
} | |||||
/** | |||||
* 日志处理 | |||||
* | |||||
* @param logType 日志类型 | |||||
* @param level 日志级别 | |||||
* @param object 打印的日志参数 | |||||
*/ | |||||
private static void logHandle(LogEnum logType, Level level, Object[] object) { | |||||
LogInfo logInfo = generateLogInfo(logType, level, object); | |||||
String logInfoJsonStr = logJsonStringLengthLimit(logInfo); | |||||
switch (Level.toLevel(logInfo.getLevel()).levelInt) { | |||||
case Level.TRACE_INT: | |||||
log.trace(logInfoJsonStr); | |||||
break; | |||||
case Level.DEBUG_INT: | |||||
log.debug(logInfoJsonStr); | |||||
break; | |||||
case Level.INFO_INT: | |||||
log.info(logInfoJsonStr); | |||||
break; | |||||
case Level.WARN_INT: | |||||
log.warn(logInfoJsonStr); | |||||
break; | |||||
case Level.ERROR_INT: | |||||
log.error(logInfoJsonStr); | |||||
break; | |||||
default: | |||||
} | |||||
} | |||||
/** | |||||
* 日志信息组装的内部方法 | |||||
* | |||||
* @param logType 日志类型 | |||||
* @param level 日志级别 | |||||
* @param object 打印的日志参数 | |||||
* @return LogInfo日志对象信息 | |||||
*/ | |||||
private static LogInfo generateLogInfo(LogEnum logType, Level level, Object[] object) { | |||||
LogInfo logInfo = new LogInfo(); | |||||
// 日志类型检测 | |||||
if (!LogEnum.isLogType(logType)) { | |||||
level = Level.ERROR; | |||||
object = new Object[MagicNumConstant.ONE]; | |||||
object[MagicNumConstant.ZERO] = String.valueOf("logType【").concat(String.valueOf(logType)) | |||||
.concat("】is error !"); | |||||
logType = LogEnum.SYS_ERR; | |||||
} | |||||
// 获取trace_id | |||||
if (StringUtils.isEmpty(MDC.get(LogAspect.TRACE_ID))) { | |||||
MDC.put(LogAspect.TRACE_ID, UUID.randomUUID().toString()); | |||||
} | |||||
// 设置logInfo的level,type,traceId属性 | |||||
logInfo.setLevel(level.levelStr).setType(logType.toString()).setTraceId(MDC.get(LogAspect.TRACE_ID)); | |||||
// 设置logInfo的堆栈信息 | |||||
setLogStackInfo(logInfo); | |||||
// 设置logInfo的info信息 | |||||
setLogInfo(logInfo, object); | |||||
// 截取loginfo的长度并转换成json字符串 | |||||
return logInfo; | |||||
} | |||||
/** | |||||
* 设置loginfo的堆栈信息 | |||||
* | |||||
* @param logInfo 日志对象 | |||||
*/ | |||||
private static void setLogStackInfo(LogInfo logInfo) { | |||||
StackTraceElement[] elements = Thread.currentThread().getStackTrace(); | |||||
if (elements.length >= MagicNumConstant.SIX) { | |||||
logInfo.setCName(elements[MagicNumConstant.FIVE].getClassName()) | |||||
.setMName(elements[MagicNumConstant.FIVE].getMethodName()) | |||||
.setLine(String.valueOf(elements[MagicNumConstant.FIVE].getLineNumber())); | |||||
} | |||||
} | |||||
/** | |||||
* 限制log日志的长度并转换成json | |||||
* | |||||
* @param logInfo 日志对象 | |||||
* @return String 日志对象Json字符串 | |||||
*/ | |||||
private static String logJsonStringLengthLimit(LogInfo logInfo) { | |||||
try { | |||||
String jsonString = JSON.toJSONString(logInfo.getInfo()); | |||||
if (jsonString.length() > MagicNumConstant.TEN_THOUSAND) { | |||||
jsonString = jsonString.substring(MagicNumConstant.ZERO, MagicNumConstant.TEN_THOUSAND); | |||||
} | |||||
logInfo.setInfo(jsonString); | |||||
jsonString = JSON.toJSONString(logInfo); | |||||
jsonString = jsonString.replace(SymbolConstant.BACKSLASH_MARK, SymbolConstant.MARK) | |||||
.replace(SymbolConstant.DOUBLE_MARK, SymbolConstant.MARK) | |||||
.replace(SymbolConstant.BRACKETS, SymbolConstant.BLANK); | |||||
return jsonString; | |||||
} catch (Exception e) { | |||||
logInfo.setLevel(Level.ERROR.levelStr).setType(LogEnum.SYS_ERR.toString()) | |||||
.setInfo("cannot serialize exception: " + ExceptionUtils.getStackTrace(e)); | |||||
return JSON.toJSONString(logInfo); | |||||
} | |||||
} | |||||
/** | |||||
* 设置日志对象的info信息 | |||||
* | |||||
* @param logInfo 日志对象 | |||||
* @param object 打印的日志参数 | |||||
*/ | |||||
private static void setLogInfo(LogInfo logInfo, Object[] object) { | |||||
for (Object obj : object) { | |||||
if (obj instanceof Exception) { | |||||
log.error((ExceptionUtils.getStackTrace((Throwable) obj))); | |||||
} | |||||
} | |||||
if (object.length > MagicNumConstant.ONE) { | |||||
logInfo.setInfo(MessageFormatter.arrayFormat(object[MagicNumConstant.ZERO].toString(), | |||||
Arrays.copyOfRange(object, MagicNumConstant.ONE, object.length)).getMessage()); | |||||
} else if (object.length == MagicNumConstant.ONE && object[MagicNumConstant.ZERO] instanceof Exception) { | |||||
logInfo.setInfo((ExceptionUtils.getStackTrace((Exception) object[MagicNumConstant.ZERO]))); | |||||
} else if (object.length == MagicNumConstant.ONE) { | |||||
logInfo.setInfo( | |||||
object[MagicNumConstant.ZERO] == null ? SymbolConstant.BLANK : object[MagicNumConstant.ZERO]); | |||||
} else { | |||||
logInfo.setInfo(SymbolConstant.BLANK); | |||||
} | |||||
} | |||||
/** | |||||
* 处理Exception的情况 | |||||
* | |||||
* @param object 打印的日志参数 | |||||
*/ | |||||
private static void errorObjectHandle(Object[] object) { | |||||
if (object.length >= MagicNumConstant.TWO) { | |||||
object[MagicNumConstant.ZERO] = String.valueOf(object[MagicNumConstant.ZERO]) | |||||
.concat(SymbolConstant.BRACKETS); | |||||
} | |||||
if (object.length == MagicNumConstant.TWO && object[MagicNumConstant.ONE] instanceof Exception) { | |||||
log.error((ExceptionUtils.getStackTrace((Throwable) object[MagicNumConstant.ONE]))); | |||||
object[MagicNumConstant.ONE] = ExceptionUtils.getStackTrace((Exception) object[MagicNumConstant.ONE]); | |||||
} else if (object.length >= MagicNumConstant.THREE) { | |||||
for (int i = 0; i < object.length; i++) { | |||||
if (object[i] instanceof Exception) { | |||||
log.error((ExceptionUtils.getStackTrace((Throwable) object[i]))); | |||||
object[i] = ExceptionUtils.getStackTrace((Exception) object[i]); | |||||
} | |||||
} | |||||
} | |||||
} | |||||
private static final String TRACE_TYPE = "TRACE_TYPE"; | |||||
public static final String SCHEDULE_LEVEL = "SCHEDULE"; | |||||
public static final String K8S_CALLBACK_LEVEL = "K8S_CALLBACK"; | |||||
private static final String GLOBAL_REQUEST_LEVEL = "GLOBAL_REQUEST"; | |||||
private static final String TRACE_LEVEL = "TRACE"; | |||||
private static final String DEBUG_LEVEL = "DEBUG"; | |||||
private static final String INFO_LEVEL = "INFO"; | |||||
private static final String WARN_LEVEL = "WARN"; | |||||
private static final String ERROR_LEVEL = "ERROR"; | |||||
public static void startScheduleTrace() { | |||||
MDC.put(TRACE_TYPE, SCHEDULE_LEVEL); | |||||
} | |||||
public static void startK8sCallbackTrace() { | |||||
MDC.put(TRACE_TYPE, K8S_CALLBACK_LEVEL); | |||||
} | |||||
public static void cleanTrace() { | |||||
MDC.clear(); | |||||
} | |||||
/** | |||||
* info级别的日志 | |||||
* | |||||
* @param logType 日志类型 | |||||
* @param object 打印的日志参数 | |||||
* @return void | |||||
*/ | |||||
public static void info(LogEnum logType, Object... object) { | |||||
logHandle(logType, Level.INFO, object); | |||||
} | |||||
/** | |||||
* debug级别的日志 | |||||
* | |||||
* @param logType 日志类型 | |||||
* @param object 打印的日志参数 | |||||
* @return void | |||||
*/ | |||||
public static void debug(LogEnum logType, Object... object) { | |||||
logHandle(logType, Level.DEBUG, object); | |||||
} | |||||
/** | |||||
* error级别的日志 | |||||
* | |||||
* @param logType 日志类型 | |||||
* @param object 打印的日志参数 | |||||
* @return void | |||||
*/ | |||||
public static void error(LogEnum logType, Object... object) { | |||||
errorObjectHandle(object); | |||||
logHandle(logType, Level.ERROR, object); | |||||
} | |||||
/** | |||||
* warn级别的日志 | |||||
* | |||||
* @param logType 日志类型 | |||||
* @param object 打印的日志参数 | |||||
* @return void | |||||
*/ | |||||
public static void warn(LogEnum logType, Object... object) { | |||||
logHandle(logType, Level.WARN, object); | |||||
} | |||||
/** | |||||
* trace级别的日志 | |||||
* | |||||
* @param logType 日志类型 | |||||
* @param object 打印的日志参数 | |||||
* @return void | |||||
*/ | |||||
public static void trace(LogEnum logType, Object... object) { | |||||
logHandle(logType, Level.TRACE, object); | |||||
} | |||||
/** | |||||
* 日志处理 | |||||
* | |||||
* @param logType 日志类型 | |||||
* @param level 日志级别 | |||||
* @param object 打印的日志参数 | |||||
* @return void | |||||
*/ | |||||
private static void logHandle(LogEnum logType, Level level, Object[] object) { | |||||
LogInfo logInfo = generateLogInfo(logType, level, object); | |||||
switch (logInfo.getLevel()) { | |||||
case TRACE_LEVEL: | |||||
log.trace(MarkerFactory.getMarker(TRACE_LEVEL), logJsonStringLengthLimit(logInfo)); | |||||
break; | |||||
case DEBUG_LEVEL: | |||||
log.debug(MarkerFactory.getMarker(DEBUG_LEVEL), logJsonStringLengthLimit(logInfo)); | |||||
break; | |||||
case GLOBAL_REQUEST_LEVEL: | |||||
logInfo.setLevel(null); | |||||
logInfo.setType(null); | |||||
logInfo.setLocation(null); | |||||
log.info(MarkerFactory.getMarker(GLOBAL_REQUEST_LEVEL), logJsonStringLengthLimit(logInfo)); | |||||
break; | |||||
case SCHEDULE_LEVEL: | |||||
log.info(MarkerFactory.getMarker(SCHEDULE_LEVEL), logJsonStringLengthLimit(logInfo)); | |||||
break; | |||||
case K8S_CALLBACK_LEVEL: | |||||
log.info(MarkerFactory.getMarker(K8S_CALLBACK_LEVEL), logJsonStringLengthLimit(logInfo)); | |||||
break; | |||||
case INFO_LEVEL: | |||||
log.info(MarkerFactory.getMarker(INFO_LEVEL), logJsonStringLengthLimit(logInfo)); | |||||
break; | |||||
case WARN_LEVEL: | |||||
log.warn(MarkerFactory.getMarker(WARN_LEVEL), logJsonStringLengthLimit(logInfo)); | |||||
break; | |||||
case ERROR_LEVEL: | |||||
log.error(MarkerFactory.getMarker(ERROR_LEVEL), logJsonStringLengthLimit(logInfo)); | |||||
break; | |||||
default: | |||||
} | |||||
} | |||||
/** | |||||
* 日志信息组装的内部方法 | |||||
* | |||||
* @param logType 日志类型 | |||||
* @param level 日志级别 | |||||
* @param object 打印的日志参数 | |||||
* @return LogInfo | |||||
*/ | |||||
private static LogInfo generateLogInfo(LogEnum logType, Level level, Object[] object) { | |||||
LogInfo logInfo = new LogInfo(); | |||||
// 日志类型检测 | |||||
if (!LogEnum.isLogType(logType)) { | |||||
level = Level.ERROR; | |||||
object = new Object[MagicNumConstant.ONE]; | |||||
object[MagicNumConstant.ZERO] = "日志类型【".concat(String.valueOf(logType)).concat("】不正确!"); | |||||
logType = LogEnum.SYS_ERR; | |||||
} | |||||
// 获取trace_id | |||||
if (StringUtils.isEmpty(MDC.get(LogAspect.TRACE_ID))) { | |||||
MDC.put(LogAspect.TRACE_ID, UUID.randomUUID().toString()); | |||||
} | |||||
// 设置logInfo的level,type,traceId属性 | |||||
logInfo.setLevel(level.levelStr) | |||||
.setType(logType.toString()) | |||||
.setTraceId(MDC.get(LogAspect.TRACE_ID)); | |||||
//自定义日志级别 | |||||
//LogEnum、 MDC中的 TRACE_TYPE 做日志分流标识 | |||||
if (Level.INFO.toInt() == level.toInt()) { | |||||
if (LogEnum.GLOBAL_REQ.equals(logType)) { | |||||
//info全局请求 | |||||
logInfo.setLevel(GLOBAL_REQUEST_LEVEL); | |||||
} else if (LogEnum.BIZ_K8S.equals(logType)) { | |||||
logInfo.setLevel(K8S_CALLBACK_LEVEL); | |||||
} else { | |||||
//schedule定时等 链路记录 | |||||
String traceType = MDC.get(TRACE_TYPE); | |||||
if (StringUtils.isNotBlank(traceType)) { | |||||
logInfo.setLevel(traceType); | |||||
} | |||||
} | |||||
} | |||||
// 设置logInfo的堆栈信息 | |||||
setLogStackInfo(logInfo); | |||||
// 设置logInfo的info信息 | |||||
setLogInfo(logInfo, object); | |||||
// 截取logInfo的长度并转换成json字符串 | |||||
return logInfo; | |||||
} | |||||
/** | |||||
* 设置loginfo的堆栈信息 | |||||
* | |||||
* @param logInfo 日志对象 | |||||
* @return void | |||||
*/ | |||||
private static void setLogStackInfo(LogInfo logInfo) { | |||||
StackTraceElement[] elements = Thread.currentThread().getStackTrace(); | |||||
if (elements.length >= MagicNumConstant.SIX) { | |||||
StackTraceElement element = elements[MagicNumConstant.FIVE]; | |||||
logInfo.setLocation(String.format("%s#%s:%s", element.getClassName(), element.getMethodName(), element.getLineNumber())); | |||||
} | |||||
} | |||||
/** | |||||
* 限制log日志的长度并转换成json | |||||
* | |||||
* @param logInfo 日志对象 | |||||
* @return String | |||||
*/ | |||||
private static String logJsonStringLengthLimit(LogInfo logInfo) { | |||||
try { | |||||
String jsonString = JSON.toJSONString(logInfo); | |||||
if (StringUtils.isBlank(jsonString)) { | |||||
return ""; | |||||
} | |||||
if (jsonString.length() > MagicNumConstant.TEN_THOUSAND) { | |||||
String trunk = logInfo.getInfo().toString().substring(MagicNumConstant.ZERO, MagicNumConstant.NINE_THOUSAND); | |||||
logInfo.setInfo(trunk); | |||||
jsonString = JSON.toJSONString(logInfo); | |||||
} | |||||
return jsonString; | |||||
} catch (Exception e) { | |||||
logInfo.setLevel(Level.ERROR.levelStr).setType(LogEnum.SYS_ERR.toString()) | |||||
.setInfo("cannot serialize exception: " + ExceptionUtils.getStackTrace(e)); | |||||
return JSON.toJSONString(logInfo); | |||||
} | |||||
} | |||||
/** | |||||
* 设置日志对象的info信息 | |||||
* | |||||
* @param logInfo 日志对象 | |||||
* @param object 打印的日志参数 | |||||
* @return void | |||||
*/ | |||||
private static void setLogInfo(LogInfo logInfo, Object[] object) { | |||||
if (object.length > MagicNumConstant.ONE) { | |||||
logInfo.setInfo(MessageFormatter.arrayFormat(object[MagicNumConstant.ZERO].toString(), | |||||
Arrays.copyOfRange(object, MagicNumConstant.ONE, object.length)).getMessage()); | |||||
} else if (object.length == MagicNumConstant.ONE && object[MagicNumConstant.ZERO] instanceof Exception) { | |||||
logInfo.setInfo((ExceptionUtils.getStackTrace((Exception) object[MagicNumConstant.ZERO]))); | |||||
log.error((ExceptionUtils.getStackTrace((Exception) object[MagicNumConstant.ZERO]))); | |||||
} else if (object.length == MagicNumConstant.ONE) { | |||||
logInfo.setInfo(object[MagicNumConstant.ZERO] == null ? "" : object[MagicNumConstant.ZERO]); | |||||
} else { | |||||
logInfo.setInfo(""); | |||||
} | |||||
} | |||||
/** | |||||
* 处理Exception的情况 | |||||
* | |||||
* @param object 打印的日志参数 | |||||
* @return void | |||||
*/ | |||||
private static void errorObjectHandle(Object[] object) { | |||||
if (object.length == MagicNumConstant.TWO && object[MagicNumConstant.ONE] instanceof Exception) { | |||||
log.error(String.valueOf(object[MagicNumConstant.ZERO]), (Exception) object[MagicNumConstant.ONE]); | |||||
object[MagicNumConstant.ONE] = ExceptionUtils.getStackTrace((Exception) object[MagicNumConstant.ONE]); | |||||
} else if (object.length >= MagicNumConstant.THREE) { | |||||
log.error(String.valueOf(object[MagicNumConstant.ZERO]), | |||||
Arrays.copyOfRange(object, MagicNumConstant.ONE, object.length)); | |||||
for (int i = 0; i < object.length; i++) { | |||||
if (object[i] instanceof Exception) { | |||||
object[i] = ExceptionUtils.getStackTrace((Exception) object[i]); | |||||
} | |||||
} | |||||
} | |||||
} | |||||
} | } |
@@ -20,8 +20,8 @@ package org.dubhe.utils; | |||||
import org.dubhe.base.MagicNumConstant; | import org.dubhe.base.MagicNumConstant; | ||||
/** | /** | ||||
* @description: 计算工具类 | |||||
* @create: 2020/6/4 14:53 | |||||
* @description 计算工具类 | |||||
* @date 2020-06-04 | |||||
*/ | */ | ||||
public class MathUtils { | public class MathUtils { | ||||
@@ -68,9 +68,9 @@ public class MinioUtil { | |||||
try { | try { | ||||
client = new MinioClient(url, accessKey, secretKey); | client = new MinioClient(url, accessKey, secretKey); | ||||
} catch (InvalidEndpointException e) { | } catch (InvalidEndpointException e) { | ||||
LogUtil.warn(LogEnum.BIZ_DATASET, "MinIO endpoint invalid. e:", e); | |||||
LogUtil.warn(LogEnum.BIZ_DATASET, "MinIO endpoint invalid. e, {}", e); | |||||
} catch (InvalidPortException e) { | } catch (InvalidPortException e) { | ||||
LogUtil.warn(LogEnum.BIZ_DATASET, "MinIO endpoint port invalid. e:", e); | |||||
LogUtil.warn(LogEnum.BIZ_DATASET, "MinIO endpoint port invalid. e, {}", e); | |||||
} | } | ||||
} | } | ||||
@@ -94,7 +94,7 @@ public class MinioUtil { | |||||
/** | /** | ||||
* 读取文件 | * 读取文件 | ||||
* | * | ||||
* @param bucket | |||||
* @param bucket 桶 | |||||
* @param fullFilePath 文件存储的全路径,包括文件名,非'/'开头. e.g. dataset/12/annotation/test.txt | * @param fullFilePath 文件存储的全路径,包括文件名,非'/'开头. e.g. dataset/12/annotation/test.txt | ||||
* @return String | * @return String | ||||
*/ | */ | ||||
@@ -107,7 +107,7 @@ public class MinioUtil { | |||||
/** | /** | ||||
* 文件删除 | * 文件删除 | ||||
* | * | ||||
* @param bucket | |||||
* @param bucket 桶 | |||||
* @param fullFilePath 文件存储的全路径,包括文件名,非'/'开头. e.g. dataset/12/annotation/test.txt | * @param fullFilePath 文件存储的全路径,包括文件名,非'/'开头. e.g. dataset/12/annotation/test.txt | ||||
*/ | */ | ||||
public void del(String bucket, String fullFilePath) throws Exception { | public void del(String bucket, String fullFilePath) throws Exception { | ||||
@@ -125,8 +125,8 @@ public class MinioUtil { | |||||
/** | /** | ||||
* 批量删除文件 | * 批量删除文件 | ||||
* | * | ||||
* @param bucket | |||||
* @param objectNames | |||||
* @param bucket 桶 | |||||
* @param objectNames 对象名称 | |||||
*/ | */ | ||||
public void delFiles(String bucket,List<String> objectNames) throws Exception{ | public void delFiles(String bucket,List<String> objectNames) throws Exception{ | ||||
Iterable<Result<DeleteError>> results = client.removeObjects(bucket, objectNames); | Iterable<Result<DeleteError>> results = client.removeObjects(bucket, objectNames); | ||||
@@ -138,6 +138,10 @@ public class MinioUtil { | |||||
/** | /** | ||||
* 获取对象名称 | * 获取对象名称 | ||||
* | * | ||||
* @param bucketName 桶名称 | |||||
* @param prefix 前缀 | |||||
* @return | |||||
* @throws Exception | |||||
*/ | */ | ||||
public List<String> getObjects(String bucketName, String prefix)throws Exception{ | public List<String> getObjects(String bucketName, String prefix)throws Exception{ | ||||
List<String> fileNames = new ArrayList<>(); | List<String> fileNames = new ArrayList<>(); | ||||
@@ -152,6 +156,10 @@ public class MinioUtil { | |||||
/** | /** | ||||
* 获取文件流 | * 获取文件流 | ||||
* | * | ||||
* @param bucket 桶 | |||||
* @param objectName 对象名称 | |||||
* @return | |||||
* @throws Exception | |||||
*/ | */ | ||||
public InputStream getObjectInputStream(String bucket,String objectName)throws Exception{ | public InputStream getObjectInputStream(String bucket,String objectName)throws Exception{ | ||||
return client.getObject(bucket, objectName); | return client.getObject(bucket, objectName); | ||||
@@ -160,9 +168,9 @@ public class MinioUtil { | |||||
/** | /** | ||||
* 文件夹复制 | * 文件夹复制 | ||||
* | * | ||||
* @param bucket | |||||
* @param bucket 桶 | |||||
* @param sourceFiles 源文件 | * @param sourceFiles 源文件 | ||||
* @param targetDir 目标文件夹 | |||||
* @param targetDir 目标文件夹 | |||||
*/ | */ | ||||
public void copyDir(String bucket, List<String> sourceFiles, String targetDir) { | public void copyDir(String bucket, List<String> sourceFiles, String targetDir) { | ||||
sourceFiles.forEach(sourceFile -> { | sourceFiles.forEach(sourceFile -> { | ||||
@@ -211,10 +219,10 @@ public class MinioUtil { | |||||
/** | /** | ||||
* 生成文件下载请求参数方法 | * 生成文件下载请求参数方法 | ||||
* | * | ||||
* @param bucketName | |||||
* @param prefix | |||||
* @param objects | |||||
* @return MinioDownloadDto | |||||
* @param bucketName 桶名称 | |||||
* @param prefix 前缀 | |||||
* @param objects 对象名称 | |||||
* @return MinioDownloadDto 下载请求参数 | |||||
*/ | */ | ||||
public MinioDownloadDto getDownloadParam(String bucketName, String prefix, List<String> objects, String zipName) { | public MinioDownloadDto getDownloadParam(String bucketName, String prefix, List<String> objects, String zipName) { | ||||
String paramTemplate = "{\"id\":%d,\"jsonrpc\":\"%s\",\"params\":{\"username\":\"%s\",\"password\":\"%s\"},\"method\":\"%s\"}"; | String paramTemplate = "{\"id\":%d,\"jsonrpc\":\"%s\",\"params\":{\"username\":\"%s\",\"password\":\"%s\"},\"method\":\"%s\"}"; | ||||
@@ -17,6 +17,7 @@ | |||||
package org.dubhe.utils; | package org.dubhe.utils; | ||||
import cn.hutool.core.util.StrUtil; | |||||
import com.emc.ecs.nfsclient.nfs.io.Nfs3File; | import com.emc.ecs.nfsclient.nfs.io.Nfs3File; | ||||
import com.emc.ecs.nfsclient.nfs.io.NfsFileInputStream; | import com.emc.ecs.nfsclient.nfs.io.NfsFileInputStream; | ||||
import com.emc.ecs.nfsclient.nfs.io.NfsFileOutputStream; | import com.emc.ecs.nfsclient.nfs.io.NfsFileOutputStream; | ||||
@@ -31,7 +32,6 @@ import org.dubhe.exception.NfsBizException; | |||||
import org.springframework.beans.factory.annotation.Autowired; | import org.springframework.beans.factory.annotation.Autowired; | ||||
import org.springframework.stereotype.Component; | import org.springframework.stereotype.Component; | ||||
import org.springframework.util.CollectionUtils; | import org.springframework.util.CollectionUtils; | ||||
import org.springframework.util.FileCopyUtils; | |||||
import java.io.*; | import java.io.*; | ||||
import java.util.ArrayList; | import java.util.ArrayList; | ||||
@@ -130,14 +130,14 @@ public class NfsUtil { | |||||
} | } | ||||
/** | /** | ||||
* 校验文件或文件夹是否存在 | |||||
* 校验文件或文件夹是否不存在 | |||||
* | * | ||||
* @param path 文件路径 | * @param path 文件路径 | ||||
* @return boolean | * @return boolean | ||||
*/ | */ | ||||
public boolean fileOrDirIsEmpty(String path) { | public boolean fileOrDirIsEmpty(String path) { | ||||
if (!StringUtils.isEmpty(path)) { | if (!StringUtils.isEmpty(path)) { | ||||
path = formatPath(path); | |||||
path = formatPath(path.startsWith(nfsConfig.getRootDir()) ? path.replaceFirst(nfsConfig.getRootDir(), StrUtil.SLASH) : path); | |||||
Nfs3File nfs3File = getNfs3File(path); | Nfs3File nfs3File = getNfs3File(path); | ||||
try { | try { | ||||
if (nfs3File.exists()) { | if (nfs3File.exists()) { | ||||
@@ -398,30 +398,6 @@ public class NfsUtil { | |||||
} | } | ||||
/** | |||||
* NFS 复制目录到指定目录下 多个文件 包含目录与文件并存情况 | |||||
* | |||||
* 通过本地文件复制方式 | |||||
* | |||||
* @param sourcePath 需要复制的文件目录 例如:/abc/def | |||||
* @param targetPath 需要放置的目标目录 例如:/abc/dd | |||||
* @return boolean | |||||
*/ | |||||
public boolean copyPath(String sourcePath, String targetPath) { | |||||
if (StringUtils.isEmpty(sourcePath) || StringUtils.isEmpty(targetPath)) { | |||||
return false; | |||||
} | |||||
sourcePath = formatPath(sourcePath); | |||||
targetPath = formatPath(targetPath); | |||||
try { | |||||
return copyLocalPath(nfsConfig.getRootDir() + sourcePath, nfsConfig.getRootDir() + targetPath); | |||||
} catch (Exception e) { | |||||
LogUtil.error(LogEnum.NFS_UTIL, " copyPath 复制失败: ", e); | |||||
return false; | |||||
} | |||||
} | |||||
/** | /** | ||||
* NFS 复制目录到指定目录下 多个文件 包含目录与文件并存情况 | * NFS 复制目录到指定目录下 多个文件 包含目录与文件并存情况 | ||||
* | * | ||||
@@ -468,126 +444,15 @@ public class NfsUtil { | |||||
} | } | ||||
} | } | ||||
/** | |||||
* 复制文件到指定目录下 单个文件 | |||||
* | |||||
* @param sourcePath 需要复制的文件 例如:/abc/def/cc.txt | |||||
* @param targetPath 需要放置的目标目录 例如:/abc/dd | |||||
* @return boolean | |||||
*/ | |||||
public boolean copyLocalFile(String sourcePath, String targetPath) { | |||||
LogUtil.info(LogEnum.NFS_UTIL, "复制文件原路径: {} ,目标路径: {}", sourcePath, targetPath); | |||||
if (StringUtils.isEmpty(sourcePath) || StringUtils.isEmpty(targetPath)) { | |||||
return false; | |||||
} | |||||
sourcePath = formatPath(sourcePath); | |||||
targetPath = formatPath(targetPath); | |||||
LogUtil.info(LogEnum.NFS_UTIL, "过滤后文件原路径: {} ,目标路径:{}", sourcePath, targetPath); | |||||
try (InputStream input = new FileInputStream(sourcePath); | |||||
FileOutputStream output = new FileOutputStream(targetPath)) { | |||||
FileCopyUtils.copy(input, output); | |||||
LogUtil.info(LogEnum.NFS_UTIL, "复制文件成功"); | |||||
return true; | |||||
} catch (IOException e) { | |||||
LogUtil.error(LogEnum.NFS_UTIL, " copyLocalFile 复制失败: ", e); | |||||
return false; | |||||
} | |||||
} | |||||
/** | |||||
* 复制文件 到指定目录下 多个文件 包含目录与文件并存情况 | |||||
* | |||||
* @param sourcePath 需要复制的文件目录 例如:/abc/def | |||||
* @param targetPath 需要放置的目标目录 例如:/abc/dd | |||||
* @return boolean | |||||
*/ | |||||
public boolean copyLocalPath(String sourcePath, String targetPath) { | |||||
if (!StringUtils.isEmpty(sourcePath) && !StringUtils.isEmpty(targetPath)) { | |||||
sourcePath = formatPath(sourcePath); | |||||
if (sourcePath.endsWith(FILE_SEPARATOR)) { | |||||
sourcePath = sourcePath.substring(MagicNumConstant.ZERO, sourcePath.lastIndexOf(FILE_SEPARATOR)); | |||||
} | |||||
targetPath = formatPath(targetPath); | |||||
LogUtil.info(LogEnum.NFS_UTIL, "复制文件夹 原路径: {} , 目标路径 : {} ", sourcePath, targetPath); | |||||
File[] files = new File(sourcePath).listFiles(); | |||||
LogUtil.info(LogEnum.NFS_UTIL, "需要复制的文件数量为: {}", files.length); | |||||
if (files.length != 0) { | |||||
for (File file : files) { | |||||
try { | |||||
if (file.isDirectory()) { | |||||
LogUtil.info(LogEnum.NFS_UTIL, "需要复制夹: {}", file.getAbsolutePath()); | |||||
LogUtil.info(LogEnum.NFS_UTIL, "目标文件夹: {}", targetPath + FILE_SEPARATOR + file.getName()); | |||||
File fileDir = new File(targetPath + FILE_SEPARATOR + file.getName()); | |||||
if(!fileDir.exists()){ | |||||
fileDir.mkdirs(); | |||||
} | |||||
copyLocalPath(sourcePath + FILE_SEPARATOR + file.getName(), targetPath + FILE_SEPARATOR + file.getName()); | |||||
} | |||||
if (file.isFile()) { | |||||
File fileTargetPath = new File(targetPath); | |||||
if(!fileTargetPath.exists()){ | |||||
fileTargetPath.mkdirs(); | |||||
} | |||||
LogUtil.info(LogEnum.NFS_UTIL, "需要复制文件: {}", file.getAbsolutePath()); | |||||
LogUtil.info(LogEnum.NFS_UTIL, "需要复制文件名称: {}", file.getName()); | |||||
copyLocalFile(file.getAbsolutePath() , targetPath + FILE_SEPARATOR + file.getName()); | |||||
} | |||||
}catch (Exception e){ | |||||
LogUtil.error(LogEnum.NFS_UTIL, "复制文件夹失败: {}", e); | |||||
return false; | |||||
} | |||||
} | |||||
} | |||||
return true; | |||||
} | |||||
return false; | |||||
} | |||||
/** | |||||
* 解压前清理同路径下其他文件(目前只支持路径下无文件夹,文件均为zip文件) | |||||
* 上传路径垃圾文件清理 | |||||
* | |||||
* @param zipFilePath zip源文件 例如:/abc/z.zip | |||||
* @param path 文件夹 例如:/abc/ | |||||
* @return boolean | |||||
*/ | |||||
public boolean cleanPath(String zipFilePath, String path) { | |||||
if (!StringUtils.isEmpty(zipFilePath) && !StringUtils.isEmpty(path) && zipFilePath.toLowerCase().endsWith(ZIP)) { | |||||
zipFilePath = formatPath(zipFilePath); | |||||
path = formatPath(path); | |||||
Nfs3File nfs3Files = getNfs3File(path); | |||||
try { | |||||
String zipName = zipFilePath.substring(zipFilePath.lastIndexOf(FILE_SEPARATOR) + MagicNumConstant.ONE); | |||||
if (!StringUtils.isEmpty(zipName)) { | |||||
List<Nfs3File> nfs3FilesList = nfs3Files.listFiles(); | |||||
if (!CollectionUtils.isEmpty(nfs3FilesList)) { | |||||
for (Nfs3File nfs3File : nfs3FilesList) { | |||||
if (!zipName.equals(nfs3File.getName())) { | |||||
nfs3File.delete(); | |||||
} | |||||
} | |||||
return true; | |||||
} | |||||
} | |||||
} catch (Exception e) { | |||||
LogUtil.error(LogEnum.NFS_UTIL, "路径{}清理失败,错误原因为:{} ", path, e); | |||||
return false; | |||||
} finally { | |||||
nfsPool.revertNfs(nfs3Files.getNfs()); | |||||
} | |||||
} | |||||
return false; | |||||
} | |||||
/** | /** | ||||
* zip解压并删除压缩文件 | * zip解压并删除压缩文件 | ||||
* | |||||
* 当压缩包文件较多时,可能会因为RPC超时而解压失败 | |||||
* 该方法已废弃,请使用org.dubhe.utils.LocalFileUtil类的unzipLocalPath方法来替代 | |||||
* @param sourcePath zip源文件 例如:/abc/z.zip | * @param sourcePath zip源文件 例如:/abc/z.zip | ||||
* @param targetPath 解压后的目标文件夹 例如:/abc/ | * @param targetPath 解压后的目标文件夹 例如:/abc/ | ||||
* @return boolean | * @return boolean | ||||
*/ | */ | ||||
@Deprecated | |||||
public boolean unzip(String sourcePath, String targetPath) { | public boolean unzip(String sourcePath, String targetPath) { | ||||
if (StringUtils.isEmpty(sourcePath) || StringUtils.isEmpty(targetPath)) { | if (StringUtils.isEmpty(sourcePath) || StringUtils.isEmpty(targetPath)) { | ||||
return false; | return false; | ||||
@@ -894,11 +759,15 @@ public class NfsUtil { | |||||
* @param path | * @param path | ||||
* @return String | * @return String | ||||
*/ | */ | ||||
private String formatPath(String path) { | |||||
public String formatPath(String path) { | |||||
if (!StringUtils.isEmpty(path)) { | if (!StringUtils.isEmpty(path)) { | ||||
return path.replaceAll("///*", FILE_SEPARATOR); | return path.replaceAll("///*", FILE_SEPARATOR); | ||||
} | } | ||||
return path; | return path; | ||||
} | } | ||||
public String getAbsolutePath(String relativePath) { | |||||
return nfsConfig.getRootDir() + nfsConfig.getBucket() + relativePath; | |||||
} | |||||
} | } |
@@ -26,6 +26,9 @@ import org.springframework.data.redis.core.Cursor; | |||||
import org.springframework.data.redis.core.RedisConnectionUtils; | import org.springframework.data.redis.core.RedisConnectionUtils; | ||||
import org.springframework.data.redis.core.RedisTemplate; | import org.springframework.data.redis.core.RedisTemplate; | ||||
import org.springframework.data.redis.core.ScanOptions; | import org.springframework.data.redis.core.ScanOptions; | ||||
import org.springframework.data.redis.core.script.DefaultRedisScript; | |||||
import org.springframework.data.redis.core.script.RedisScript; | |||||
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; | |||||
import org.springframework.stereotype.Component; | import org.springframework.stereotype.Component; | ||||
import org.springframework.util.CollectionUtils; | import org.springframework.util.CollectionUtils; | ||||
@@ -33,7 +36,7 @@ import java.util.*; | |||||
import java.util.concurrent.TimeUnit; | import java.util.concurrent.TimeUnit; | ||||
/** | /** | ||||
* @description redis工具类 | |||||
* @description redis工具类 | |||||
* @date 2020-03-13 | * @date 2020-03-13 | ||||
*/ | */ | ||||
@Component | @Component | ||||
@@ -62,7 +65,7 @@ public class RedisUtils { | |||||
redisTemplate.expire(key, time, TimeUnit.SECONDS); | redisTemplate.expire(key, time, TimeUnit.SECONDS); | ||||
} | } | ||||
} catch (Exception e) { | } catch (Exception e) { | ||||
LogUtil.error(LogEnum.SYS_ERR,"RedisUtils expire key {} time {} error:{}",key,time,e.getMessage(),e); | |||||
LogUtil.error(LogEnum.SYS_ERR, "RedisUtils expire key {} time {} error:{}", key, time, e.getMessage(), e); | |||||
return false; | return false; | ||||
} | } | ||||
return true; | return true; | ||||
@@ -82,7 +85,7 @@ public class RedisUtils { | |||||
* 查找匹配key | * 查找匹配key | ||||
* | * | ||||
* @param pattern key | * @param pattern key | ||||
* @return / | |||||
* @return List<String> 匹配的key集合 | |||||
*/ | */ | ||||
public List<String> scan(String pattern) { | public List<String> scan(String pattern) { | ||||
ScanOptions options = ScanOptions.scanOptions().match(pattern).build(); | ScanOptions options = ScanOptions.scanOptions().match(pattern).build(); | ||||
@@ -94,9 +97,9 @@ public class RedisUtils { | |||||
result.add(new String(cursor.next())); | result.add(new String(cursor.next())); | ||||
} | } | ||||
try { | try { | ||||
RedisConnectionUtils.releaseConnection(rc, factory,true); | |||||
RedisConnectionUtils.releaseConnection(rc, factory, true); | |||||
} catch (Exception e) { | } catch (Exception e) { | ||||
LogUtil.error(LogEnum.SYS_ERR,"RedisUtils scan pattern {} error:{}",pattern,e.getMessage(),e); | |||||
LogUtil.error(LogEnum.SYS_ERR, "RedisUtils scan pattern {} error:{}", pattern, e.getMessage(), e); | |||||
} | } | ||||
return result; | return result; | ||||
} | } | ||||
@@ -107,7 +110,7 @@ public class RedisUtils { | |||||
* @param patternKey key | * @param patternKey key | ||||
* @param page 页码 | * @param page 页码 | ||||
* @param size 每页数目 | * @param size 每页数目 | ||||
* @return / | |||||
* @return 匹配到的key集合 | |||||
*/ | */ | ||||
public List<String> findKeysForPage(String patternKey, int page, int size) { | public List<String> findKeysForPage(String patternKey, int page, int size) { | ||||
ScanOptions options = ScanOptions.scanOptions().match(patternKey).build(); | ScanOptions options = ScanOptions.scanOptions().match(patternKey).build(); | ||||
@@ -132,9 +135,9 @@ public class RedisUtils { | |||||
cursor.next(); | cursor.next(); | ||||
} | } | ||||
try { | try { | ||||
RedisConnectionUtils.releaseConnection(rc, factory,true); | |||||
RedisConnectionUtils.releaseConnection(rc, factory, true); | |||||
} catch (Exception e) { | } catch (Exception e) { | ||||
LogUtil.error(LogEnum.SYS_ERR,"RedisUtils findKeysForPage patternKey {} page {} size {} error:{}",patternKey,page,size,e.getMessage(),e); | |||||
LogUtil.error(LogEnum.SYS_ERR, "RedisUtils findKeysForPage patternKey {} page {} size {} error:{}", patternKey, page, size, e.getMessage(), e); | |||||
} | } | ||||
return result; | return result; | ||||
} | } | ||||
@@ -149,7 +152,7 @@ public class RedisUtils { | |||||
try { | try { | ||||
return redisTemplate.hasKey(key); | return redisTemplate.hasKey(key); | ||||
} catch (Exception e) { | } catch (Exception e) { | ||||
LogUtil.error(LogEnum.SYS_ERR,"RedisUtils hasKey key {} error:{}",key,e.getMessage(),e); | |||||
LogUtil.error(LogEnum.SYS_ERR, "RedisUtils hasKey key {} error:{}", key, e.getMessage(), e); | |||||
return false; | return false; | ||||
} | } | ||||
} | } | ||||
@@ -175,7 +178,7 @@ public class RedisUtils { | |||||
* 普通缓存获取 | * 普通缓存获取 | ||||
* | * | ||||
* @param key 键 | * @param key 键 | ||||
* @return 值 | |||||
* @return key对应的value值 | |||||
*/ | */ | ||||
public Object get(String key) { | public Object get(String key) { | ||||
@@ -185,8 +188,8 @@ public class RedisUtils { | |||||
/** | /** | ||||
* 批量获取 | * 批量获取 | ||||
* | * | ||||
* @param keys | |||||
* @return | |||||
* @param keys key集合 | |||||
* @return key集合对应的value集合 | |||||
*/ | */ | ||||
public List<Object> multiGet(List<String> keys) { | public List<Object> multiGet(List<String> keys) { | ||||
Object obj = redisTemplate.opsForValue().multiGet(Collections.singleton(keys)); | Object obj = redisTemplate.opsForValue().multiGet(Collections.singleton(keys)); | ||||
@@ -205,7 +208,7 @@ public class RedisUtils { | |||||
redisTemplate.opsForValue().set(key, value); | redisTemplate.opsForValue().set(key, value); | ||||
return true; | return true; | ||||
} catch (Exception e) { | } catch (Exception e) { | ||||
LogUtil.error(LogEnum.SYS_ERR,"RedisUtils set key {} value {} error:{}",key,value,e.getMessage(),e); | |||||
LogUtil.error(LogEnum.SYS_ERR, "RedisUtils set key {} value {} error:{}", key, value, e.getMessage(), e); | |||||
return false; | return false; | ||||
} | } | ||||
} | } | ||||
@@ -227,7 +230,7 @@ public class RedisUtils { | |||||
} | } | ||||
return true; | return true; | ||||
} catch (Exception e) { | } catch (Exception e) { | ||||
LogUtil.error(LogEnum.SYS_ERR,"RedisUtils set key {} value {} time {} error:{}",key,value,time,e.getMessage(),e); | |||||
LogUtil.error(LogEnum.SYS_ERR, "RedisUtils set key {} value {} time {} error:{}", key, value, time, e.getMessage(), e); | |||||
return false; | return false; | ||||
} | } | ||||
} | } | ||||
@@ -250,11 +253,56 @@ public class RedisUtils { | |||||
} | } | ||||
return true; | return true; | ||||
} catch (Exception e) { | } catch (Exception e) { | ||||
LogUtil.error(LogEnum.SYS_ERR,"RedisUtils set key {} value {} time {} timeUnit {} error:{}",key,value,time,timeUnit,e.getMessage(),e); | |||||
LogUtil.error(LogEnum.SYS_ERR, "RedisUtils set key {} value {} time {} timeUnit {} error:{}", key, value, time, timeUnit, e.getMessage(), e); | |||||
return false; | return false; | ||||
} | } | ||||
} | } | ||||
//===============================Lock================================= | |||||
/** | |||||
* 加锁 | |||||
* @param key 键 | |||||
* @param requestId 请求id用以释放锁 | |||||
* @param expireTime 超时时间(秒) | |||||
* @return | |||||
*/ | |||||
public boolean getDistributedLock(String key, String requestId, long expireTime) { | |||||
String script = "if redis.call('setNx',KEYS[1],ARGV[1]) == 1 then if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('expire',KEYS[1],ARGV[2]) else return 0 end else return 0 end"; | |||||
Object result = executeRedisScript(script, key, requestId, expireTime); | |||||
return result != null && result.equals(MagicNumConstant.ONE_LONG); | |||||
} | |||||
/** | |||||
* 释放锁 | |||||
* @param key 键 | |||||
* @param requestId 请求id用以释放锁 | |||||
* @return | |||||
*/ | |||||
public boolean releaseDistributedLock(String key, String requestId) { | |||||
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end"; | |||||
Object result = executeRedisScript(script, key, requestId); | |||||
return result != null && result.equals(MagicNumConstant.ONE_LONG); | |||||
} | |||||
/** | |||||
* | |||||
* @param script 脚本字符串 | |||||
* @param key 键 | |||||
* @param args 脚本其他参数 | |||||
* @return | |||||
*/ | |||||
public Object executeRedisScript(String script, String key, Object... args) { | |||||
try { | |||||
RedisScript<Long> redisScript = new DefaultRedisScript<>(script, Long.class); | |||||
redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<>(Object.class)); | |||||
return redisTemplate.execute(redisScript, Collections.singletonList(key), args); | |||||
} catch (Exception e) { | |||||
LogUtil.error(LogEnum.SYS_ERR, "executeRedisScript script {} key {} expireTime {} args {} error:{}", script, key, args, e); | |||||
return MagicNumConstant.ZERO_LONG; | |||||
} | |||||
} | |||||
// ================================Map================================= | // ================================Map================================= | ||||
/** | /** | ||||
@@ -291,7 +339,7 @@ public class RedisUtils { | |||||
redisTemplate.opsForHash().putAll(key, map); | redisTemplate.opsForHash().putAll(key, map); | ||||
return true; | return true; | ||||
} catch (Exception e) { | } catch (Exception e) { | ||||
LogUtil.error(LogEnum.SYS_ERR,"RedisUtils hmset key {} map {} error:{}",key,map,e.getMessage(),e); | |||||
LogUtil.error(LogEnum.SYS_ERR, "RedisUtils hmset key {} map {} error:{}", key, map, e.getMessage(), e); | |||||
return false; | return false; | ||||
} | } | ||||
} | } | ||||
@@ -312,7 +360,7 @@ public class RedisUtils { | |||||
} | } | ||||
return true; | return true; | ||||
} catch (Exception e) { | } catch (Exception e) { | ||||
LogUtil.error(LogEnum.SYS_ERR,"RedisUtils hmset key {} map {} time {} error:{}",key,map,time,e.getMessage(),e); | |||||
LogUtil.error(LogEnum.SYS_ERR, "RedisUtils hmset key {} map {} time {} error:{}", key, map, time, e.getMessage(), e); | |||||
return false; | return false; | ||||
} | } | ||||
} | } | ||||
@@ -330,7 +378,7 @@ public class RedisUtils { | |||||
redisTemplate.opsForHash().put(key, item, value); | redisTemplate.opsForHash().put(key, item, value); | ||||
return true; | return true; | ||||
} catch (Exception e) { | } catch (Exception e) { | ||||
LogUtil.error(LogEnum.SYS_ERR,"RedisUtils hset key {} item {} value {} error:{}",key,item,value,e.getMessage(),e); | |||||
LogUtil.error(LogEnum.SYS_ERR, "RedisUtils hset key {} item {} value {} error:{}", key, item, value, e.getMessage(), e); | |||||
return false; | return false; | ||||
} | } | ||||
} | } | ||||
@@ -352,7 +400,7 @@ public class RedisUtils { | |||||
} | } | ||||
return true; | return true; | ||||
} catch (Exception e) { | } catch (Exception e) { | ||||
LogUtil.error(LogEnum.SYS_ERR,"RedisUtils hset key {} item {} value {} time {} error:{}",key,item,value,time,e.getMessage(),e); | |||||
LogUtil.error(LogEnum.SYS_ERR, "RedisUtils hset key {} item {} value {} time {} error:{}", key, item, value, time, e.getMessage(), e); | |||||
return false; | return false; | ||||
} | } | ||||
} | } | ||||
@@ -414,7 +462,7 @@ public class RedisUtils { | |||||
try { | try { | ||||
return redisTemplate.opsForSet().members(key); | return redisTemplate.opsForSet().members(key); | ||||
} catch (Exception e) { | } catch (Exception e) { | ||||
LogUtil.error(LogEnum.SYS_ERR,"RedisUtils sGet key {} error:{}",key,e.getMessage(),e); | |||||
LogUtil.error(LogEnum.SYS_ERR, "RedisUtils sGet key {} error:{}", key, e.getMessage(), e); | |||||
return null; | return null; | ||||
} | } | ||||
} | } | ||||
@@ -430,7 +478,7 @@ public class RedisUtils { | |||||
try { | try { | ||||
return redisTemplate.opsForSet().isMember(key, value); | return redisTemplate.opsForSet().isMember(key, value); | ||||
} catch (Exception e) { | } catch (Exception e) { | ||||
LogUtil.error(LogEnum.SYS_ERR,"RedisUtils sHasKey key {} value {} error:{}",key,value,e.getMessage(),e); | |||||
LogUtil.error(LogEnum.SYS_ERR, "RedisUtils sHasKey key {} value {} error:{}", key, value, e.getMessage(), e); | |||||
return false; | return false; | ||||
} | } | ||||
} | } | ||||
@@ -446,7 +494,7 @@ public class RedisUtils { | |||||
try { | try { | ||||
return redisTemplate.opsForSet().add(key, values); | return redisTemplate.opsForSet().add(key, values); | ||||
} catch (Exception e) { | } catch (Exception e) { | ||||
LogUtil.error(LogEnum.SYS_ERR,"RedisUtils sSet key {} values {} error:{}",key,values,e.getMessage(),e); | |||||
LogUtil.error(LogEnum.SYS_ERR, "RedisUtils sSet key {} values {} error:{}", key, values, e.getMessage(), e); | |||||
return 0; | return 0; | ||||
} | } | ||||
} | } | ||||
@@ -467,7 +515,7 @@ public class RedisUtils { | |||||
} | } | ||||
return count; | return count; | ||||
} catch (Exception e) { | } catch (Exception e) { | ||||
LogUtil.error(LogEnum.SYS_ERR,"RedisUtils sSetAndTime key {} time {} values {} error:{}",key,time,values,e.getMessage(),e); | |||||
LogUtil.error(LogEnum.SYS_ERR, "RedisUtils sSetAndTime key {} time {} values {} error:{}", key, time, values, e.getMessage(), e); | |||||
return 0; | return 0; | ||||
} | } | ||||
} | } | ||||
@@ -482,7 +530,7 @@ public class RedisUtils { | |||||
try { | try { | ||||
return redisTemplate.opsForSet().size(key); | return redisTemplate.opsForSet().size(key); | ||||
} catch (Exception e) { | } catch (Exception e) { | ||||
LogUtil.error(LogEnum.SYS_ERR,"RedisUtils sGetSetSize key {} error:{}",key,e.getMessage(),e); | |||||
LogUtil.error(LogEnum.SYS_ERR, "RedisUtils sGetSetSize key {} error:{}", key, e.getMessage(), e); | |||||
return 0; | return 0; | ||||
} | } | ||||
} | } | ||||
@@ -499,7 +547,7 @@ public class RedisUtils { | |||||
Long count = redisTemplate.opsForSet().remove(key, values); | Long count = redisTemplate.opsForSet().remove(key, values); | ||||
return count; | return count; | ||||
} catch (Exception e) { | } catch (Exception e) { | ||||
LogUtil.error(LogEnum.SYS_ERR,"RedisUtils setRemove key {} values {} error:{}",key,values,e.getMessage(),e); | |||||
LogUtil.error(LogEnum.SYS_ERR, "RedisUtils setRemove key {} values {} error:{}", key, values, e.getMessage(), e); | |||||
return 0; | return 0; | ||||
} | } | ||||
} | } | ||||
@@ -507,22 +555,22 @@ public class RedisUtils { | |||||
// ===============================sorted set================================= | // ===============================sorted set================================= | ||||
/** | /** | ||||
*将zSet数据放入缓存 | |||||
* 将zSet数据放入缓存 | |||||
* | * | ||||
* @param key | * @param key | ||||
* @param time | * @param time | ||||
* @param values | * @param values | ||||
* @return Boolean | * @return Boolean | ||||
*/ | */ | ||||
public Boolean zSet(String key, long time, Object value){ | |||||
public Boolean zSet(String key, long time, Object value) { | |||||
try { | try { | ||||
Boolean success = redisTemplate.opsForZSet().add(key, value,System.currentTimeMillis()); | |||||
Boolean success = redisTemplate.opsForZSet().add(key, value, System.currentTimeMillis()); | |||||
if (success) { | if (success) { | ||||
expire(key, time); | expire(key, time); | ||||
} | } | ||||
return success; | return success; | ||||
} catch (Exception e) { | } catch (Exception e) { | ||||
LogUtil.error(LogEnum.SYS_ERR,"RedisUtils zSet key {} time {} value {} error:{}",key,time,value,e.getMessage(),e); | |||||
LogUtil.error(LogEnum.SYS_ERR, "RedisUtils zSet key {} time {} value {} error:{}", key, time, value, e.getMessage(), e); | |||||
return false; | return false; | ||||
} | } | ||||
} | } | ||||
@@ -533,17 +581,16 @@ public class RedisUtils { | |||||
* @param key | * @param key | ||||
* @return Set<Object> | * @return Set<Object> | ||||
*/ | */ | ||||
public Set<Object> zGet(String key){ | |||||
public Set<Object> zGet(String key) { | |||||
try { | try { | ||||
return redisTemplate.opsForZSet().reverseRange(key,Long.MIN_VALUE, Long.MAX_VALUE); | |||||
return redisTemplate.opsForZSet().reverseRange(key, Long.MIN_VALUE, Long.MAX_VALUE); | |||||
} catch (Exception e) { | } catch (Exception e) { | ||||
LogUtil.error(LogEnum.SYS_ERR,"RedisUtils zGet key {} error:{}",key,e.getMessage(),e); | |||||
LogUtil.error(LogEnum.SYS_ERR, "RedisUtils zGet key {} error:{}", key, e.getMessage(), e); | |||||
return null; | return null; | ||||
} | } | ||||
} | } | ||||
// ===============================list================================= | // ===============================list================================= | ||||
/** | /** | ||||
@@ -558,7 +605,7 @@ public class RedisUtils { | |||||
try { | try { | ||||
return redisTemplate.opsForList().range(key, start, end); | return redisTemplate.opsForList().range(key, start, end); | ||||
} catch (Exception e) { | } catch (Exception e) { | ||||
LogUtil.error(LogEnum.SYS_ERR,"RedisUtils lGetIndex key {} start {} end {} error:{}",key,start,end,e.getMessage(),e); | |||||
LogUtil.error(LogEnum.SYS_ERR, "RedisUtils lGetIndex key {} start {} end {} error:{}", key, start, end, e.getMessage(), e); | |||||
return null; | return null; | ||||
} | } | ||||
} | } | ||||
@@ -573,7 +620,7 @@ public class RedisUtils { | |||||
try { | try { | ||||
return redisTemplate.opsForList().size(key); | return redisTemplate.opsForList().size(key); | ||||
} catch (Exception e) { | } catch (Exception e) { | ||||
LogUtil.error(LogEnum.SYS_ERR,"RedisUtils lGetListSize key {} error:{}",key,e.getMessage(),e); | |||||
LogUtil.error(LogEnum.SYS_ERR, "RedisUtils lGetListSize key {} error:{}", key, e.getMessage(), e); | |||||
return 0; | return 0; | ||||
} | } | ||||
} | } | ||||
@@ -589,7 +636,7 @@ public class RedisUtils { | |||||
try { | try { | ||||
return redisTemplate.opsForList().index(key, index); | return redisTemplate.opsForList().index(key, index); | ||||
} catch (Exception e) { | } catch (Exception e) { | ||||
LogUtil.error(LogEnum.SYS_ERR,"RedisUtils lGetIndex key {} index {} error:{}",key,index,e.getMessage(),e); | |||||
LogUtil.error(LogEnum.SYS_ERR, "RedisUtils lGetIndex key {} index {} error:{}", key, index, e.getMessage(), e); | |||||
return null; | return null; | ||||
} | } | ||||
} | } | ||||
@@ -606,7 +653,7 @@ public class RedisUtils { | |||||
redisTemplate.opsForList().rightPush(key, value); | redisTemplate.opsForList().rightPush(key, value); | ||||
return true; | return true; | ||||
} catch (Exception e) { | } catch (Exception e) { | ||||
LogUtil.error(LogEnum.SYS_ERR,"RedisUtils lSet key {} value {} error:{}",key,value,e.getMessage(),e); | |||||
LogUtil.error(LogEnum.SYS_ERR, "RedisUtils lSet key {} value {} error:{}", key, value, e.getMessage(), e); | |||||
return false; | return false; | ||||
} | } | ||||
} | } | ||||
@@ -617,7 +664,7 @@ public class RedisUtils { | |||||
* @param key 键 | * @param key 键 | ||||
* @param value 值 | * @param value 值 | ||||
* @param time 时间(秒) | * @param time 时间(秒) | ||||
* @return | |||||
* @return 是否存储成功 | |||||
*/ | */ | ||||
public boolean lSet(String key, Object value, long time) { | public boolean lSet(String key, Object value, long time) { | ||||
try { | try { | ||||
@@ -627,7 +674,7 @@ public class RedisUtils { | |||||
} | } | ||||
return true; | return true; | ||||
} catch (Exception e) { | } catch (Exception e) { | ||||
LogUtil.error(LogEnum.SYS_ERR,"RedisUtils lSet key {} value {} time {} error:{}",key,value,time,e.getMessage(),e); | |||||
LogUtil.error(LogEnum.SYS_ERR, "RedisUtils lSet key {} value {} time {} error:{}", key, value, time, e.getMessage(), e); | |||||
return false; | return false; | ||||
} | } | ||||
} | } | ||||
@@ -637,14 +684,14 @@ public class RedisUtils { | |||||
* | * | ||||
* @param key 键 | * @param key 键 | ||||
* @param value 值 | * @param value 值 | ||||
* @return | |||||
* @return 是否存储成功 | |||||
*/ | */ | ||||
public boolean lSet(String key, List<Object> value) { | public boolean lSet(String key, List<Object> value) { | ||||
try { | try { | ||||
redisTemplate.opsForList().rightPushAll(key, value); | redisTemplate.opsForList().rightPushAll(key, value); | ||||
return true; | return true; | ||||
} catch (Exception e) { | } catch (Exception e) { | ||||
LogUtil.error(LogEnum.SYS_ERR,"RedisUtils lSet key {} value {} error:{}",key,value,e.getMessage(),e); | |||||
LogUtil.error(LogEnum.SYS_ERR, "RedisUtils lSet key {} value {} error:{}", key, value, e.getMessage(), e); | |||||
return false; | return false; | ||||
} | } | ||||
} | } | ||||
@@ -655,7 +702,7 @@ public class RedisUtils { | |||||
* @param key 键 | * @param key 键 | ||||
* @param value 值 | * @param value 值 | ||||
* @param time 时间(秒) | * @param time 时间(秒) | ||||
* @return | |||||
* @return 是否存储成功 | |||||
*/ | */ | ||||
public boolean lSet(String key, List<Object> value, long time) { | public boolean lSet(String key, List<Object> value, long time) { | ||||
try { | try { | ||||
@@ -665,7 +712,7 @@ public class RedisUtils { | |||||
} | } | ||||
return true; | return true; | ||||
} catch (Exception e) { | } catch (Exception e) { | ||||
LogUtil.error(LogEnum.SYS_ERR,"RedisUtils lSet key {} value {} time {} error:{}",key,value,time,e.getMessage(),e); | |||||
LogUtil.error(LogEnum.SYS_ERR, "RedisUtils lSet key {} value {} time {} error:{}", key, value, time, e.getMessage(), e); | |||||
return false; | return false; | ||||
} | } | ||||
} | } | ||||
@@ -676,14 +723,14 @@ public class RedisUtils { | |||||
* @param key 键 | * @param key 键 | ||||
* @param index 索引 | * @param index 索引 | ||||
* @param value 值 | * @param value 值 | ||||
* @return / | |||||
* @return 更新数据标识 | |||||
*/ | */ | ||||
public boolean lUpdateIndex(String key, long index, Object value) { | public boolean lUpdateIndex(String key, long index, Object value) { | ||||
try { | try { | ||||
redisTemplate.opsForList().set(key, index, value); | redisTemplate.opsForList().set(key, index, value); | ||||
return true; | return true; | ||||
} catch (Exception e) { | } catch (Exception e) { | ||||
LogUtil.error(LogEnum.SYS_ERR,"RedisUtils lUpdateIndex key {} index {} value {} error:{}",key,index,value,e.getMessage(),e); | |||||
LogUtil.error(LogEnum.SYS_ERR, "RedisUtils lUpdateIndex key {} index {} value {} error:{}", key, index, value, e.getMessage(), e); | |||||
return false; | return false; | ||||
} | } | ||||
} | } | ||||
@@ -700,8 +747,23 @@ public class RedisUtils { | |||||
try { | try { | ||||
return redisTemplate.opsForList().remove(key, count, value); | return redisTemplate.opsForList().remove(key, count, value); | ||||
} catch (Exception e) { | } catch (Exception e) { | ||||
LogUtil.error(LogEnum.SYS_ERR,"RedisUtils lRemove key {} count {} value {} error:{}",key,count,value,e.getMessage(),e); | |||||
LogUtil.error(LogEnum.SYS_ERR, "RedisUtils lRemove key {} count {} value {} error:{}", key, count, value, e.getMessage(), e); | |||||
return 0; | return 0; | ||||
} | } | ||||
} | } | ||||
/** | |||||
* 队列从左弹出数据 | |||||
* | |||||
* @param key | |||||
* @return key对应的value值 | |||||
*/ | |||||
public Object lpop(String key) { | |||||
try { | |||||
return redisTemplate.opsForList().leftPop(key); | |||||
} catch (Exception e) { | |||||
LogUtil.error(LogEnum.SYS_ERR, "RedisUtils lRemove key {} error:{}", key, e.getMessage(), e); | |||||
return null; | |||||
} | |||||
} | |||||
} | } |
@@ -18,7 +18,8 @@ | |||||
package org.dubhe.utils; | package org.dubhe.utils; | ||||
import java.lang.reflect.Field; | import java.lang.reflect.Field; | ||||
import java.util.*; | |||||
import java.util.ArrayList; | |||||
import java.util.List; | |||||
/** | /** | ||||
* @description 反射工具类 | * @description 反射工具类 | ||||
@@ -23,8 +23,8 @@ import java.util.regex.Matcher; | |||||
import java.util.regex.Pattern; | import java.util.regex.Pattern; | ||||
/** | /** | ||||
* @description: 正则匹配工具类 | |||||
* @create: 2020/4/23 13:51 | |||||
* @description 正则匹配工具类 | |||||
* @date 2020-04-23 | |||||
*/ | */ | ||||
@Slf4j | @Slf4j | ||||
public class RegexUtil { | public class RegexUtil { | ||||
@@ -17,11 +17,18 @@ | |||||
package org.dubhe.utils; | package org.dubhe.utils; | ||||
import org.dubhe.base.BaseService; | |||||
import org.dubhe.base.DataContext; | |||||
import java.util.HashSet; | |||||
import java.util.Objects; | |||||
import java.util.Set; | |||||
/** | /** | ||||
* @description sql语句转换的工具类 | * @description sql语句转换的工具类 | ||||
* @date 2020-07-06 | * @date 2020-07-06 | ||||
*/ | */ | ||||
public class SqlUtil { | public class SqlUtil { | ||||
/** | /** | ||||
@@ -46,4 +53,46 @@ public class SqlUtil { | |||||
return ""; | return ""; | ||||
} | } | ||||
/** | |||||
* 获取资源拥有着ID | |||||
* | |||||
* @return 资源拥有者id集合 | |||||
*/ | |||||
public static Set<Long> getResourceIds() { | |||||
if (!Objects.isNull(DataContext.get())) { | |||||
return DataContext.get().getResourceUserIds(); | |||||
} | |||||
Set<Long> ids = new HashSet<>(); | |||||
Long id = JwtUtils.getCurrentUserDto().getId(); | |||||
ids.add(id); | |||||
return ids; | |||||
} | |||||
/** | |||||
* 构建目标sql语句 | |||||
* | |||||
* @param originSql 原生sql | |||||
* @param resourceUserIds 所属资源用户ids | |||||
* @return 目标sql | |||||
*/ | |||||
public static String buildTargetSql(String originSql, Set<Long> resourceUserIds) { | |||||
if (BaseService.isAdmin()) { | |||||
return originSql; | |||||
} | |||||
String sqlWhereBefore = org.dubhe.utils.StringUtils.substringBefore(originSql.toLowerCase(), "where"); | |||||
String sqlWhereAfter = org.dubhe.utils.StringUtils.substringAfter(originSql.toLowerCase(), "where"); | |||||
StringBuffer buffer = new StringBuffer(); | |||||
//操作的sql拼接 | |||||
String targetSql = buffer.append(sqlWhereBefore).append(" where ").append(" origin_user_id in (") | |||||
.append(org.dubhe.utils.StringUtils.join(resourceUserIds, ",")).append(") and ").append(sqlWhereAfter).toString(); | |||||
return targetSql; | |||||
} | |||||
} | } |
@@ -273,4 +273,41 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils { | |||||
matcher.appendTail(sb); | matcher.appendTail(sb); | ||||
return sb.toString(); | return sb.toString(); | ||||
} | } | ||||
/** | |||||
* 字符串截取前 | |||||
* @param str | |||||
* @return | |||||
*/ | |||||
public static String substringBefore(String str, String separator){ | |||||
if (!isEmpty(str) && separator != null) { | |||||
if (separator.isEmpty()) { | |||||
return ""; | |||||
} else { | |||||
int pos = str.indexOf(separator); | |||||
return pos == -1 ? str : str.substring(0, pos); | |||||
} | |||||
} else { | |||||
return str; | |||||
} | |||||
} | |||||
/** | |||||
* 字符串截取后 | |||||
* @param str | |||||
* @return | |||||
*/ | |||||
public static String substringAfter(String str, String separator){ | |||||
if (isEmpty(str)) { | |||||
return str; | |||||
} else if (separator == null) { | |||||
return ""; | |||||
} else { | |||||
int pos = str.indexOf(separator); | |||||
return pos == -1 ? "" : str.substring(pos + separator.length()); | |||||
} | |||||
} | |||||
} | } |
@@ -17,42 +17,33 @@ | |||||
package org.dubhe.utils; | package org.dubhe.utils; | ||||
import lombok.extern.slf4j.Slf4j; | |||||
import java.text.ParseException; | |||||
import java.text.SimpleDateFormat; | import java.text.SimpleDateFormat; | ||||
import java.util.Calendar; | import java.util.Calendar; | ||||
import java.util.Date; | import java.util.Date; | ||||
import static org.dubhe.base.MagicNumConstant.EIGHT; | |||||
/** | /** | ||||
* @description: UTC时间转换CST时间工具类 | |||||
* @create: 2020/5/20 12:10 | |||||
* @description 时间格式转换工具类 | |||||
* @date 2020-05-20 | |||||
*/ | */ | ||||
@Slf4j | |||||
public class TimeTransferUtil { | public class TimeTransferUtil { | ||||
private static final String UTC_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.sss'Z'"; | |||||
/** | /** | ||||
* @param utcTime | |||||
* @return cstTime | |||||
* Date转换为UTC时间 | |||||
* | |||||
* @param date | |||||
* @return utcTime | |||||
*/ | */ | ||||
public static String cstTransfer(String utcTime){ | |||||
Date utcDate = null; | |||||
/**2020-05-20T03:13:22Z 对应的时间格式 yyyy-MM-dd'T'HH:mm:ss'Z'**/ | |||||
SimpleDateFormat utcSimpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); | |||||
try { | |||||
utcDate = utcSimpleDateFormat.parse(utcTime); | |||||
} catch (ParseException e) { | |||||
log.info(e.getMessage()); | |||||
return null; | |||||
} | |||||
/**System.out.println("UTC时间:"+date);**/ | |||||
public static String dateTransferToUtc(Date date){ | |||||
Calendar calendar = Calendar.getInstance(); | Calendar calendar = Calendar.getInstance(); | ||||
calendar.setTime(utcDate); | |||||
calendar.set(Calendar.HOUR,calendar.get(Calendar.HOUR)+8); | |||||
SimpleDateFormat cstSimpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); | |||||
Date cstDate = calendar.getTime(); | |||||
String cstTime = cstSimpleDateFormat.format(calendar.getTime()); | |||||
return cstTime; | |||||
calendar.setTime(date); | |||||
/**UTC时间与CST时间相差8小时**/ | |||||
calendar.set(Calendar.HOUR,calendar.get(Calendar.HOUR) - EIGHT); | |||||
SimpleDateFormat utcSimpleDateFormat = new SimpleDateFormat(UTC_FORMAT); | |||||
Date utcDate = calendar.getTime(); | |||||
return utcSimpleDateFormat.format(utcDate); | |||||
} | } | ||||
} | } |
@@ -25,9 +25,8 @@ import java.util.concurrent.ConcurrentHashMap; | |||||
import java.util.concurrent.atomic.AtomicInteger; | import java.util.concurrent.atomic.AtomicInteger; | ||||
/** | /** | ||||
* @description: 唯一码生成器 (依赖时间轴) | |||||
* | |||||
* @date 2020.05.08 | |||||
* @description 唯一码生成器 (依赖时间轴) | |||||
* @date 2020-05-08 | |||||
*/ | */ | ||||
public class UniqueKeyGenerator { | public class UniqueKeyGenerator { | ||||
@@ -20,7 +20,6 @@ package org.dubhe.utils; | |||||
import cn.hutool.core.util.ObjectUtil; | import cn.hutool.core.util.ObjectUtil; | ||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; | ||||
import lombok.extern.slf4j.Slf4j; | import lombok.extern.slf4j.Slf4j; | ||||
import lombok.val; | |||||
import org.dubhe.annotation.Query; | import org.dubhe.annotation.Query; | ||||
import java.lang.reflect.Field; | import java.lang.reflect.Field; | ||||
@@ -31,7 +30,7 @@ import java.util.List; | |||||
/** | /** | ||||
* @description 构建Wrapper | * @description 构建Wrapper | ||||
* @date 2020-03-15 13:52:30 | |||||
* @date 2020-03-15 | |||||
*/ | */ | ||||
@Slf4j | @Slf4j | ||||
public class WrapperHelp { | public class WrapperHelp { | ||||
@@ -23,8 +23,8 @@ import org.junit.Test; | |||||
import static org.dubhe.utils.HttpUtils.isSuccess; | import static org.dubhe.utils.HttpUtils.isSuccess; | ||||
/** | /** | ||||
* @description: HttpUtil | |||||
* @date 2020.04.30 | |||||
* @description HttpUtil | |||||
* @date 2020-04-30 | |||||
*/ | */ | ||||
public class HttpUtilsTest { | public class HttpUtilsTest { | ||||
@@ -0,0 +1,71 @@ | |||||
#!/bin/bash | |||||
PROG_NAME=$0 | |||||
ACTION=$1 | |||||
ENV=$2 | |||||
APP_HOME=$3 | |||||
APP_NAME=dubhe-${ENV} | |||||
APP_HOME=$APP_HOME/${APP_NAME} # 从package.tgz中解压出来的jar包放到这个目录下 | |||||
JAR_NAME=${APP_HOME}/dubhe-admin/target/dubhe-admin-1.0-exec.jar # jar包的名字 | |||||
JAVA_OUT=/dev/null | |||||
# 创建出相关目录 | |||||
mkdir -p ${APP_HOME} | |||||
mkdir -p ${APP_HOME}/logs | |||||
usage() { | |||||
echo "Usage: $PROG_NAME {start|stop|restart} {dev|test|prod}" | |||||
exit 2 | |||||
} | |||||
start_application() { | |||||
echo "starting java process" | |||||
echo "nohup java -jar ${JAR_NAME} > ${JAVA_OUT} --spring.profiles.active=${ENV} 2>&1 &" | |||||
nohup java -jar ${JAR_NAME} > ${JAVA_OUT} --spring.profiles.active=${ENV} 2>&1 & | |||||
echo "started java process" | |||||
} | |||||
stop_application() { | |||||
checkjavapid=`ps -ef | grep java | grep ${APP_NAME} | grep -v grep |grep -v 'deploy.sh'| awk '{print$2}'` | |||||
if [ -z $checkjavapid ];then | |||||
echo -e "\rno java process "$checkjavapid | |||||
return | |||||
fi | |||||
echo "stop java process" | |||||
times=60 | |||||
for e in $(seq 60) | |||||
do | |||||
sleep 1 | |||||
COSTTIME=$(($times - $e )) | |||||
checkjavapid=`ps -ef | grep java | grep ${APP_NAME} | grep -v grep |grep -v 'deploy.sh'| awk '{print$2}'` | |||||
if [ "$checkjavapid" != "" ];then | |||||
echo "kill "$checkjavapid | |||||
kill -9 $checkjavapid | |||||
echo -e "\r -- stopping java lasts `expr $COSTTIME` seconds." | |||||
else | |||||
echo -e "\rjava process has exited" | |||||
break; | |||||
fi | |||||
done | |||||
echo "" | |||||
} | |||||
case "$ACTION" in | |||||
start) | |||||
start_application | |||||
;; | |||||
stop) | |||||
stop_application | |||||
;; | |||||
restart) | |||||
stop_application | |||||
start_application | |||||
;; | |||||
*) | |||||
usage | |||||
;; | |||||
esac |
@@ -75,6 +75,7 @@ | |||||
<configuration> | <configuration> | ||||
<skip>false</skip> | <skip>false</skip> | ||||
<fork>true</fork> | <fork>true</fork> | ||||
<classifier>exec</classifier> | |||||
</configuration> | </configuration> | ||||
</plugin> | </plugin> | ||||
<!-- 跳过单元测试 --> | <!-- 跳过单元测试 --> | ||||
@@ -14,7 +14,7 @@ | |||||
* limitations under the License. | * limitations under the License. | ||||
* ============================================================= | * ============================================================= | ||||
*/ | */ | ||||
package org.dubhe.task; | |||||
package org.dubhe.async; | |||||
import cn.hutool.core.util.StrUtil; | import cn.hutool.core.util.StrUtil; | ||||
import org.dubhe.base.ResponseCode; | import org.dubhe.base.ResponseCode; | ||||
@@ -25,6 +25,7 @@ import org.dubhe.enums.ImageStateEnum; | |||||
import org.dubhe.enums.LogEnum; | import org.dubhe.enums.LogEnum; | ||||
import org.dubhe.exception.BusinessException; | import org.dubhe.exception.BusinessException; | ||||
import org.dubhe.harbor.api.HarborApi; | import org.dubhe.harbor.api.HarborApi; | ||||
import org.dubhe.utils.IOUtil; | |||||
import org.dubhe.utils.LogUtil; | import org.dubhe.utils.LogUtil; | ||||
import org.dubhe.utils.StringUtils; | import org.dubhe.utils.StringUtils; | ||||
import org.springframework.beans.factory.annotation.Autowired; | import org.springframework.beans.factory.annotation.Autowired; | ||||
@@ -62,46 +63,21 @@ public class HarborImagePushAsync { | |||||
String imageResource = trainHarborConfig.getAddress() + StrUtil.SLASH + trainHarborConfig.getModelName() | String imageResource = trainHarborConfig.getAddress() + StrUtil.SLASH + trainHarborConfig.getModelName() | ||||
+ StrUtil.SLASH + imageNameandTag; | + StrUtil.SLASH + imageNameandTag; | ||||
String cmdStr = "docker login --username=" + trainHarborConfig.getUsername() + " " + trainHarborConfig.getAddress() + " --password=" + trainHarborConfig.getPassword() + " ; docker " + | String cmdStr = "docker login --username=" + trainHarborConfig.getUsername() + " " + trainHarborConfig.getAddress() + " --password=" + trainHarborConfig.getPassword() + " ; docker " + | ||||
"load < " + imagePath + " |awk '{print $3}' |xargs -I str docker tag str " + imageResource + " ; docker push " + imageResource; | |||||
"load < " + imagePath + " |awk '{print $3}' |xargs -I str docker tag str " + imageResource + " ; docker push " + imageResource + "; docker rmi " + imageResource; | |||||
String[] cmd = {"/bin/bash", "-c", cmdStr}; | String[] cmd = {"/bin/bash", "-c", cmdStr}; | ||||
LogUtil.info(LogEnum.BIZ_TRAIN, "镜像上传执行脚本参数:{}", cmd); | LogUtil.info(LogEnum.BIZ_TRAIN, "镜像上传执行脚本参数:{}", cmd); | ||||
Process process = Runtime.getRuntime().exec(cmd); | Process process = Runtime.getRuntime().exec(cmd); | ||||
//读取标准输出流 | |||||
BufferedReader brOut = new BufferedReader(new InputStreamReader(process.getInputStream())); | |||||
//读取标准错误流 | |||||
BufferedReader brErr = new BufferedReader(new InputStreamReader(process.getErrorStream())); | |||||
String line; | |||||
String outMessage = ""; | |||||
String errMessage = ""; | |||||
while ((line = brOut.readLine()) != null) { | |||||
outMessage += line; | |||||
} | |||||
if (StringUtils.isNotEmpty(outMessage)) { | |||||
LogUtil.info(LogEnum.BIZ_TRAIN, "shell上传镜像输出信息:" + outMessage); | |||||
} | |||||
while ((line = brErr.readLine()) != null) { | |||||
errMessage += line; | |||||
} | |||||
if (StringUtils.isNotEmpty(errMessage)) { | |||||
LogUtil.error(LogEnum.BIZ_TRAIN, "shell上传镜像异常信息:" + errMessage); | |||||
} | |||||
Integer status = process.waitFor(); | |||||
LogUtil.info(LogEnum.BIZ_TRAIN, "上传镜像状态:{}", status); | |||||
if (status == null) { | |||||
if (harborApi.isExistImage(ptImage.getImageUrl())) { | |||||
updateImageStatus(ptImage, ImageStateEnum.SUCCESS.getCode()); | |||||
} else { | |||||
updateImageStatus(ptImage, ImageStateEnum.FAIL.getCode()); | |||||
} | |||||
} else if (status == 0) { | |||||
if (checkImagePushIsOk(ptImage, process)) { | |||||
updateImageStatus(ptImage, ImageStateEnum.SUCCESS.getCode()); | updateImageStatus(ptImage, ImageStateEnum.SUCCESS.getCode()); | ||||
} else { | } else { | ||||
updateImageStatus(ptImage, ImageStateEnum.FAIL.getCode()); | updateImageStatus(ptImage, ImageStateEnum.FAIL.getCode()); | ||||
} | } | ||||
} catch (Exception e) { | } catch (Exception e) { | ||||
LogUtil.error(LogEnum.BIZ_TRAIN, "上传镜像异常:{}", e); | LogUtil.error(LogEnum.BIZ_TRAIN, "上传镜像异常:{}", e); | ||||
updateImageStatus(ptImage, ImageStateEnum.FAIL.getCode()); | |||||
throw new BusinessException("上传镜像异常!"); | throw new BusinessException("上传镜像异常!"); | ||||
} | } | ||||
} | } | ||||
@@ -117,4 +93,52 @@ public class HarborImagePushAsync { | |||||
ptImageMapper.updateById(ptImage); | ptImageMapper.updateById(ptImage); | ||||
return ResponseCode.SUCCESS; | return ResponseCode.SUCCESS; | ||||
} | } | ||||
/** | |||||
* 校验镜像是否上传成功 | |||||
* | |||||
* @param ptImage 镜像信息 | |||||
* @param process process对象 | |||||
* @return 是否上传成功 | |||||
*/ | |||||
public boolean checkImagePushIsOk(PtImage ptImage, Process process) { | |||||
//读取标准输出流 | |||||
BufferedReader brOut = new BufferedReader(new InputStreamReader(process.getInputStream())); | |||||
//读取标准错误流 | |||||
BufferedReader brErr = new BufferedReader(new InputStreamReader(process.getErrorStream())); | |||||
String line; | |||||
StringBuilder outMessage = new StringBuilder(); | |||||
StringBuilder errMessage = new StringBuilder(); | |||||
boolean isPushOk = true; | |||||
try { | |||||
while ((line = brOut.readLine()) != null) { | |||||
outMessage.append(line); | |||||
} | |||||
if (StringUtils.isNotEmpty(outMessage)) { | |||||
LogUtil.info(LogEnum.BIZ_TRAIN, "shell上传镜像输出信息:{}", outMessage.toString()); | |||||
} | |||||
while ((line = brErr.readLine()) != null) { | |||||
errMessage.append(line); | |||||
} | |||||
if (StringUtils.isNotEmpty(errMessage)) { | |||||
LogUtil.error(LogEnum.BIZ_TRAIN, "shell上传镜像异常信息:{}", errMessage.toString()); | |||||
} | |||||
Integer status = process.waitFor(); | |||||
LogUtil.info(LogEnum.BIZ_TRAIN, "上传镜像状态:{}", status); | |||||
if (status == null) { | |||||
if (!harborApi.isExistImage(ptImage.getImageUrl())) { | |||||
isPushOk = false; | |||||
} | |||||
} else if (status != 0) { | |||||
isPushOk = false; | |||||
} | |||||
} catch (Exception e) { | |||||
LogUtil.error(LogEnum.BIZ_TRAIN, "上传镜像异常:{}", e); | |||||
return false; | |||||
} finally { | |||||
IOUtil.close(brErr, brOut); | |||||
} | |||||
return isPushOk; | |||||
} | |||||
} | } |
@@ -0,0 +1,144 @@ | |||||
/** | |||||
* Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||||
* | |||||
* 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.dubhe.async; | |||||
import org.dubhe.config.TrainJobConfig; | |||||
import org.dubhe.dao.PtTrainJobMapper; | |||||
import org.dubhe.domain.dto.UserDTO; | |||||
import org.dubhe.domain.entity.PtTrainJob; | |||||
import org.dubhe.enums.LogEnum; | |||||
import org.dubhe.enums.TrainJobStatusEnum; | |||||
import org.dubhe.enums.TrainTypeEnum; | |||||
import org.dubhe.k8s.api.DistributeTrainApi; | |||||
import org.dubhe.k8s.api.PodApi; | |||||
import org.dubhe.k8s.api.TrainJobApi; | |||||
import org.dubhe.k8s.domain.resource.BizPod; | |||||
import org.dubhe.utils.*; | |||||
import org.springframework.beans.factory.annotation.Autowired; | |||||
import org.springframework.scheduling.annotation.Async; | |||||
import org.springframework.stereotype.Component; | |||||
import java.time.LocalDateTime; | |||||
import java.time.ZoneOffset; | |||||
import java.time.format.DateTimeFormatter; | |||||
import java.util.List; | |||||
import java.util.function.Consumer; | |||||
/** | |||||
* @description 停止训练任务异步处理 | |||||
* @date 2020-08-13 | |||||
*/ | |||||
@Component | |||||
public class StopTrainJobAsync { | |||||
@Autowired | |||||
private K8sNameTool k8sNameTool; | |||||
@Autowired | |||||
private PodApi podApi; | |||||
@Autowired | |||||
private TrainJobApi trainJobApi; | |||||
@Autowired | |||||
private TrainJobConfig trainJobConfig; | |||||
@Autowired | |||||
private DistributeTrainApi distributeTrainApi; | |||||
@Autowired | |||||
private PtTrainJobMapper ptTrainJobMapper; | |||||
/** | |||||
* 停止任务 | |||||
* | |||||
* @param currentUser 用户 | |||||
* @param jobList 任务集合 | |||||
*/ | |||||
@Async("trainExecutor") | |||||
public void stopJobs(UserDTO currentUser, List<PtTrainJob> jobList) { | |||||
String namespace = k8sNameTool.generateNamespace(currentUser.getId()); | |||||
jobList.forEach(job -> { | |||||
BizPod bizPod = podApi.getWithResourceName(namespace, job.getJobName()); | |||||
if (!bizPod.isSuccess()) { | |||||
LogUtil.error(LogEnum.BIZ_TRAIN, "User {} stops training Job return code:{},message:{}", currentUser.getUsername(), Integer.valueOf(bizPod.getCode()), bizPod.getMessage()); | |||||
} | |||||
boolean bool = TrainTypeEnum.isDistributeTrain(job.getTrainType()) ? | |||||
distributeTrainApi.deleteByResourceName(namespace, job.getJobName()).isSuccess() : | |||||
trainJobApi.delete(namespace, job.getJobName()); | |||||
if (!bool) { | |||||
LogUtil.error(LogEnum.BIZ_TRAIN, "User {} stops training Job and K8S fails in the stop process, namespace为{}, resourceName为{}", | |||||
currentUser.getUsername(), namespace, job.getJobName()); | |||||
} | |||||
//更新训练状态 | |||||
job.setRuntime(calculateRuntime(bizPod)) | |||||
.setTrainStatus(TrainJobStatusEnum.STOP.getStatus()); | |||||
ptTrainJobMapper.updateById(job); | |||||
}); | |||||
} | |||||
/** | |||||
* 计算job训练时长 | |||||
* | |||||
* @param bizPod pod信息 | |||||
* @return String 训练时长 | |||||
*/ | |||||
private String calculateRuntime(BizPod bizPod) { | |||||
return calculateRuntime(bizPod, (x) -> { | |||||
}); | |||||
} | |||||
/** | |||||
* 计算job训练时长 | |||||
* | |||||
* @param bizPod | |||||
* @param consumer pod已经完成状态的回调函数 | |||||
* @return res 返回训练时长 | |||||
*/ | |||||
private String calculateRuntime(BizPod bizPod, Consumer<String> consumer) { | |||||
Long completedTime; | |||||
if (StringUtils.isBlank(bizPod.getStartTime())) { | |||||
return TrainUtil.INIT_RUNTIME; | |||||
} | |||||
Long startTime = transformTime(bizPod.getStartTime()); | |||||
boolean hasCompleted = StringUtils.isNotBlank(bizPod.getCompletedTime()); | |||||
completedTime = hasCompleted ? transformTime(bizPod.getCompletedTime()) : LocalDateTime.now().toEpochSecond(ZoneOffset.of(trainJobConfig.getPlusEight())); | |||||
Long time = completedTime - startTime; | |||||
String res = DubheDateUtil.convert2Str(time); | |||||
if (hasCompleted) { | |||||
consumer.accept(res); | |||||
} | |||||
return res; | |||||
} | |||||
/** | |||||
* 时间转换 | |||||
* | |||||
* @param time 时间 | |||||
* @return Long 时间戳 | |||||
*/ | |||||
private Long transformTime(String time) { | |||||
LocalDateTime localDateTime = LocalDateTime.parse(time, DateTimeFormatter.ISO_OFFSET_DATE_TIME); | |||||
//没有根据时区做处理, 默认当前为东八区 | |||||
localDateTime = localDateTime.plusHours(Long.valueOf(trainJobConfig.getEight())); | |||||
return localDateTime.toEpochSecond(ZoneOffset.of(trainJobConfig.getPlusEight())); | |||||
} | |||||
} |
@@ -0,0 +1,115 @@ | |||||
/** | |||||
* Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||||
* | |||||
* 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.dubhe.async; | |||||
import org.dubhe.config.NfsConfig; | |||||
import org.dubhe.dao.PtTrainAlgorithmMapper; | |||||
import org.dubhe.domain.dto.PtTrainAlgorithmCreateDTO; | |||||
import org.dubhe.domain.dto.UserDTO; | |||||
import org.dubhe.domain.entity.PtTrainAlgorithm; | |||||
import org.dubhe.enums.AlgorithmStatusEnum; | |||||
import org.dubhe.enums.BizNfsEnum; | |||||
import org.dubhe.enums.LogEnum; | |||||
import org.dubhe.exception.BusinessException; | |||||
import org.dubhe.service.NoteBookService; | |||||
import org.dubhe.utils.K8sNameTool; | |||||
import org.dubhe.utils.LocalFileUtil; | |||||
import org.dubhe.utils.LogUtil; | |||||
import org.springframework.beans.factory.annotation.Autowired; | |||||
import org.springframework.scheduling.annotation.Async; | |||||
import org.springframework.stereotype.Component; | |||||
/** | |||||
* @description 异步上传算法 | |||||
* @date 2020-08-10 | |||||
*/ | |||||
@Component | |||||
public class TrainAlgorithmUploadAsync { | |||||
@Autowired | |||||
private LocalFileUtil localFileUtil; | |||||
@Autowired | |||||
private NfsConfig nfsConfig; | |||||
@Autowired | |||||
private K8sNameTool k8sNameTool; | |||||
@Autowired | |||||
private NoteBookService noteBookService; | |||||
@Autowired | |||||
private PtTrainAlgorithmMapper trainAlgorithmMapper; | |||||
/** | |||||
* 异步任务创建算法 | |||||
* | |||||
* @param user 当前登录用户信息 | |||||
* @param ptTrainAlgorithm 算法信息 | |||||
* @param trainAlgorithmCreateDTO 创建算法条件 | |||||
*/ | |||||
@Async("trainExecutor") | |||||
public void createTrainAlgorithm(UserDTO user, PtTrainAlgorithm ptTrainAlgorithm, PtTrainAlgorithmCreateDTO trainAlgorithmCreateDTO) { | |||||
String path = nfsConfig.getBucket() + trainAlgorithmCreateDTO.getCodeDir(); | |||||
//校验创建算法来源(true:由fork创建算法,false:其它创建算法方式),若为true则拷贝预置算法文件至新路径 | |||||
if (trainAlgorithmCreateDTO.getFork()) { | |||||
//生成算法相对路径 | |||||
String algorithmPath = k8sNameTool.getNfsPath(BizNfsEnum.ALGORITHM, user.getId()); | |||||
//拷贝预置算法文件夹 | |||||
boolean copyResult = localFileUtil.copyPath(path, nfsConfig.getBucket() + algorithmPath); | |||||
if (!copyResult) { | |||||
LogUtil.error(LogEnum.BIZ_TRAIN, "The user {} copied the preset algorithm path {} successfully", user.getUsername(), path); | |||||
updateTrainAlgorithm(ptTrainAlgorithm, trainAlgorithmCreateDTO, false); | |||||
throw new BusinessException("内部错误"); | |||||
} | |||||
ptTrainAlgorithm.setCodeDir(algorithmPath); | |||||
//修改算法上传状态 | |||||
updateTrainAlgorithm(ptTrainAlgorithm, trainAlgorithmCreateDTO, true); | |||||
} else { | |||||
updateTrainAlgorithm(ptTrainAlgorithm, trainAlgorithmCreateDTO, true); | |||||
} | |||||
} | |||||
/** | |||||
* 更新上传算法状态 | |||||
* | |||||
* @param ptTrainAlgorithm 算法信息 | |||||
* @param trainAlgorithmCreateDTO 创建算法的条件 | |||||
* @param flag 创建算法是否成功(true:成功,false:失败) | |||||
*/ | |||||
public void updateTrainAlgorithm(PtTrainAlgorithm ptTrainAlgorithm, PtTrainAlgorithmCreateDTO trainAlgorithmCreateDTO, boolean flag) { | |||||
LogUtil.info(LogEnum.BIZ_TRAIN, "async update algorithmPath by algorithmId:{} and update noteBook by noteBookId:{}", ptTrainAlgorithm.getId(), trainAlgorithmCreateDTO.getNoteBookId()); | |||||
if (flag) { | |||||
ptTrainAlgorithm.setAlgorithmStatus(AlgorithmStatusEnum.SUCCESS.getCode()); | |||||
//更新fork算法新路径 | |||||
trainAlgorithmMapper.updateById(ptTrainAlgorithm); | |||||
//保存算法根据notbookId更新算法id | |||||
if (trainAlgorithmCreateDTO.getNoteBookId() != null) { | |||||
LogUtil.info(LogEnum.BIZ_TRAIN, "Save algorithm Update algorithm ID :{} according to notBookId:{}", trainAlgorithmCreateDTO.getNoteBookId(), ptTrainAlgorithm.getId()); | |||||
noteBookService.updateTrainIdByNoteBookId(trainAlgorithmCreateDTO.getNoteBookId(), ptTrainAlgorithm.getId()); | |||||
} | |||||
} else { | |||||
ptTrainAlgorithm.setAlgorithmStatus(AlgorithmStatusEnum.FAIL.getCode()); | |||||
trainAlgorithmMapper.updateById(ptTrainAlgorithm); | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,417 @@ | |||||
/** | |||||
* Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||||
* | |||||
* 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.dubhe.async; | |||||
import cn.hutool.core.util.StrUtil; | |||||
import com.alibaba.fastjson.JSONObject; | |||||
import org.dubhe.base.MagicNumConstant; | |||||
import org.dubhe.constant.SymbolConstant; | |||||
import org.dubhe.config.TrainJobConfig; | |||||
import org.dubhe.dao.PtTrainJobMapper; | |||||
import org.dubhe.domain.dto.BaseTrainJobDTO; | |||||
import org.dubhe.domain.dto.UserDTO; | |||||
import org.dubhe.domain.entity.PtTrainJob; | |||||
import org.dubhe.domain.vo.PtImageAndAlgorithmVO; | |||||
import org.dubhe.enums.BizEnum; | |||||
import org.dubhe.enums.LogEnum; | |||||
import org.dubhe.enums.ResourcesPoolTypeEnum; | |||||
import org.dubhe.enums.TrainJobStatusEnum; | |||||
import org.dubhe.exception.BusinessException; | |||||
import org.dubhe.k8s.api.DistributeTrainApi; | |||||
import org.dubhe.k8s.api.NamespaceApi; | |||||
import org.dubhe.k8s.api.TrainJobApi; | |||||
import org.dubhe.k8s.domain.bo.DistributeTrainBO; | |||||
import org.dubhe.k8s.domain.bo.PtJupyterJobBO; | |||||
import org.dubhe.k8s.domain.resource.BizDistributeTrain; | |||||
import org.dubhe.k8s.domain.resource.BizNamespace; | |||||
import org.dubhe.k8s.domain.vo.PtJupyterJobVO; | |||||
import org.dubhe.utils.*; | |||||
import org.springframework.beans.factory.annotation.Autowired; | |||||
import org.springframework.stereotype.Component; | |||||
import java.util.ArrayList; | |||||
import java.util.List; | |||||
/** | |||||
* @description 提交训练任务 | |||||
* @date 2020-07-17 | |||||
*/ | |||||
@Component | |||||
public class TrainJobAsync { | |||||
@Autowired | |||||
private K8sNameTool k8sNameTool; | |||||
@Autowired | |||||
private NamespaceApi namespaceApi; | |||||
@Autowired | |||||
private TrainJobConfig trainJobConfig; | |||||
@Autowired | |||||
private NfsUtil nfsUtil; | |||||
@Autowired | |||||
private LocalFileUtil localFileUtil; | |||||
@Autowired | |||||
private PtTrainJobMapper ptTrainJobMapper; | |||||
@Autowired | |||||
private TrainJobApi trainJobApi; | |||||
@Autowired | |||||
private DistributeTrainApi distributeTrainApi; | |||||
/** | |||||
* 提交分布式训练 | |||||
* | |||||
* @param baseTrainJobDTO 训练任务信息 | |||||
* @param currentUser 用户 | |||||
* @param ptImageAndAlgorithmVO 镜像和算法信息 | |||||
* @param ptTrainJob 训练任务实体信息 | |||||
*/ | |||||
public void doDistributedJob(BaseTrainJobDTO baseTrainJobDTO, UserDTO currentUser, PtImageAndAlgorithmVO ptImageAndAlgorithmVO, PtTrainJob ptTrainJob) { | |||||
try { | |||||
//判断是否存在相应的namespace,如果没有则创建 | |||||
String namespace = getNamespace(currentUser); | |||||
// 构建DistributeTrainBO | |||||
DistributeTrainBO bo = buildDistributeTrainBO(baseTrainJobDTO, currentUser, ptImageAndAlgorithmVO, ptTrainJob, namespace); | |||||
if (null == bo) { | |||||
LogUtil.error(LogEnum.BIZ_TRAIN, "user{}create TrainJob,Encapsulating ptjupyterjobbo object is empty,the received parameters namespace:{}", currentUser.getId(), namespace); | |||||
updateTrainStatus(currentUser, ptTrainJob, baseTrainJobDTO, "", false); | |||||
return; | |||||
} | |||||
// 调度K8s | |||||
BizDistributeTrain bizDistributeTrain = distributeTrainApi.create(bo); | |||||
if (bizDistributeTrain.isSuccess()) { | |||||
// 调度成功 | |||||
updateTrainStatus(currentUser, ptTrainJob, baseTrainJobDTO, bizDistributeTrain.getName(), true); | |||||
} else { | |||||
// 调度失败 | |||||
LogUtil.error(LogEnum.BIZ_TRAIN, "distributeTrainApi.create FAILED! {}", bizDistributeTrain); | |||||
updateTrainStatus(currentUser, ptTrainJob, baseTrainJobDTO, bizDistributeTrain.getName(), false); | |||||
} | |||||
} catch (Exception e) { | |||||
LogUtil.error(LogEnum.BIZ_TRAIN, "doDistributedJob ERROR!{} ", e); | |||||
updateTrainStatus(currentUser, ptTrainJob, baseTrainJobDTO, "", false); | |||||
} | |||||
} | |||||
/** | |||||
* 构造分布式训练DistributeTrainBO | |||||
* | |||||
* @param baseTrainJobDTO 训练任务信息 | |||||
* @param currentUser 用户 | |||||
* @param ptImageAndAlgorithmVO 镜像和算法信息 | |||||
* @param ptTrainJob 训练任务实体信息 | |||||
* @param namespace 命名空间 | |||||
* @return DistributeTrainBO | |||||
*/ | |||||
private DistributeTrainBO buildDistributeTrainBO(BaseTrainJobDTO baseTrainJobDTO, UserDTO currentUser, PtImageAndAlgorithmVO ptImageAndAlgorithmVO, PtTrainJob ptTrainJob, String namespace) { | |||||
//绝对路径 | |||||
String basePath = nfsUtil.getNfsConfig().getBucket() + trainJobConfig.getManage() + StrUtil.SLASH | |||||
+ currentUser.getId() + StrUtil.SLASH + baseTrainJobDTO.getJobName(); | |||||
//相对路径 | |||||
String relativePath = StrUtil.SLASH + trainJobConfig.getManage() + StrUtil.SLASH | |||||
+ currentUser.getId() + StrUtil.SLASH + baseTrainJobDTO.getJobName(); | |||||
String[] codeDirArray = ptImageAndAlgorithmVO.getCodeDir().split(StrUtil.SLASH); | |||||
String workspaceDir = codeDirArray[codeDirArray.length - 1]; | |||||
// 算法路径待拷贝的地址 | |||||
String sourcePath = nfsUtil.getNfsConfig().getBucket() + ptImageAndAlgorithmVO.getCodeDir().substring(1); | |||||
String trainDir = basePath.substring(1) + StrUtil.SLASH + workspaceDir; | |||||
if (!localFileUtil.copyPath(sourcePath, trainDir)) { | |||||
LogUtil.error(LogEnum.BIZ_TRAIN, "buildDistributeTrainBO copyPath failed ! sourcePath:{},basePath:{},trainDir:{}", sourcePath, basePath, trainDir); | |||||
return null; | |||||
} | |||||
// 参数前缀 | |||||
String paramPrefix = trainJobConfig.getPythonFormat(); | |||||
// 初始化固定头命令,获取分布式节点IP | |||||
StringBuilder sb = new StringBuilder("export NODE_IPS=`cat /home/hostfile.json |jq -r \".[]|.ip\"|paste -d \",\" -s` "); | |||||
// 切换到算法路径下 | |||||
sb.append(" && cd ").append(trainJobConfig.getDockerTrainPath()).append(StrUtil.SLASH).append(workspaceDir).append(" && "); | |||||
// 拼接用户自定义python启动命令 | |||||
sb.append(ptImageAndAlgorithmVO.getRunCommand()); | |||||
// 拼接python固定参数 节点IP | |||||
sb.append(paramPrefix).append(trainJobConfig.getNodeIps()).append("=\"$NODE_IPS\" "); | |||||
// 拼接python固定参数 节点数量 | |||||
sb.append(paramPrefix).append(trainJobConfig.getNodeNum()).append(SymbolConstant.FLAG_EQUAL).append(ptTrainJob.getResourcesPoolNode()).append(StrUtil.SPACE); | |||||
if (ptImageAndAlgorithmVO.getIsTrainOut()) { | |||||
// 拼接 out | |||||
nfsUtil.createDir(basePath + StrUtil.SLASH + trainJobConfig.getOutPath()); | |||||
baseTrainJobDTO.setOutPath(relativePath + StrUtil.SLASH + trainJobConfig.getOutPath()); | |||||
sb.append(paramPrefix).append(trainJobConfig.getDockerOutPath()); | |||||
} | |||||
if (ptImageAndAlgorithmVO.getIsTrainLog()) { | |||||
// 拼接 输出日志 | |||||
nfsUtil.createDir(basePath + StrUtil.SLASH + trainJobConfig.getLogPath()); | |||||
baseTrainJobDTO.setLogPath(relativePath + StrUtil.SLASH + trainJobConfig.getLogPath()); | |||||
sb.append(paramPrefix).append(trainJobConfig.getDockerLogPath()); | |||||
} | |||||
if (ptImageAndAlgorithmVO.getIsVisualizedLog()) { | |||||
// 拼接 输出可视化日志 | |||||
nfsUtil.createDir(basePath + StrUtil.SLASH + trainJobConfig.getVisualizedLogPath()); | |||||
baseTrainJobDTO.setVisualizedLogPath(relativePath + StrUtil.SLASH + trainJobConfig.getVisualizedLogPath()); | |||||
sb.append(paramPrefix).append(trainJobConfig.getDockerVisualizedLogPath()); | |||||
} | |||||
// 拼接python固定参数 数据集 | |||||
sb.append(paramPrefix).append(trainJobConfig.getDockerDataset()); | |||||
JSONObject runParams = baseTrainJobDTO.getRunParams(); | |||||
if (null != runParams && !runParams.isEmpty()) { | |||||
// 拼接用户自定义参数 | |||||
runParams.entrySet().forEach(entry -> | |||||
sb.append(paramPrefix).append(entry.getKey()).append(SymbolConstant.FLAG_EQUAL).append(entry.getValue()).append(StrUtil.SPACE) | |||||
); | |||||
} | |||||
// 在用户自定以参数拼接晚后拼接固定参数,防止被用户自定义参数覆盖 | |||||
if (ResourcesPoolTypeEnum.isGpuCode(baseTrainJobDTO.getPtTrainJobSpecs().getResourcesPoolType())) { | |||||
// 需要GPU | |||||
sb.append(paramPrefix).append(trainJobConfig.getGpuNumPerNode()).append(SymbolConstant.FLAG_EQUAL).append(baseTrainJobDTO.getGpuNumPerNode()).append(StrUtil.SPACE); | |||||
} | |||||
String mainCommand = sb.toString(); | |||||
// 拼接辅助日志打印 | |||||
String wholeCommand = " echo 'Distribute training mission begins... " | |||||
+ mainCommand | |||||
+ " ' && " | |||||
+ mainCommand | |||||
+ " && echo 'Distribute training mission is over' "; | |||||
DistributeTrainBO distributeTrainBO = new DistributeTrainBO() | |||||
.setNamespace(namespace) | |||||
.setName(baseTrainJobDTO.getJobName()) | |||||
.setSize(ptTrainJob.getResourcesPoolNode()) | |||||
.setImage(ptImageAndAlgorithmVO.getImageName()) | |||||
.setMasterCmd(wholeCommand) | |||||
.setMemNum(baseTrainJobDTO.getMenNum()) | |||||
.setCpuNum(baseTrainJobDTO.getCpuNum()) | |||||
.setDatasetStoragePath(k8sNameTool.getAbsoluteNfsPath(baseTrainJobDTO.getDataSourcePath())) | |||||
.setWorkspaceStoragePath(localFileUtil.formatPath(nfsUtil.getNfsConfig().getRootDir() + basePath)) | |||||
.setModelStoragePath(k8sNameTool.getAbsoluteNfsPath(relativePath + StrUtil.SLASH + trainJobConfig.getOutPath())) | |||||
.setBusinessLabel(k8sNameTool.getPodLabel(BizEnum.ALGORITHM)); | |||||
//延时启动,单位为分钟 | |||||
if (baseTrainJobDTO.getDelayCreateTime() != null && baseTrainJobDTO.getDelayCreateTime() > 0) { | |||||
distributeTrainBO.setDelayCreateTime(baseTrainJobDTO.getDelayCreateTime() * MagicNumConstant.SIXTY); | |||||
} | |||||
//定时停止,单位为分钟 | |||||
if (baseTrainJobDTO.getDelayDeleteTime() != null && baseTrainJobDTO.getDelayDeleteTime() > 0) { | |||||
distributeTrainBO.setDelayDeleteTime(baseTrainJobDTO.getDelayDeleteTime() * MagicNumConstant.SIXTY); | |||||
} | |||||
if (ResourcesPoolTypeEnum.isGpuCode(baseTrainJobDTO.getPtTrainJobSpecs().getResourcesPoolType())) { | |||||
// 需要GPU | |||||
distributeTrainBO.setGpuNum(baseTrainJobDTO.getGpuNumPerNode()); | |||||
} | |||||
// 主从一致 | |||||
distributeTrainBO.setSlaveCmd(distributeTrainBO.getMasterCmd()); | |||||
return distributeTrainBO; | |||||
} | |||||
/** | |||||
* 提交job | |||||
* | |||||
* @param baseTrainJobDTO 训练任务信息 | |||||
* @param currentUser 用户 | |||||
* @param ptImageAndAlgorithmVO 镜像和算法信息 | |||||
*/ | |||||
public void doJob(BaseTrainJobDTO baseTrainJobDTO, UserDTO currentUser, PtImageAndAlgorithmVO ptImageAndAlgorithmVO, PtTrainJob ptTrainJob) { | |||||
PtJupyterJobBO jobBo = null; | |||||
String k8sJobName = ""; | |||||
try { | |||||
//判断是否存在相应的namespace,如果没有则创建 | |||||
String namespace = getNamespace(currentUser); | |||||
//封装PtJupyterJobBO对象,调用创建训练任务接口 | |||||
jobBo = pkgPtJupyterJobBo(baseTrainJobDTO, currentUser, ptImageAndAlgorithmVO, namespace); | |||||
if (null == jobBo) { | |||||
LogUtil.error(LogEnum.BIZ_TRAIN, "user {} create TrainJob,Encapsulating ptjupyterjobbo object is empty,the received parameters namespace:{}", currentUser.getId(), namespace); | |||||
updateTrainStatus(currentUser, ptTrainJob, baseTrainJobDTO, k8sJobName, false); | |||||
} | |||||
PtJupyterJobVO ptJupyterJobResult = trainJobApi.create(jobBo); | |||||
if (!ptJupyterJobResult.isSuccess()) { | |||||
String message = null == ptJupyterJobResult.getMessage() ? "未知的错误" : ptJupyterJobResult.getMessage(); | |||||
LogUtil.error(LogEnum.BIZ_TRAIN, "user {} create TrainJob, K8s creation failed, the received parameters are {}, the wrong information is{}", currentUser.getUsername(), jobBo, message); | |||||
ptTrainJob.setTrainMsg(message); | |||||
updateTrainStatus(currentUser, ptTrainJob, baseTrainJobDTO, k8sJobName, false); | |||||
} | |||||
k8sJobName = ptJupyterJobResult.getName(); | |||||
//更新训练任务状态 | |||||
updateTrainStatus(currentUser, ptTrainJob, baseTrainJobDTO, k8sJobName, true); | |||||
} catch (Exception e) { | |||||
LogUtil.error(LogEnum.BIZ_TRAIN, "user {} create TrainJob, K8s creation failed, the received parameters are {}, the wrong information is{}", currentUser.getUsername(), | |||||
jobBo, e); | |||||
ptTrainJob.setTrainMsg("内部错误"); | |||||
updateTrainStatus(currentUser, ptTrainJob, baseTrainJobDTO, k8sJobName, false); | |||||
} | |||||
} | |||||
/** | |||||
* 获取namespace | |||||
* | |||||
* @param currentUser 用户 | |||||
* @return String 命名空间 | |||||
*/ | |||||
private String getNamespace(UserDTO currentUser) { | |||||
String namespaceStr = k8sNameTool.generateNamespace(currentUser.getId()); | |||||
BizNamespace bizNamespace = namespaceApi.get(namespaceStr); | |||||
if (null == bizNamespace) { | |||||
BizNamespace namespace = namespaceApi.create(namespaceStr, null); | |||||
if (null == namespace || !namespace.isSuccess()) { | |||||
LogUtil.error(LogEnum.BIZ_TRAIN, "User {} failed to create namespace during training job..."); | |||||
throw new BusinessException("内部错误"); | |||||
} | |||||
} | |||||
return namespaceStr; | |||||
} | |||||
/** | |||||
* 封装出创建job所需的BO | |||||
* | |||||
* @param baseTrainJobDTO 训练任务信息 | |||||
* @param ptImageAndAlgorithmVO 镜像和算法信息 | |||||
* @param namespace 命名空间 | |||||
* @return PtJupyterJobBO jupyter任务BO | |||||
*/ | |||||
private PtJupyterJobBO pkgPtJupyterJobBo(BaseTrainJobDTO baseTrainJobDTO, UserDTO currentUser, | |||||
PtImageAndAlgorithmVO ptImageAndAlgorithmVO, String namespace) { | |||||
//绝对路径 | |||||
String commonPath = nfsUtil.getNfsConfig().getBucket() + trainJobConfig.getManage() + StrUtil.SLASH | |||||
+ currentUser.getId() + StrUtil.SLASH + baseTrainJobDTO.getJobName(); | |||||
//相对路径 | |||||
String relativeCommonPath = StrUtil.SLASH + trainJobConfig.getManage() + StrUtil.SLASH | |||||
+ currentUser.getId() + StrUtil.SLASH + baseTrainJobDTO.getJobName(); | |||||
String[] codeDirArray = ptImageAndAlgorithmVO.getCodeDir().split(StrUtil.SLASH); | |||||
String workspaceDir = codeDirArray[codeDirArray.length - 1]; | |||||
// 算法路径待拷贝的地址 | |||||
String sourcePath = nfsUtil.getNfsConfig().getBucket() + ptImageAndAlgorithmVO.getCodeDir().substring(1); | |||||
String trainDir = commonPath.substring(1) + StrUtil.SLASH + workspaceDir; | |||||
LogUtil.info(LogEnum.BIZ_TRAIN, "Algorithm path copy::sourcePath:{},commonPath:{},trainDir:{}", sourcePath, commonPath, trainDir); | |||||
boolean bool = localFileUtil.copyPath(sourcePath.substring(1), trainDir); | |||||
if (!bool) { | |||||
LogUtil.error(LogEnum.BIZ_TRAIN, "During the process of user {} creating training Job and encapsulating k8s creating job interface parameters, it failed to copy algorithm directory {} to the specified directory {}", currentUser.getUsername(), sourcePath.substring(1), | |||||
trainDir); | |||||
return null; | |||||
} | |||||
List<String> list = new ArrayList<>(); | |||||
JSONObject runParams = baseTrainJobDTO.getRunParams(); | |||||
StringBuilder sb = new StringBuilder(); | |||||
sb.append(ptImageAndAlgorithmVO.getRunCommand()); | |||||
// 拼接out,log和dataset | |||||
String pattern = trainJobConfig.getPythonFormat(); | |||||
if (ptImageAndAlgorithmVO.getIsTrainOut()) { | |||||
nfsUtil.createDir(commonPath + StrUtil.SLASH + trainJobConfig.getOutPath()); | |||||
baseTrainJobDTO.setOutPath(relativeCommonPath + StrUtil.SLASH + trainJobConfig.getOutPath()); | |||||
sb.append(pattern).append(trainJobConfig.getDockerOutPath()); | |||||
} | |||||
if (ptImageAndAlgorithmVO.getIsTrainLog()) { | |||||
nfsUtil.createDir(commonPath + StrUtil.SLASH + trainJobConfig.getLogPath()); | |||||
baseTrainJobDTO.setLogPath(relativeCommonPath + StrUtil.SLASH + trainJobConfig.getLogPath()); | |||||
sb.append(pattern).append(trainJobConfig.getDockerLogPath()); | |||||
} | |||||
if (ptImageAndAlgorithmVO.getIsVisualizedLog()) { | |||||
nfsUtil.createDir(commonPath + StrUtil.SLASH + trainJobConfig.getVisualizedLogPath()); | |||||
baseTrainJobDTO.setVisualizedLogPath(relativeCommonPath + StrUtil.SLASH + trainJobConfig.getVisualizedLogPath()); | |||||
sb.append(pattern).append(trainJobConfig.getDockerVisualizedLogPath()); | |||||
} | |||||
sb.append(pattern).append(trainJobConfig.getDockerDataset()); | |||||
String valDataSourcePath = baseTrainJobDTO.getValDataSourcePath(); | |||||
if (StringUtils.isNotBlank(valDataSourcePath)) { | |||||
sb.append(pattern).append(trainJobConfig.getLoadValDatasetKey()).append(SymbolConstant.FLAG_EQUAL).append(trainJobConfig.getDockerValDatasetPath()); | |||||
} | |||||
//将模型加载路径拼接到 | |||||
String modelLoadPathDir = baseTrainJobDTO.getModelLoadPathDir(); | |||||
if (StringUtils.isNotBlank(modelLoadPathDir)) { | |||||
//将模型路径model_load_dir路径 | |||||
sb.append(pattern).append(trainJobConfig.getLoadKey()).append(SymbolConstant.FLAG_EQUAL).append(trainJobConfig.getDockerModelPath()); | |||||
} | |||||
if (null != runParams && !runParams.isEmpty()) { | |||||
runParams.forEach((k, v) -> | |||||
sb.append(pattern).append(k).append(SymbolConstant.FLAG_EQUAL).append(v).append(StrUtil.SPACE) | |||||
); | |||||
} | |||||
// 在用户自定以参数拼接晚后拼接固定参数,防止被用户自定义参数覆盖 | |||||
if (ResourcesPoolTypeEnum.isGpuCode(baseTrainJobDTO.getPtTrainJobSpecs().getResourcesPoolType())) { | |||||
// 需要GPU | |||||
sb.append(pattern).append(trainJobConfig.getGpuNumPerNode()).append(SymbolConstant.FLAG_EQUAL).append(baseTrainJobDTO.getGpuNumPerNode()).append(StrUtil.SPACE); | |||||
} | |||||
String executeCmd = sb.toString(); | |||||
list.add("-c"); | |||||
String workPath = trainJobConfig.getDockerTrainPath() + StrUtil.SLASH + workspaceDir; | |||||
String command = "echo 'training mission begins... " + executeCmd + "\r\n '" + | |||||
" && cd " + workPath + | |||||
" && " + executeCmd + | |||||
" && echo 'the training mission is over' "; | |||||
list.add(command); | |||||
PtJupyterJobBO jobBo = new PtJupyterJobBO(); | |||||
jobBo.setNamespace(namespace) | |||||
.setName(baseTrainJobDTO.getJobName()) | |||||
.setImage(ptImageAndAlgorithmVO.getImageName()) | |||||
.putNfsMounts(trainJobConfig.getDockerDatasetPath(), nfsUtil.getNfsConfig().getRootDir() + nfsUtil.getNfsConfig().getBucket().substring(1) + baseTrainJobDTO.getDataSourcePath()) | |||||
.setCmdLines(list) | |||||
.putNfsMounts(trainJobConfig.getDockerTrainPath(), nfsUtil.getNfsConfig().getRootDir() + commonPath.substring(1)) | |||||
.putNfsMounts(trainJobConfig.getDockerModelPath(), nfsUtil.formatPath(nfsUtil.getAbsolutePath(modelLoadPathDir))) | |||||
.putNfsMounts(trainJobConfig.getDockerValDatasetPath(), nfsUtil.formatPath(nfsUtil.getAbsolutePath(valDataSourcePath))) | |||||
.setBusinessLabel(k8sNameTool.getPodLabel(BizEnum.ALGORITHM)); | |||||
//延时启动,单位为分钟 | |||||
if (baseTrainJobDTO.getDelayCreateTime() != null && baseTrainJobDTO.getDelayCreateTime() > 0) { | |||||
jobBo.setDelayCreateTime(baseTrainJobDTO.getDelayCreateTime() * MagicNumConstant.SIXTY); | |||||
} | |||||
//自动停止,单位为分钟 | |||||
if (baseTrainJobDTO.getDelayDeleteTime() != null && baseTrainJobDTO.getDelayDeleteTime() > 0) { | |||||
jobBo.setDelayDeleteTime(baseTrainJobDTO.getDelayDeleteTime() * MagicNumConstant.SIXTY); | |||||
} | |||||
jobBo.setCpuNum(baseTrainJobDTO.getCpuNum()).setMemNum(baseTrainJobDTO.getMenNum()); | |||||
if (ResourcesPoolTypeEnum.isGpuCode(baseTrainJobDTO.getPtTrainJobSpecs().getResourcesPoolType())) { | |||||
jobBo.setUseGpu(true).setGpuNum(baseTrainJobDTO.getGpuNumPerNode()); | |||||
} else { | |||||
jobBo.setUseGpu(false); | |||||
} | |||||
return jobBo; | |||||
} | |||||
/** | |||||
* 训练任务异步处理更新训练状态 | |||||
* | |||||
* @param user 用户 | |||||
* @param ptTrainJob 训练任务 | |||||
* @param baseTrainJobDTO 训练任务信息 | |||||
* @param k8sJobName k8s创建的job名称,或者分布式训练名称 | |||||
* @param flag 创建训练任务是否异常(true:正常,false:失败) | |||||
**/ | |||||
private void updateTrainStatus(UserDTO user, PtTrainJob ptTrainJob, BaseTrainJobDTO baseTrainJobDTO, String k8sJobName, boolean flag) { | |||||
ptTrainJob.setK8sJobName(k8sJobName) | |||||
.setOutPath(baseTrainJobDTO.getOutPath()) | |||||
.setLogPath(baseTrainJobDTO.getLogPath()) | |||||
.setVisualizedLogPath(baseTrainJobDTO.getVisualizedLogPath()); | |||||
LogUtil.info(LogEnum.BIZ_TRAIN, "user {} training tasks are processed asynchronously to update training status,receiving parameters:{}", user.getId(), ptTrainJob); | |||||
if (flag) { | |||||
ptTrainJobMapper.updateById(ptTrainJob); | |||||
} else { | |||||
ptTrainJob.setTrainStatus(TrainJobStatusEnum.CREATE_FAILED.getStatus()); | |||||
//训练任务创建失败 | |||||
ptTrainJobMapper.updateById(ptTrainJob); | |||||
} | |||||
} | |||||
} |
@@ -14,13 +14,16 @@ | |||||
* limitations under the License. | * limitations under the License. | ||||
* ============================================================= | * ============================================================= | ||||
*/ | */ | ||||
package org.dubhe.task; | |||||
package org.dubhe.async; | |||||
import org.dubhe.aspect.LogAspect; | import org.dubhe.aspect.LogAspect; | ||||
import org.dubhe.base.DataContext; | |||||
import org.dubhe.domain.dto.BaseTrainJobDTO; | import org.dubhe.domain.dto.BaseTrainJobDTO; | ||||
import org.dubhe.domain.dto.CommonPermissionDataDTO; | |||||
import org.dubhe.domain.dto.UserDTO; | import org.dubhe.domain.dto.UserDTO; | ||||
import org.dubhe.domain.entity.PtTrainJob; | import org.dubhe.domain.entity.PtTrainJob; | ||||
import org.dubhe.domain.vo.PtImageAndAlgorithmVO; | import org.dubhe.domain.vo.PtImageAndAlgorithmVO; | ||||
import org.dubhe.enums.TrainTypeEnum; | |||||
import org.slf4j.MDC; | import org.slf4j.MDC; | ||||
import org.springframework.beans.factory.annotation.Autowired; | import org.springframework.beans.factory.annotation.Autowired; | ||||
import org.springframework.stereotype.Component; | import org.springframework.stereotype.Component; | ||||
@@ -38,26 +41,32 @@ import java.util.concurrent.Executor; | |||||
public class TransactionAsyncManager { | public class TransactionAsyncManager { | ||||
@Autowired | @Autowired | ||||
private TrainJobAsyncTask trainJobAsyncTask; | |||||
@Resource(name = "trainJobAsyncExecutor") | |||||
private Executor trainJobAsyncExecutor; | |||||
private TrainJobAsync trainJobAsync; | |||||
@Resource(name = "trainExecutor") | |||||
private Executor trainExecutor; | |||||
public void execute(BaseTrainJobDTO baseTrainJobDTO, UserDTO currentUser, PtImageAndAlgorithmVO ptImageAndAlgorithmVO, PtTrainJob ptTrainJob) { | public void execute(BaseTrainJobDTO baseTrainJobDTO, UserDTO currentUser, PtImageAndAlgorithmVO ptImageAndAlgorithmVO, PtTrainJob ptTrainJob) { | ||||
String traceId = MDC.get(LogAspect.TRACE_ID); | String traceId = MDC.get(LogAspect.TRACE_ID); | ||||
CommonPermissionDataDTO commonPermissionDataDTO = DataContext.get(); | |||||
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() { | TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() { | ||||
@Override | @Override | ||||
public void afterCommit() { | public void afterCommit() { | ||||
trainJobAsyncExecutor.execute( | |||||
() -> { | |||||
MDC.put(LogAspect.TRACE_ID, traceId); | |||||
trainJobAsyncTask.doJob(baseTrainJobDTO, currentUser, ptImageAndAlgorithmVO, ptTrainJob); | |||||
MDC.remove(LogAspect.TRACE_ID); | |||||
} | |||||
); | |||||
trainExecutor.execute(() -> { | |||||
MDC.put(LogAspect.TRACE_ID, traceId); | |||||
DataContext.set(commonPermissionDataDTO); | |||||
if (TrainTypeEnum.isDistributeTrain(ptTrainJob.getTrainType())) { | |||||
// 分布式训练 | |||||
trainJobAsync.doDistributedJob(baseTrainJobDTO, currentUser, ptImageAndAlgorithmVO, ptTrainJob); | |||||
} else { | |||||
// 普通训练 | |||||
trainJobAsync.doJob(baseTrainJobDTO, currentUser, ptImageAndAlgorithmVO, ptTrainJob); | |||||
} | |||||
MDC.remove(LogAspect.TRACE_ID); | |||||
DataContext.remove(); | |||||
}); | |||||
} | } | ||||
}); | }); | ||||
} | } |
@@ -0,0 +1,148 @@ | |||||
/** | |||||
* Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||||
* | |||||
* 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.dubhe.config; | |||||
import com.alibaba.fastjson.JSON; | |||||
import org.dubhe.constant.StringConstant; | |||||
import org.dubhe.constatnts.UserConstant; | |||||
import org.dubhe.dto.GlobalRequestRecordDTO; | |||||
import org.dubhe.enums.LogEnum; | |||||
import org.dubhe.utils.JwtUtils; | |||||
import org.dubhe.utils.LogUtil; | |||||
import org.dubhe.utils.StringUtils; | |||||
import org.springframework.core.annotation.Order; | |||||
import org.springframework.stereotype.Component; | |||||
import javax.servlet.*; | |||||
import javax.servlet.annotation.WebFilter; | |||||
import javax.servlet.http.HttpServletRequest; | |||||
import javax.servlet.http.HttpServletResponse; | |||||
import java.io.IOException; | |||||
import static org.dubhe.constant.StringConstant.K8S_CALLBACK_URI; | |||||
/** | |||||
* @description 全局请求拦截器 用于日志收集 | |||||
* @date 2020-08-13 | |||||
*/ | |||||
@Order(1) | |||||
@Component | |||||
@WebFilter(filterName = "GlobalFilter", urlPatterns = "/**") | |||||
public class GlobalFilter implements Filter { | |||||
@Override | |||||
public void init(FilterConfig filterConfig) throws ServletException { | |||||
} | |||||
@Override | |||||
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException { | |||||
long start = System.currentTimeMillis(); | |||||
HttpServletRequest request = ((HttpServletRequest) servletRequest); | |||||
HttpServletResponse response = ((HttpServletResponse) servletResponse); | |||||
GlobalRequestRecordDTO dto = new GlobalRequestRecordDTO(); | |||||
try { | |||||
if (StringUtils.isNotBlank(request.getContentType()) && request.getContentType().contains(StringConstant.MULTIPART)) { | |||||
chain.doFilter(request, response); | |||||
} else { | |||||
checkScheduleRequest(request); | |||||
checkK8sCallback(request); | |||||
RequestBodyWrapper requestBodyWrapper = new RequestBodyWrapper(request); | |||||
ResponseBodyWrapper responseBodyWrapper = new ResponseBodyWrapper(response); | |||||
dto.setRequestBody(requestBodyWrapper.getBodyString()); | |||||
chain.doFilter(requestBodyWrapper, responseBodyWrapper); | |||||
if (StringConstant.JSON_REQUEST.equals(responseBodyWrapper.getContentType())) { | |||||
final String responseBody = responseBodyWrapper.getResponseBody(); | |||||
dto.setResponseBody(responseBody); | |||||
} else { | |||||
responseBodyWrapper.flush(); | |||||
} | |||||
} | |||||
} catch (Exception e) { | |||||
LogUtil.error(LogEnum.GLOBAL_REQ, "Global request record error : {}", e); | |||||
throw e; | |||||
} finally { | |||||
buildGlobalRequestDTO(dto, request, response); | |||||
dto.setTimeCost(System.currentTimeMillis() - start); | |||||
LogUtil.info(LogEnum.GLOBAL_REQ, "Global request record: {}", dto); | |||||
LogUtil.cleanTrace(); | |||||
} | |||||
} | |||||
/** | |||||
* 构建全局请求对象 | |||||
* | |||||
* @param dto | |||||
* @param request | |||||
* @param response | |||||
*/ | |||||
private void buildGlobalRequestDTO(GlobalRequestRecordDTO dto, HttpServletRequest request, HttpServletResponse response) { | |||||
dto.setClientHost(request.getRemoteHost()); | |||||
dto.setParams(JSON.toJSONString(request.getParameterMap())); | |||||
dto.setMethod(request.getMethod()); | |||||
dto.setUri(request.getRequestURI()); | |||||
//身份认证信息 | |||||
String token = request.getHeader(UserConstant.USER_TOKEN_KEY); | |||||
dto.setAuthorization(token); | |||||
if (token != null) { | |||||
String userName = JwtUtils.getUserName(token); | |||||
dto.setUsername(userName); | |||||
} | |||||
dto.setContentType(response.getContentType()); | |||||
dto.setStatus(response.getStatus()); | |||||
} | |||||
/** | |||||
* 检查是否是前端的定时请求 | |||||
* | |||||
* @param request 请求信息 | |||||
* @return 是否是前端的定时请求 | |||||
*/ | |||||
private boolean checkScheduleRequest(HttpServletRequest request) { | |||||
if (StringConstant.REQUEST_METHOD_GET.equals(request.getMethod()) | |||||
&& StringUtils.isNotBlank(request.getParameter(LogUtil.SCHEDULE_LEVEL))) { | |||||
LogUtil.startScheduleTrace(); | |||||
return true; | |||||
} | |||||
return false; | |||||
} | |||||
/** | |||||
* 校验请求是否为k8s回调 | |||||
* @param request 请求信息 | |||||
* @return 是否为k8s回调 | |||||
*/ | |||||
private boolean checkK8sCallback(HttpServletRequest request) { | |||||
if (request.getRequestURI() != null && request.getRequestURI().contains(K8S_CALLBACK_URI)) { | |||||
LogUtil.startK8sCallbackTrace(); | |||||
return true; | |||||
} | |||||
return false; | |||||
} | |||||
@Override | |||||
public void destroy() { | |||||
} | |||||
} |
@@ -0,0 +1,101 @@ | |||||
/** | |||||
* Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||||
* | |||||
* 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.dubhe.config; | |||||
import org.dubhe.enums.LogEnum; | |||||
import org.dubhe.utils.LogUtil; | |||||
import javax.servlet.ReadListener; | |||||
import javax.servlet.ServletInputStream; | |||||
import javax.servlet.http.HttpServletRequest; | |||||
import javax.servlet.http.HttpServletRequestWrapper; | |||||
import java.io.BufferedReader; | |||||
import java.io.ByteArrayInputStream; | |||||
import java.io.IOException; | |||||
import java.io.InputStreamReader; | |||||
/** | |||||
* @description 用于获取请求body参数的包装类 | |||||
* @date 2020-08-20 | |||||
*/ | |||||
public class RequestBodyWrapper extends HttpServletRequestWrapper { | |||||
private ByteArrayInputStream byteArrayInputStream; | |||||
private String bodyString; | |||||
public RequestBodyWrapper(HttpServletRequest request) | |||||
throws IOException { | |||||
super(request); | |||||
try (BufferedReader reader = request.getReader()) { | |||||
StringBuilder sb = new StringBuilder(); | |||||
String line = null; | |||||
while ((line = reader.readLine()) != null) { | |||||
sb.append(line); | |||||
} | |||||
if (sb.length() > 0) { | |||||
bodyString = sb.toString(); | |||||
} else { | |||||
bodyString = ""; | |||||
} | |||||
byteArrayInputStream = new ByteArrayInputStream(bodyString.getBytes()); | |||||
} catch (Exception e) { | |||||
LogUtil.error(LogEnum.GLOBAL_REQ, "request get reader error : {}", e); | |||||
throw e; | |||||
} | |||||
} | |||||
/** | |||||
* 获取请求体的json数据 | |||||
* | |||||
* @return | |||||
*/ | |||||
public String getBodyString() { | |||||
return bodyString; | |||||
} | |||||
@Override | |||||
public BufferedReader getReader() throws IOException { | |||||
return new BufferedReader(new InputStreamReader(getInputStream())); | |||||
} | |||||
@Override | |||||
public ServletInputStream getInputStream() throws IOException { | |||||
return new ServletInputStream() { | |||||
@Override | |||||
public boolean isFinished() { | |||||
return false; | |||||
} | |||||
@Override | |||||
public boolean isReady() { | |||||
return false; | |||||
} | |||||
@Override | |||||
public void setReadListener(ReadListener readListener) { | |||||
} | |||||
@Override | |||||
public int read() throws IOException { | |||||
return byteArrayInputStream.read(); | |||||
} | |||||
}; | |||||
} | |||||
} |
@@ -0,0 +1,126 @@ | |||||
/** | |||||
* Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||||
* | |||||
* 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.dubhe.config; | |||||
import org.dubhe.enums.LogEnum; | |||||
import org.dubhe.utils.LogUtil; | |||||
import java.io.ByteArrayOutputStream; | |||||
import java.io.IOException; | |||||
import java.io.OutputStreamWriter; | |||||
import java.io.PrintWriter; | |||||
import java.io.UnsupportedEncodingException; | |||||
import javax.servlet.ServletOutputStream; | |||||
import javax.servlet.WriteListener; | |||||
import javax.servlet.http.HttpServletResponse; | |||||
import javax.servlet.http.HttpServletResponseWrapper; | |||||
/** | |||||
* @description 用于获取response 的 json 返回值 | |||||
* @date 2020-08-19 | |||||
*/ | |||||
public class ResponseBodyWrapper extends HttpServletResponseWrapper { | |||||
private ByteArrayOutputStream byteArrayOutputStream = null; | |||||
private ServletOutputStream servletOutputStream = null; | |||||
private PrintWriter printWriter = null; | |||||
private HttpServletResponse response; | |||||
public ResponseBodyWrapper(HttpServletResponse response) throws IOException { | |||||
super(response); | |||||
this.response = response; | |||||
byteArrayOutputStream = new ByteArrayOutputStream(); | |||||
printWriter = new PrintWriter(new OutputStreamWriter(byteArrayOutputStream, "UTF-8")); | |||||
servletOutputStream = new ServletOutputStream() { | |||||
@Override | |||||
public void write(int b) throws IOException { | |||||
byteArrayOutputStream.write(b); | |||||
} | |||||
@Override | |||||
public boolean isReady() { | |||||
return false; | |||||
} | |||||
@Override | |||||
public void setWriteListener(WriteListener writeListener) { | |||||
} | |||||
}; | |||||
} | |||||
@Override | |||||
public ServletOutputStream getOutputStream() throws IOException { | |||||
return servletOutputStream; | |||||
} | |||||
@Override | |||||
public PrintWriter getWriter() throws IOException { | |||||
return printWriter; | |||||
} | |||||
@Override | |||||
public void flushBuffer() throws IOException { | |||||
if (servletOutputStream != null) { | |||||
servletOutputStream.flush(); | |||||
} | |||||
if (printWriter != null) { | |||||
printWriter.flush(); | |||||
} | |||||
} | |||||
@Override | |||||
public void reset() { | |||||
byteArrayOutputStream.reset(); | |||||
} | |||||
/** | |||||
* 获取json返回值 | |||||
* @return | |||||
* @throws IOException | |||||
*/ | |||||
public String getResponseBody() throws IOException { | |||||
//清空response的流,之后再添加进去 | |||||
flushBuffer(); | |||||
byte[] bytes = byteArrayOutputStream.toByteArray(); | |||||
try { | |||||
return new String(bytes, "UTF-8"); | |||||
} catch (UnsupportedEncodingException e) { | |||||
LogUtil.error(LogEnum.GLOBAL_REQ, e); | |||||
} finally { | |||||
response.getOutputStream().write(bytes); | |||||
} | |||||
return ""; | |||||
} | |||||
/** | |||||
* 清掉缓冲 | |||||
* @throws IOException | |||||
*/ | |||||
public void flush() throws IOException { | |||||
//清空response的流,之后再添加进去 | |||||
flushBuffer(); | |||||
byte[] bytes = byteArrayOutputStream.toByteArray(); | |||||
response.getOutputStream().write(bytes); | |||||
} | |||||
} |
@@ -24,7 +24,7 @@ import org.springframework.stereotype.Component; | |||||
import java.sql.Timestamp; | import java.sql.Timestamp; | ||||
/** | /** | ||||
* @description: 转换时间戳类型 | |||||
* @description 转换时间戳类型 | |||||
* @date 2020-05-22 | * @date 2020-05-22 | ||||
*/ | */ | ||||
@Component | @Component | ||||
@@ -0,0 +1,47 @@ | |||||
/** | |||||
* Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||||
* | |||||
* 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.dubhe.dao; | |||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper; | |||||
import org.apache.ibatis.annotations.Param; | |||||
import org.apache.ibatis.annotations.Select; | |||||
import org.dubhe.domain.dto.ModelQueryDTO; | |||||
import org.dubhe.domain.entity.ModelQuery; | |||||
import org.dubhe.domain.entity.ModelQueryBrance; | |||||
/** | |||||
* @description model mapper | |||||
* @date 2020-10-09 | |||||
*/ | |||||
public interface ModelQueryMapper extends BaseMapper<ModelQueryDTO> { | |||||
/** | |||||
* 根据modelId查询模型信息 | |||||
* | |||||
* @param modelId 模型id | |||||
* @return modelQuery返回查询的模型对象 | |||||
*/ | |||||
@Select("select name,url from pt_model_info where id=#{modelId}") | |||||
ModelQuery findModelNameById(@Param("modelId") Integer modelId); | |||||
/** | |||||
* 根据模型路径查询模型版本信息 | |||||
* | |||||
* @param modelLoadPathDir 模型路径 | |||||
* @return ModelQueryBrance 模型版本信息 | |||||
*/ | |||||
@Select("select version from pt_model_branch where url=#{modelLoadPathDir}") | |||||
ModelQueryBrance findModelVersionByUrl(@Param("modelLoadPathDir") String modelLoadPathDir); | |||||
} |
@@ -21,6 +21,7 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper; | |||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; | ||||
import org.apache.ibatis.annotations.Param; | import org.apache.ibatis.annotations.Param; | ||||
import org.apache.ibatis.annotations.Select; | import org.apache.ibatis.annotations.Select; | ||||
import org.dubhe.annotation.DataPermission; | |||||
import org.dubhe.domain.entity.NoteBook; | import org.dubhe.domain.entity.NoteBook; | ||||
import java.util.List; | import java.util.List; | ||||
@@ -29,28 +30,27 @@ import java.util.List; | |||||
* @description notebook mapper | * @description notebook mapper | ||||
* @date 2020-04-28 | * @date 2020-04-28 | ||||
*/ | */ | ||||
@DataPermission(ignoresMethod = {"insert","findByNamespaceAndResourceName","selectRunNotUrlList"}) | |||||
public interface NoteBookMapper extends BaseMapper<NoteBook> { | public interface NoteBookMapper extends BaseMapper<NoteBook> { | ||||
/** | /** | ||||
* 根据名称查询 | * 根据名称查询 | ||||
* | * | ||||
* @param name | * @param name | ||||
* @param userId | |||||
* @param status | * @param status | ||||
* @return NoteBook | * @return NoteBook | ||||
*/ | */ | ||||
@Select("select * from notebook where notebook_name = #{name} and user_id = #{userId} and status != #{status} and deleted = 0 limit 1") | |||||
NoteBook findByNameAndUserId(@Param("name") String name, @Param("userId") long userId, @Param("status") Integer status); | |||||
@Select("select * from notebook where notebook_name = #{name} and status != #{status} and deleted = 0 limit 1") | |||||
NoteBook findByNameAndStatus(@Param("name") String name, @Param("status") Integer status); | |||||
/** | /** | ||||
* 查询正在运行的notebook数量 | * 查询正在运行的notebook数量 | ||||
* | * | ||||
* @param userId | |||||
* @param status | * @param status | ||||
* @return int | * @return int | ||||
*/ | */ | ||||
@Select("select count(1) from notebook where user_id = #{userId} and status = #{status} and deleted = 0") | |||||
int selectRunNoteBookNum(@Param("userId") long userId, @Param("status") Integer status); | |||||
@Select("select count(1) from notebook where status = #{status} and deleted = 0") | |||||
int selectRunNoteBookNum( @Param("status") Integer status); | |||||
/** | /** | ||||
* 根据namespace + resourceName查询 | * 根据namespace + resourceName查询 | ||||
@@ -19,12 +19,14 @@ package org.dubhe.dao; | |||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper; | import com.baomidou.mybatisplus.core.mapper.BaseMapper; | ||||
import org.dubhe.annotation.DataPermission; | |||||
import org.dubhe.domain.entity.PtImage; | import org.dubhe.domain.entity.PtImage; | ||||
/** | /** | ||||
* @description 镜像 Mapper 接口 | * @description 镜像 Mapper 接口 | ||||
* @date 2020-04-27 | * @date 2020-04-27 | ||||
*/ | */ | ||||
@DataPermission(ignoresMethod = {"insert"}) | |||||
public interface PtImageMapper extends BaseMapper<PtImage> { | public interface PtImageMapper extends BaseMapper<PtImage> { | ||||
} | } |
@@ -20,6 +20,7 @@ package org.dubhe.dao; | |||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper; | import com.baomidou.mybatisplus.core.mapper.BaseMapper; | ||||
import org.apache.ibatis.annotations.Param; | import org.apache.ibatis.annotations.Param; | ||||
import org.apache.ibatis.annotations.Select; | import org.apache.ibatis.annotations.Select; | ||||
import org.dubhe.annotation.DataPermission; | |||||
import org.dubhe.domain.entity.PtTrainAlgorithm; | import org.dubhe.domain.entity.PtTrainAlgorithm; | ||||
import java.util.List; | import java.util.List; | ||||
@@ -28,6 +29,7 @@ import java.util.List; | |||||
* @description 训练算法Mapper | * @description 训练算法Mapper | ||||
* @date 2020-04-27 | * @date 2020-04-27 | ||||
*/ | */ | ||||
@DataPermission(ignoresMethod = {"insert"}) | |||||
public interface PtTrainAlgorithmMapper extends BaseMapper<PtTrainAlgorithm> { | public interface PtTrainAlgorithmMapper extends BaseMapper<PtTrainAlgorithm> { | ||||
/** | /** | ||||
@@ -17,17 +17,17 @@ | |||||
package org.dubhe.dao; | package org.dubhe.dao; | ||||
import org.dubhe.annotation.DataPermission; | |||||
import org.dubhe.domain.entity.PtTrainAlgorithmUsage; | import org.dubhe.domain.entity.PtTrainAlgorithmUsage; | ||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper; | import com.baomidou.mybatisplus.core.mapper.BaseMapper; | ||||
/** | /** | ||||
* | * | ||||
* 用户辅助信息Mapper 接口 | |||||
* </p> | |||||
* | |||||
* @since 2020-06-23 | |||||
* @description 用户辅助信息Mapper 接口 | |||||
* @date 2020-06-23 | |||||
*/ | */ | ||||
@DataPermission(ignoresMethod = "insert") | |||||
public interface PtTrainAlgorithmUsageMapper extends BaseMapper<PtTrainAlgorithmUsage> { | public interface PtTrainAlgorithmUsageMapper extends BaseMapper<PtTrainAlgorithmUsage> { | ||||
} | } |
@@ -21,6 +21,7 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper; | |||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; | ||||
import org.apache.ibatis.annotations.Param; | import org.apache.ibatis.annotations.Param; | ||||
import org.apache.ibatis.annotations.Select; | import org.apache.ibatis.annotations.Select; | ||||
import org.dubhe.annotation.DataPermission; | |||||
import org.dubhe.domain.entity.PtTrainJob; | import org.dubhe.domain.entity.PtTrainJob; | ||||
import org.dubhe.domain.vo.PtTrainVO; | import org.dubhe.domain.vo.PtTrainVO; | ||||
@@ -28,6 +29,7 @@ import org.dubhe.domain.vo.PtTrainVO; | |||||
* @description 训练作业job Mapper 接口 | * @description 训练作业job Mapper 接口 | ||||
* @date 2020-04-27 | * @date 2020-04-27 | ||||
*/ | */ | ||||
@DataPermission(ignoresMethod = {"insert","selectCountByStatus","getPageTrain"}) | |||||
public interface PtTrainJobMapper extends BaseMapper<PtTrainJob> { | public interface PtTrainJobMapper extends BaseMapper<PtTrainJob> { | ||||
/** | /** | ||||
@@ -18,12 +18,14 @@ | |||||
package org.dubhe.dao; | package org.dubhe.dao; | ||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper; | import com.baomidou.mybatisplus.core.mapper.BaseMapper; | ||||
import org.dubhe.annotation.DataPermission; | |||||
import org.dubhe.domain.entity.PtTrain; | import org.dubhe.domain.entity.PtTrain; | ||||
/** | /** | ||||
* @description 训练作业主 Mapper 接口 | * @description 训练作业主 Mapper 接口 | ||||
* @date 2020-04-27 | * @date 2020-04-27 | ||||
*/ | */ | ||||
@DataPermission(ignoresMethod = {"insert"}) | |||||
public interface PtTrainMapper extends BaseMapper<PtTrain> { | public interface PtTrainMapper extends BaseMapper<PtTrain> { | ||||
} | } |
@@ -17,6 +17,7 @@ | |||||
package org.dubhe.dao; | package org.dubhe.dao; | ||||
import org.dubhe.annotation.DataPermission; | |||||
import org.dubhe.domain.entity.PtTrainParam; | import org.dubhe.domain.entity.PtTrainParam; | ||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper; | import com.baomidou.mybatisplus.core.mapper.BaseMapper; | ||||
@@ -24,6 +25,7 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper; | |||||
* @description 任务参数 Mapper 接口 | * @description 任务参数 Mapper 接口 | ||||
* @date 2020-04-27 | * @date 2020-04-27 | ||||
*/ | */ | ||||
@DataPermission(ignoresMethod = "insert") | |||||
public interface PtTrainParamMapper extends BaseMapper<PtTrainParam> { | public interface PtTrainParamMapper extends BaseMapper<PtTrainParam> { | ||||
} | } |
@@ -40,4 +40,40 @@ public class BaseTrainJobDTO implements Serializable { | |||||
private String outPath; | private String outPath; | ||||
private String logPath; | private String logPath; | ||||
private String visualizedLogPath; | private String visualizedLogPath; | ||||
private Integer delayCreateTime; | |||||
private Integer delayDeleteTime; | |||||
/** | |||||
* @return 每个节点的GPU数量 | |||||
*/ | |||||
public Integer getGpuNumPerNode(){ | |||||
return getPtTrainJobSpecs().getSpecsInfo().getInteger("gpuNum"); | |||||
} | |||||
/** | |||||
* @return cpu数量 | |||||
*/ | |||||
public Integer getCpuNum(){ | |||||
return getPtTrainJobSpecs().getSpecsInfo().getInteger("cpuNum"); | |||||
} | |||||
/** | |||||
* @return memNum | |||||
*/ | |||||
public Integer getMenNum(){ | |||||
return getPtTrainJobSpecs().getSpecsInfo().getInteger("memNum"); | |||||
} | |||||
/** | |||||
* "验证数据来源名称" | |||||
*/ | |||||
private String valDataSourceName; | |||||
/** | |||||
* 验证数据来源路径 | |||||
*/ | |||||
private String valDataSourcePath; | |||||
/** | |||||
* 模型路径 | |||||
*/ | |||||
private String modelLoadPathDir; | |||||
} | } |
@@ -0,0 +1,39 @@ | |||||
/** | |||||
* Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||||
* | |||||
* 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.dubhe.domain.dto; | |||||
import io.swagger.annotations.ApiModel; | |||||
import io.swagger.annotations.ApiModelProperty; | |||||
import lombok.Data; | |||||
/** | |||||
* @description model 查询dto | |||||
* @date 2020-10-09 | |||||
*/ | |||||
@Data | |||||
@ApiModel("模型查询") | |||||
public class ModelQueryDTO { | |||||
@ApiModelProperty(value = "模型类型") | |||||
private Integer modelResource; | |||||
@ApiModelProperty(value = "模型名称") | |||||
private String name; | |||||
@ApiModelProperty(value = "模型版本") | |||||
private String version; | |||||
@ApiModelProperty(value = "模型id") | |||||
private Integer id; | |||||
@ApiModelProperty(value = "模型路径") | |||||
private String modelPath; | |||||
} |
@@ -30,7 +30,6 @@ import java.io.Serializable; | |||||
@Data | @Data | ||||
public class NoteBookListQueryDTO implements Serializable { | public class NoteBookListQueryDTO implements Serializable { | ||||
@Query(propName = "status", type = Query.Type.EQ) | |||||
@ApiModelProperty("0运行中,1停止, 2删除, 3启动中,4停止中,5删除中,6运行异常(暂未启用)") | @ApiModelProperty("0运行中,1停止, 2删除, 3启动中,4停止中,5删除中,6运行异常(暂未启用)") | ||||
private Integer status; | private Integer status; | ||||
@@ -38,7 +37,7 @@ public class NoteBookListQueryDTO implements Serializable { | |||||
@ApiModelProperty("notebook名称") | @ApiModelProperty("notebook名称") | ||||
private String noteBookName; | private String noteBookName; | ||||
@Query(propName = "user_id", type = Query.Type.EQ) | |||||
@Query(propName = "origin_user_id", type = Query.Type.EQ) | |||||
@ApiModelProperty(value = "所属用户ID", hidden = true) | @ApiModelProperty(value = "所属用户ID", hidden = true) | ||||
private Long userId; | private Long userId; | ||||
@@ -42,7 +42,7 @@ public class NoteBookQueryDTO implements Serializable { | |||||
@Query(propName = "k8s_pvc_path", type = Query.Type.EQ) | @Query(propName = "k8s_pvc_path", type = Query.Type.EQ) | ||||
private String k8sPvcPath; | private String k8sPvcPath; | ||||
@Query(propName = "user_id", type = Query.Type.EQ) | |||||
@Query(propName = "origin_user_id", type = Query.Type.EQ) | |||||
private Long userId; | private Long userId; | ||||
@Query(propName = "last_operation_timeout", type = Query.Type.LT) | @Query(propName = "last_operation_timeout", type = Query.Type.LT) | ||||
@@ -66,4 +66,6 @@ public class PtImageDTO implements Serializable { | |||||
@ApiModelProperty("删除(0正常,1已删除)") | @ApiModelProperty("删除(0正常,1已删除)") | ||||
private Boolean deleted; | private Boolean deleted; | ||||
@ApiModelProperty("资源拥有者ID") | |||||
private Long originUserId; | |||||
} | } |
@@ -0,0 +1,39 @@ | |||||
/** | |||||
* Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||||
* | |||||
* 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.dubhe.domain.dto; | |||||
import io.swagger.annotations.ApiModelProperty; | |||||
import lombok.Data; | |||||
import lombok.experimental.Accessors; | |||||
import javax.validation.constraints.NotNull; | |||||
import java.io.Serializable; | |||||
import java.util.List; | |||||
/** | |||||
* @description 训练镜像删除DTO | |||||
* @date 2020-08-13 | |||||
*/ | |||||
@Data | |||||
@Accessors(chain = true) | |||||
public class PtImageDeleteDTO implements Serializable { | |||||
private static final long serialVersionUID = 1L; | |||||
@ApiModelProperty(value = "id", required = true) | |||||
@NotNull(message = "镜像id不能为空") | |||||
private List<Long> ids; | |||||
} |
@@ -40,4 +40,7 @@ public class PtImageQueryDTO extends PageQueryBase implements Serializable { | |||||
@ApiModelProperty(value = "镜像状态,0为制作中,1位制作成功,2位制作失败") | @ApiModelProperty(value = "镜像状态,0为制作中,1位制作成功,2位制作失败") | ||||
private Integer imageStatus; | private Integer imageStatus; | ||||
@ApiModelProperty(value = "镜像名称或id") | |||||
private String imageNameOrId; | |||||
} | } |
@@ -0,0 +1,47 @@ | |||||
/** | |||||
* Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||||
* | |||||
* 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.dubhe.domain.dto; | |||||
import io.swagger.annotations.ApiModelProperty; | |||||
import lombok.Data; | |||||
import lombok.experimental.Accessors; | |||||
import org.dubhe.utils.TrainUtil; | |||||
import org.hibernate.validator.constraints.Length; | |||||
import javax.validation.constraints.NotNull; | |||||
import java.io.Serializable; | |||||
import java.util.List; | |||||
/** | |||||
* @description 训练镜像信息修改DTO | |||||
* @date 2020-08-13 | |||||
*/ | |||||
@Data | |||||
@Accessors(chain = true) | |||||
public class PtImageUpdateDTO implements Serializable { | |||||
private static final long serialVersionUID = 1L; | |||||
@ApiModelProperty(value = "id", required = true) | |||||
@NotNull(message = "镜像id不能为空") | |||||
private List<Long> ids; | |||||
@ApiModelProperty("镜像描述") | |||||
@Length(max = TrainUtil.NUMBER_ONE_THOUSAND_AND_TWENTY_FOUR, message = "镜像描述-输入长度不能超过1024个字符") | |||||
private String remark; | |||||
} |
@@ -55,7 +55,7 @@ public class PtImageUploadDTO implements Serializable { | |||||
@Pattern(regexp = TrainUtil.REGEXP_TAG, message = "镜像版本号支持字母、数字、英文横杠、英文.号和下划线") | @Pattern(regexp = TrainUtil.REGEXP_TAG, message = "镜像版本号支持字母、数字、英文横杠、英文.号和下划线") | ||||
private String imageTag; | private String imageTag; | ||||
@ApiModelProperty("备注") | |||||
@Length(max = TrainUtil.NUMBER_ONE_THOUSAND_AND_TWENTY_FOUR, message = "备注-输入长度不能超过1024个字符") | |||||
@ApiModelProperty("镜像描述") | |||||
@Length(max = TrainUtil.NUMBER_ONE_THOUSAND_AND_TWENTY_FOUR, message = "镜像描述-输入长度不能超过1024个字符") | |||||
private String remark; | private String remark; | ||||
} | } |
@@ -85,4 +85,7 @@ public class PtTrainAlgorithmCreateDTO implements Serializable { | |||||
@ApiModelProperty("noteBookId") | @ApiModelProperty("noteBookId") | ||||
private Long noteBookId; | private Long noteBookId; | ||||
@ApiModelProperty("资源拥有者ID") | |||||
private Long originUserId; | |||||
} | } |