@@ -0,0 +1,41 @@ | |||||
/** | |||||
* Copyright 2020 Tianshu AI Platform. 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.admin.client; | |||||
import org.dubhe.admin.client.fallback.ResourceQuotaClientFallback; | |||||
import org.dubhe.admin.domain.dto.UserConfigDTO; | |||||
import org.dubhe.biz.base.constant.ApplicationNameConst; | |||||
import org.dubhe.biz.base.vo.DataResponseBody; | |||||
import org.springframework.cloud.openfeign.FeignClient; | |||||
import org.springframework.web.bind.annotation.PostMapping; | |||||
import org.springframework.web.bind.annotation.RequestBody; | |||||
/** | |||||
* @description 远程调用资源配额 Client | |||||
* @date 2021-7-21 | |||||
*/ | |||||
@FeignClient(value = ApplicationNameConst.SERVER_K8S,fallback = ResourceQuotaClientFallback.class) | |||||
public interface ResourceQuotaClient { | |||||
/** | |||||
* 更新 ResourceQuota | |||||
* | |||||
* @param userConfigDTO 用户配置信息 | |||||
* @return | |||||
*/ | |||||
@PostMapping(value = "/resourceQuota/update") | |||||
DataResponseBody updateResourceQuota(@RequestBody UserConfigDTO userConfigDTO); | |||||
} |
@@ -0,0 +1,33 @@ | |||||
/** | |||||
* Copyright 2020 Tianshu AI Platform. 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.admin.client.fallback; | |||||
import org.dubhe.admin.client.ResourceQuotaClient; | |||||
import org.dubhe.admin.domain.dto.UserConfigDTO; | |||||
import org.dubhe.biz.base.vo.DataResponseBody; | |||||
import org.dubhe.biz.dataresponse.factory.DataResponseFactory; | |||||
/** | |||||
* @description ResourceQuotaClient 熔断处理 | |||||
* @date 2021-7-21 | |||||
*/ | |||||
public class ResourceQuotaClientFallback implements ResourceQuotaClient { | |||||
@Override | |||||
public DataResponseBody updateResourceQuota(UserConfigDTO userConfigDTO) { | |||||
return DataResponseFactory.failed("Call ResourceQuota server updateResourceQuota error"); | |||||
} | |||||
} |
@@ -0,0 +1,36 @@ | |||||
/** | |||||
* Copyright 2020 Tianshu AI Platform. 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.admin.dao; | |||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper; | |||||
import org.apache.ibatis.annotations.Select; | |||||
import org.dubhe.admin.domain.entity.UserConfig; | |||||
import java.util.List; | |||||
import org.apache.ibatis.annotations.Param; | |||||
/** | |||||
* @description 用户配置 Mapper | |||||
* @date 2021-6-30 | |||||
*/ | |||||
public interface UserConfigMapper extends BaseMapper<UserConfig> { | |||||
/** | |||||
* 插入或更新配置 | |||||
* @param userConfig 用户配置 | |||||
*/ | |||||
Long insertOrUpdate(UserConfig userConfig); | |||||
} |
@@ -0,0 +1,53 @@ | |||||
/** | |||||
* Copyright 2020 Tianshu AI Platform. 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.admin.domain.dto; | |||||
import io.swagger.annotations.ApiModelProperty; | |||||
import lombok.Data; | |||||
import org.hibernate.validator.constraints.Length; | |||||
import javax.validation.constraints.NotNull; | |||||
import java.io.Serializable; | |||||
/** | |||||
* @description 用户配置DTO | |||||
* @date 2021-7-1 | |||||
*/ | |||||
@Data | |||||
public class UserConfigDTO implements Serializable { | |||||
private static final long serialVersionUID = 1L; | |||||
@NotNull(message = "用户 ID 不能为空") | |||||
@ApiModelProperty("用户 ID") | |||||
private Long userId; | |||||
@NotNull(message = "Notebook 延迟删除时间配置不能为空") | |||||
@ApiModelProperty("Notebook 延迟删除时间配置,单位:小时") | |||||
private Integer notebookDelayDeleteTime; | |||||
@NotNull(message = "CPU 资源限制配置不能为空") | |||||
@ApiModelProperty("CPU 资源限制,单位:核") | |||||
private Integer cpuLimit; | |||||
@NotNull(message = "内存资源限制配置不能为空") | |||||
@ApiModelProperty("内存资源限制,单位:Gi") | |||||
private Integer memoryLimit; | |||||
@NotNull(message = "GPU 资源限制配置不能为空") | |||||
@ApiModelProperty("GPU 资源限制,单位:块") | |||||
private Integer gpuLimit; | |||||
} |
@@ -0,0 +1,48 @@ | |||||
/** | |||||
* Copyright 2020 Tianshu AI Platform. 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.admin.domain.entity; | |||||
import com.baomidou.mybatisplus.annotation.IdType; | |||||
import com.baomidou.mybatisplus.annotation.TableField; | |||||
import com.baomidou.mybatisplus.annotation.TableId; | |||||
import com.baomidou.mybatisplus.annotation.TableName; | |||||
import lombok.Data; | |||||
import lombok.experimental.Accessors; | |||||
import org.dubhe.biz.db.entity.BaseEntity; | |||||
/** | |||||
* @description 配置实体 | |||||
* @date 2021-06-30 | |||||
*/ | |||||
@Data | |||||
@TableName("config") | |||||
@Accessors(chain = true) | |||||
public class Config extends BaseEntity { | |||||
@TableId(value = "id", type = IdType.AUTO) | |||||
private Long id; | |||||
@TableField(value = "name") | |||||
private String name; | |||||
@TableField(value = "default_value") | |||||
private Integer defaultValue; | |||||
@TableField(value = "description") | |||||
private String description; | |||||
} |
@@ -0,0 +1,53 @@ | |||||
/** | |||||
* Copyright 2020 Tianshu AI Platform. 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.admin.domain.entity; | |||||
import com.baomidou.mybatisplus.annotation.IdType; | |||||
import com.baomidou.mybatisplus.annotation.TableField; | |||||
import com.baomidou.mybatisplus.annotation.TableId; | |||||
import com.baomidou.mybatisplus.annotation.TableName; | |||||
import lombok.Data; | |||||
import lombok.experimental.Accessors; | |||||
import org.dubhe.biz.db.entity.BaseEntity; | |||||
/** | |||||
* @description 用户配置实体 | |||||
* @date 2021-06-30 | |||||
*/ | |||||
@Data | |||||
@TableName("user_config") | |||||
@Accessors(chain = true) | |||||
public class UserConfig extends BaseEntity { | |||||
@TableId(value = "id", type = IdType.AUTO) | |||||
private Long id; | |||||
@TableId(value = "user_id") | |||||
private Long userId; | |||||
@TableId(value = "notebook_delay_delete_time") | |||||
private Integer notebookDelayDeleteTime; | |||||
@TableId(value = "cpu_limit") | |||||
private Integer cpuLimit; | |||||
@TableId(value = "memory_limit") | |||||
private Integer memoryLimit; | |||||
@TableId(value = "gpu_limit") | |||||
private Integer gpuLimit; | |||||
} |
@@ -0,0 +1,37 @@ | |||||
/** | |||||
* Copyright 2020 Tianshu AI Platform. 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.admin.domain.vo; | |||||
import io.swagger.annotations.ApiModelProperty; | |||||
import lombok.Data; | |||||
import lombok.experimental.Accessors; | |||||
import java.io.Serializable; | |||||
/** | |||||
* @description 用户配置创建返回 ID | |||||
* @date 2021-7-2 | |||||
*/ | |||||
@Data | |||||
@Accessors(chain = true) | |||||
public class UserConfigCreateVO implements Serializable{ | |||||
private static final long serialVersionUID = 1L; | |||||
@ApiModelProperty(value = "用户配置 ID") | |||||
private Long id; | |||||
} |
@@ -0,0 +1,48 @@ | |||||
/** | |||||
* Copyright 2020 Tianshu AI Platform. 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.admin.domain.vo; | |||||
import io.swagger.annotations.ApiModelProperty; | |||||
import lombok.Data; | |||||
import lombok.experimental.Accessors; | |||||
import java.io.Serializable; | |||||
/** | |||||
* @description 用户配置 VO | |||||
* @date 2021-7-1 | |||||
*/ | |||||
@Data | |||||
@Accessors(chain = true) | |||||
public class UserConfigVO implements Serializable { | |||||
private static final long serialVersionUID = 1L; | |||||
@ApiModelProperty("用户 ID") | |||||
private Long userId; | |||||
@ApiModelProperty("Notebook 延迟删除时间配置,单位:小时") | |||||
private Integer notebookDelayDeleteTime; | |||||
@ApiModelProperty("CPU 资源限制,单位:核") | |||||
private Integer cpuLimit; | |||||
@ApiModelProperty("内存资源限制,单位:Gi") | |||||
private Integer memoryLimit; | |||||
@ApiModelProperty("GPU 资源限制,单位:块") | |||||
private Integer gpuLimit; | |||||
} |
@@ -19,6 +19,7 @@ package org.dubhe.admin.rest; | |||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; | ||||
import io.swagger.annotations.Api; | import io.swagger.annotations.Api; | ||||
import io.swagger.annotations.ApiOperation; | import io.swagger.annotations.ApiOperation; | ||||
import org.dubhe.admin.domain.dto.UserConfigDTO; | |||||
import org.dubhe.admin.domain.dto.UserCreateDTO; | import org.dubhe.admin.domain.dto.UserCreateDTO; | ||||
import org.dubhe.admin.domain.dto.UserDeleteDTO; | import org.dubhe.admin.domain.dto.UserDeleteDTO; | ||||
import org.dubhe.admin.domain.dto.UserQueryDTO; | import org.dubhe.admin.domain.dto.UserQueryDTO; | ||||
@@ -30,6 +31,7 @@ import org.dubhe.biz.base.dto.UserDTO; | |||||
import org.dubhe.biz.base.vo.DataResponseBody; | import org.dubhe.biz.base.vo.DataResponseBody; | ||||
import org.springframework.beans.factory.annotation.Autowired; | import org.springframework.beans.factory.annotation.Autowired; | ||||
import org.springframework.security.access.prepost.PreAuthorize; | import org.springframework.security.access.prepost.PreAuthorize; | ||||
import org.springframework.validation.annotation.Validated; | |||||
import org.springframework.web.bind.annotation.*; | import org.springframework.web.bind.annotation.*; | ||||
import javax.servlet.http.HttpServletResponse; | import javax.servlet.http.HttpServletResponse; | ||||
@@ -84,6 +86,19 @@ public class UserController { | |||||
return new DataResponseBody(); | return new DataResponseBody(); | ||||
} | } | ||||
@ApiOperation("根据用户ID查询用户配置") | |||||
@GetMapping(value = "/getUserConfig") | |||||
public DataResponseBody getUserConfig(@RequestParam(value = "userId") Long userId) { | |||||
return new DataResponseBody(userService.findUserConfig(userId)); | |||||
} | |||||
@ApiOperation("新增或修改用户配置") | |||||
@PutMapping(value = "/setUserConfig") | |||||
@PreAuthorize(Permissions.USER_CONFIG_EDIT) | |||||
public DataResponseBody setUserConfig(@Validated @RequestBody UserConfigDTO userConfigDTO) { | |||||
return new DataResponseBody(userService.createOrUpdateUserConfig(userConfigDTO)); | |||||
} | |||||
/** | /** | ||||
* 此接口提供给Auth模块获取用户信息使用 | * 此接口提供给Auth模块获取用户信息使用 | ||||
* 因Auth获取用户信息在登录时是未登录状态,请不要在此添加权限校验 | * 因Auth获取用户信息在登录时是未登录状态,请不要在此添加权限校验 | ||||
@@ -20,6 +20,8 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page; | |||||
import com.baomidou.mybatisplus.extension.service.IService; | import com.baomidou.mybatisplus.extension.service.IService; | ||||
import org.dubhe.admin.domain.dto.*; | import org.dubhe.admin.domain.dto.*; | ||||
import org.dubhe.admin.domain.entity.User; | import org.dubhe.admin.domain.entity.User; | ||||
import org.dubhe.admin.domain.vo.UserConfigCreateVO; | |||||
import org.dubhe.admin.domain.vo.UserConfigVO; | |||||
import org.dubhe.biz.base.dto.TeamDTO; | import org.dubhe.biz.base.dto.TeamDTO; | ||||
import org.dubhe.biz.base.dto.UserDTO; | import org.dubhe.biz.base.dto.UserDTO; | ||||
import org.dubhe.biz.base.vo.DataResponseBody; | import org.dubhe.biz.base.vo.DataResponseBody; | ||||
@@ -221,4 +223,20 @@ public interface UserService extends AdminUserService, IService<User> { | |||||
* @return org.dubhe.domain.dto.UserDTO 用户信息DTO集合 | * @return org.dubhe.domain.dto.UserDTO 用户信息DTO集合 | ||||
*/ | */ | ||||
List<UserDTO> getUserList(List<Long> ids); | List<UserDTO> getUserList(List<Long> ids); | ||||
/** | |||||
* 根据用户 ID 查询用户配置 | |||||
* | |||||
* @param userId 用户 ID | |||||
* @return org.dubhe.admin.domain.vo.UserConfigVO 用户配置 VO | |||||
*/ | |||||
UserConfigVO findUserConfig(Long userId); | |||||
/** | |||||
* 创建或更新用户配置 | |||||
* | |||||
* @param userConfigDTO 用户配置 | |||||
* @return org.dubhe.admin.domain.vo.UserConfigCreateVO 用户配置 VO | |||||
*/ | |||||
UserConfigCreateVO createOrUpdateUserConfig(UserConfigDTO userConfigDTO); | |||||
} | } |
@@ -67,7 +67,7 @@ public class ResourceSpecsServiceImpl implements ResourceSpecsService { | |||||
public Map<String, Object> getResourceSpecs(ResourceSpecsQueryDTO resourceSpecsQueryDTO) { | public Map<String, Object> getResourceSpecs(ResourceSpecsQueryDTO resourceSpecsQueryDTO) { | ||||
Page page = resourceSpecsQueryDTO.toPage(); | Page page = resourceSpecsQueryDTO.toPage(); | ||||
//排序字段 | //排序字段 | ||||
String sort = null == resourceSpecsQueryDTO.getSort() ? StringConstant.CREATE_TIME_SQL : resourceSpecsQueryDTO.getSort(); | |||||
String sort = null == resourceSpecsQueryDTO.getSort() ? StringConstant.ID : resourceSpecsQueryDTO.getSort(); | |||||
QueryWrapper<ResourceSpecs> queryResourceSpecsWrapper = new QueryWrapper<>(); | QueryWrapper<ResourceSpecs> queryResourceSpecsWrapper = new QueryWrapper<>(); | ||||
queryResourceSpecsWrapper.like(resourceSpecsQueryDTO.getSpecsName() != null, "specs_name", resourceSpecsQueryDTO.getSpecsName()) | queryResourceSpecsWrapper.like(resourceSpecsQueryDTO.getSpecsName() != null, "specs_name", resourceSpecsQueryDTO.getSpecsName()) | ||||
.eq(resourceSpecsQueryDTO.getResourcesPoolType() != null, "resources_pool_type", resourceSpecsQueryDTO.getResourcesPoolType()) | .eq(resourceSpecsQueryDTO.getResourcesPoolType() != null, "resources_pool_type", resourceSpecsQueryDTO.getResourcesPoolType()) | ||||
@@ -22,17 +22,22 @@ import cn.hutool.crypto.asymmetric.KeyType; | |||||
import cn.hutool.crypto.asymmetric.RSA; | import cn.hutool.crypto.asymmetric.RSA; | ||||
import com.alibaba.fastjson.JSONObject; | import com.alibaba.fastjson.JSONObject; | ||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; | ||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; | |||||
import com.baomidou.mybatisplus.core.metadata.IPage; | import com.baomidou.mybatisplus.core.metadata.IPage; | ||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; | ||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; | ||||
import org.dubhe.admin.client.AuthServiceClient; | import org.dubhe.admin.client.AuthServiceClient; | ||||
import org.dubhe.admin.client.ResourceQuotaClient; | |||||
import org.dubhe.admin.dao.*; | import org.dubhe.admin.dao.*; | ||||
import org.dubhe.admin.domain.dto.*; | import org.dubhe.admin.domain.dto.*; | ||||
import org.dubhe.admin.domain.entity.Role; | import org.dubhe.admin.domain.entity.Role; | ||||
import org.dubhe.admin.domain.entity.User; | import org.dubhe.admin.domain.entity.User; | ||||
import org.dubhe.admin.domain.entity.UserAvatar; | import org.dubhe.admin.domain.entity.UserAvatar; | ||||
import org.dubhe.admin.domain.entity.UserConfig; | |||||
import org.dubhe.admin.domain.entity.UserRole; | import org.dubhe.admin.domain.entity.UserRole; | ||||
import org.dubhe.admin.domain.vo.EmailVo; | import org.dubhe.admin.domain.vo.EmailVo; | ||||
import org.dubhe.admin.domain.vo.UserConfigCreateVO; | |||||
import org.dubhe.admin.domain.vo.UserConfigVO; | |||||
import org.dubhe.admin.domain.vo.UserVO; | import org.dubhe.admin.domain.vo.UserVO; | ||||
import org.dubhe.admin.enums.UserMailCodeEnum; | import org.dubhe.admin.enums.UserMailCodeEnum; | ||||
import org.dubhe.admin.event.EmailEventPublisher; | import org.dubhe.admin.event.EmailEventPublisher; | ||||
@@ -92,6 +97,18 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us | |||||
@Value("${initial_password}") | @Value("${initial_password}") | ||||
private String initialPassword; | private String initialPassword; | ||||
@Value("${user.config.notebook-delay-delete-time}") | |||||
private Integer defaultNotebookDelayDeleteTime; | |||||
@Value("${user.config.cpu-limit}") | |||||
private Integer cpuLimit; | |||||
@Value("${user.config.memory-limit}") | |||||
private Integer memoryLimit; | |||||
@Value("${user.config.gpu-limit}") | |||||
private Integer gpuLimit; | |||||
@Autowired | @Autowired | ||||
private UserMapper userMapper; | private UserMapper userMapper; | ||||
@@ -130,6 +147,13 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us | |||||
@Autowired | @Autowired | ||||
private PermissionMapper permissionMapper; | private PermissionMapper permissionMapper; | ||||
@Autowired | |||||
private UserConfigMapper userConfigMapper; | |||||
@Autowired | |||||
ResourceQuotaClient resourceQuotaClient; | |||||
/** | /** | ||||
* 测试标识 true:允许debug false:拒绝debug | * 测试标识 true:允许debug false:拒绝debug | ||||
*/ | */ | ||||
@@ -224,7 +248,15 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us | |||||
for (Role role : resources.getRoles()) { | for (Role role : resources.getRoles()) { | ||||
roleMapper.tiedUserRole(user.getId(), role.getId()); | roleMapper.tiedUserRole(user.getId(), role.getId()); | ||||
} | } | ||||
UserConfigDTO userConfigDTO = new UserConfigDTO(); | |||||
userConfigDTO.setUserId(user.getId()); | |||||
userConfigDTO.setCpuLimit(cpuLimit); | |||||
userConfigDTO.setMemoryLimit(memoryLimit); | |||||
userConfigDTO.setGpuLimit(gpuLimit); | |||||
DataResponseBody dataResponseBody = resourceQuotaClient.updateResourceQuota(userConfigDTO); | |||||
if (!dataResponseBody.succeed()){ | |||||
throw new BusinessException("用户配置更新失败"); | |||||
} | |||||
return userConvert.toDto(user); | return userConvert.toDto(user); | ||||
} | } | ||||
@@ -316,10 +348,24 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us | |||||
return sysRoleDTO; | return sysRoleDTO; | ||||
}).collect(Collectors.toList())); | }).collect(Collectors.toList())); | ||||
} | } | ||||
//获取用户配置 | |||||
SysUserConfigDTO sysUserConfigDTO = getUserConfig(user.getId()); | |||||
dto.setUserConfig(sysUserConfigDTO); | |||||
return dto; | return dto; | ||||
} | } | ||||
private SysUserConfigDTO getUserConfig(Long userId) { | |||||
UserConfig userConfig = userConfigMapper.selectOne(new QueryWrapper<>(new UserConfig().setUserId(userId))); | |||||
SysUserConfigDTO sysUserConfigDTO= new SysUserConfigDTO(); | |||||
if (userConfig == null){ | |||||
return sysUserConfigDTO.setCpuLimit(cpuLimit).setMemoryLimit(memoryLimit) | |||||
.setGpuLimit(gpuLimit).setNotebookDelayDeleteTime(defaultNotebookDelayDeleteTime); | |||||
} | |||||
BeanUtils.copyProperties(userConfig, sysUserConfigDTO); | |||||
return sysUserConfigDTO; | |||||
} | |||||
/** | /** | ||||
* 修改用户个人中心信息 | * 修改用户个人中心信息 | ||||
@@ -695,6 +741,48 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us | |||||
return userConvert.toDto(users); | return userConvert.toDto(users); | ||||
} | } | ||||
/** | |||||
* 根据用户 ID 查询用户配置 | |||||
* | |||||
* @param userId 用户 ID | |||||
* @return org.dubhe.admin.domain.vo.UserConfigVO 用户配置 VO | |||||
*/ | |||||
@Override | |||||
public UserConfigVO findUserConfig(Long userId) { | |||||
// 查询用户配置 | |||||
UserConfig userConfig = userConfigMapper.selectOne(new QueryWrapper<>(new UserConfig().setUserId(userId))); | |||||
UserConfigVO userConfigVO = new UserConfigVO(); | |||||
// 如果用户配置为空,则返回 | |||||
if (userConfig == null){ | |||||
return userConfigVO.setUserId(userId).setCpuLimit(cpuLimit).setMemoryLimit(memoryLimit) | |||||
.setGpuLimit(gpuLimit).setNotebookDelayDeleteTime(defaultNotebookDelayDeleteTime); | |||||
} | |||||
// 封装用户配置 VO | |||||
BeanUtils.copyProperties(userConfig, userConfigVO); | |||||
return userConfigVO; | |||||
} | |||||
/** | |||||
* 创建或更新用户配置 | |||||
* | |||||
* @param userConfigDTO 用户配置 | |||||
* @return org.dubhe.admin.domain.vo.UserConfigCreateVO 用户配置 VO | |||||
*/ | |||||
@Override | |||||
@Transactional(rollbackFor = Exception.class) | |||||
public UserConfigCreateVO createOrUpdateUserConfig(UserConfigDTO userConfigDTO) { | |||||
DataResponseBody dataResponseBody = resourceQuotaClient.updateResourceQuota(userConfigDTO); | |||||
if (!dataResponseBody.succeed()){ | |||||
throw new BusinessException("用户配置更新失败"); | |||||
} | |||||
UserConfig userConfig = new UserConfig(); | |||||
BeanUtils.copyProperties(userConfigDTO, userConfig); | |||||
userConfigMapper.insertOrUpdate(userConfig); | |||||
// 封装用户配置 VO | |||||
UserConfigCreateVO userConfigCreateVO = new UserConfigCreateVO().setId(userConfig.getId()); | |||||
return userConfigCreateVO; | |||||
} | |||||
/** | /** | ||||
* 校验验证码 | * 校验验证码 | ||||
@@ -900,8 +988,9 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us | |||||
}).collect(Collectors.toList()); | }).collect(Collectors.toList()); | ||||
dto.setRoles(roleDTOS); | dto.setRoles(roleDTOS); | ||||
} | } | ||||
//获取用户配置 | |||||
SysUserConfigDTO sysUserConfigDTO = getUserConfig(user.getId()); | |||||
dto.setUserConfig(sysUserConfigDTO); | |||||
return DataResponseFactory.success(dto); | return DataResponseFactory.success(dto); | ||||
} | } | ||||
} | } |
@@ -31,7 +31,7 @@ spring: | |||||
refresh: true | refresh: true | ||||
discovery: | discovery: | ||||
enabled: true | enabled: true | ||||
namespace: dubhe-server-cloud-prod | |||||
namespace: dubhe-server-cloud-dev | |||||
group: dubhe | group: dubhe | ||||
server-addr: 127.0.0.1:8848 | server-addr: 127.0.0.1:8848 | ||||
@@ -0,0 +1,100 @@ | |||||
<?xml version="1.0" encoding="UTF-8" ?> | |||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > | |||||
<mapper namespace="org.dubhe.admin.dao.UserConfigMapper"> | |||||
<!--保存用户配置--> | |||||
<insert id="insertOrUpdate" parameterType="org.dubhe.admin.domain.entity.UserConfig"> | |||||
<selectKey resultType="java.lang.Long" order="AFTER" keyProperty="id"> | |||||
SELECT id FROM user_config WHERE user_id = #{userId} | |||||
</selectKey> | |||||
insert into user_config | |||||
<trim prefix="(" suffix=")" suffixOverrides=","> | |||||
<if test="userId != null"> | |||||
user_id, | |||||
</if> | |||||
<if test="notebookDelayDeleteTime != null"> | |||||
notebook_delay_delete_time, | |||||
</if> | |||||
<if test="cpuLimit != null"> | |||||
cpu_limit, | |||||
</if> | |||||
<if test="memoryLimit != null"> | |||||
memory_limit, | |||||
</if> | |||||
<if test="gpuLimit != null"> | |||||
gpu_limit, | |||||
</if> | |||||
<if test="createUserId != null"> | |||||
create_user_id, | |||||
</if> | |||||
<if test="updateTime != null"> | |||||
update_time, | |||||
</if> | |||||
<if test="updateUserId != null"> | |||||
update_user_id, | |||||
</if> | |||||
<if test="deleted != null"> | |||||
deleted, | |||||
</if> | |||||
</trim> | |||||
<trim prefix="values (" suffix=")" suffixOverrides=","> | |||||
<if test="userId != null"> | |||||
#{userId}, | |||||
</if> | |||||
<if test="notebookDelayDeleteTime != null"> | |||||
#{notebookDelayDeleteTime}, | |||||
</if> | |||||
<if test="cpuLimit != null"> | |||||
#{cpuLimit}, | |||||
</if> | |||||
<if test="memoryLimit != null"> | |||||
#{memoryLimit}, | |||||
</if> | |||||
<if test="gpuLimit != null"> | |||||
#{gpuLimit}, | |||||
</if> | |||||
<if test="createUserId != null"> | |||||
#{createUserId}, | |||||
</if> | |||||
<if test="updateTime != null"> | |||||
#{updateTime}, | |||||
</if> | |||||
<if test="updateUserId != null"> | |||||
#{updateUserId}, | |||||
</if> | |||||
<if test="deleted != null"> | |||||
#{deleted}, | |||||
</if> | |||||
</trim> | |||||
ON DUPLICATE KEY UPDATE | |||||
<trim suffixOverrides=","> | |||||
<if test="notebookDelayDeleteTime != null"> | |||||
notebook_delay_delete_time = #{notebookDelayDeleteTime}, | |||||
</if> | |||||
<if test="cpuLimit != null"> | |||||
cpu_limit = #{cpuLimit}, | |||||
</if> | |||||
<if test="memoryLimit != null"> | |||||
memory_limit = #{memoryLimit}, | |||||
</if> | |||||
<if test="gpuLimit != null"> | |||||
gpu_limit = #{gpuLimit}, | |||||
</if> | |||||
<if test="createTime != null"> | |||||
create_time = #{createTime}, | |||||
</if> | |||||
<if test="createUserId != null"> | |||||
create_user_id = #{createUserId}, | |||||
</if> | |||||
<if test="updateTime != null"> | |||||
update_time = #{updateTime}, | |||||
</if> | |||||
<if test="updateUserId != null"> | |||||
update_user_id = #{updateUserId}, | |||||
</if> | |||||
<if test="deleted != null"> | |||||
deleted = #{deleted}, | |||||
</if> | |||||
</trim> | |||||
</insert> | |||||
</mapper> |
@@ -23,7 +23,7 @@ spring: | |||||
refresh: true | refresh: true | ||||
discovery: | discovery: | ||||
enabled: true | enabled: true | ||||
namespace: dubhe-server-cloud-prod | |||||
namespace: dubhe-server-cloud-dev | |||||
group: dubhe | group: dubhe | ||||
server-addr: 127.0.0.1:8848 | server-addr: 127.0.0.1:8848 | ||||
@@ -81,4 +81,13 @@ public class ApplicationNameConst { | |||||
*/ | */ | ||||
public final static String SERVER_DATA_DCM = "dubhe-data-dcm"; | public final static String SERVER_DATA_DCM = "dubhe-data-dcm"; | ||||
/** | |||||
* k8s | |||||
*/ | |||||
public final static String SERVER_K8S = "dubhe-k8s"; | |||||
/** | |||||
* 专业版终端 | |||||
*/ | |||||
public final static String TERMINAL = "dubhe-terminal"; | |||||
} | } |
@@ -56,7 +56,7 @@ public class AuthConst { | |||||
public final static String[] DEFAULT_PERMIT_PATHS = {"/swagger**/**", "/webjars/**", "/v2/api-docs/**", "/doc.html/**", | public final static String[] DEFAULT_PERMIT_PATHS = {"/swagger**/**", "/webjars/**", "/v2/api-docs/**", "/doc.html/**", | ||||
"/users/findUserByUsername", "/auth/login", "/auth/code", | "/users/findUserByUsername", "/auth/login", "/auth/code", | ||||
"/datasets/files/annotations/auto","/datasets/versions/**/convert/finish", "/datasets/enhance/finish", | "/datasets/files/annotations/auto","/datasets/versions/**/convert/finish", "/datasets/enhance/finish", | ||||
"/auth/getCodeBySentEmail","/auth/userRegister", | |||||
"/auth/getCodeBySentEmail","/auth/userRegister","/ws/**", | |||||
StringConstant.RECYCLE_CALL_URI+"**" | StringConstant.RECYCLE_CALL_URI+"**" | ||||
}; | }; | ||||
@@ -39,6 +39,7 @@ public final class MagicNumConstant { | |||||
public static final int ELEVEN = 11; | public static final int ELEVEN = 11; | ||||
public static final int SIXTEEN = 16; | public static final int SIXTEEN = 16; | ||||
public static final int TWENTY = 20; | public static final int TWENTY = 20; | ||||
public static final int TWENTY_TWO = 22; | |||||
public static final int THIRTY_TWO = 32; | public static final int THIRTY_TWO = 32; | ||||
public static final int FIFTY = 50; | public static final int FIFTY = 50; | ||||
public static final int SIXTY = 60; | public static final int SIXTY = 60; | ||||
@@ -43,6 +43,7 @@ public class NumberConstant { | |||||
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; | ||||
public final static int MONTH_SECOND = 60 * 60 * 24 * 30; | |||||
public final static int MAX_PAGE_SIZE = 2000; | public final static int MAX_PAGE_SIZE = 2000; | ||||
public final static int MAX_MESSAGE_LENGTH = 1024 * 1024 * 1024; | public final static int MAX_MESSAGE_LENGTH = 1024 * 1024 * 1024; | ||||
} | } |
@@ -140,6 +140,8 @@ public final class Permissions { | |||||
public static final String USER_EDIT = "hasAuthority('ROLE_system:user:edit')"; | public static final String USER_EDIT = "hasAuthority('ROLE_system:user:edit')"; | ||||
public static final String USER_DELETE = "hasAuthority('ROLE_system:user:delete')"; | public static final String USER_DELETE = "hasAuthority('ROLE_system:user:delete')"; | ||||
public static final String USER_DOWNLOAD = "hasAuthority('ROLE_system:user:download')"; | public static final String USER_DOWNLOAD = "hasAuthority('ROLE_system:user:download')"; | ||||
public static final String USER_CONFIG_EDIT = "hasAuthority('ROLE_system:user:configEdit')"; | |||||
public static final String USER_RESOURCE_INFO = "hasAuthority('ROLE_system:user:resourceInfo')"; | |||||
/** | /** | ||||
* 控制台:角色管理 | * 控制台:角色管理 | ||||
@@ -200,6 +202,16 @@ public final class Permissions { | |||||
public static final String SPECS_EDIT = "hasAuthority('ROLE_system:specs:edit')"; | public static final String SPECS_EDIT = "hasAuthority('ROLE_system:specs:edit')"; | ||||
public static final String SPECS_DELETE = "hasAuthority('ROLE_system:specs:delete')"; | public static final String SPECS_DELETE = "hasAuthority('ROLE_system:specs:delete')"; | ||||
/** | |||||
* 专业版:终端 | |||||
*/ | |||||
public static final String TERMINAL_CREATE = "hasAuthority('ROLE_terminal:specs:create')"; | |||||
public static final String TERMINAL_RESTART = "hasAuthority('ROLE_terminal:specs:restart')"; | |||||
public static final String TERMINAL_PRESAVE = "hasAuthority('ROLE_terminal:specs:save')"; | |||||
public static final String TERMINAL_DELETE = "hasAuthority('ROLE_terminal:specs:delete')"; | |||||
public static final String TERMINAL_DETAIL = "hasAuthority('ROLE_terminal:specs:detail')"; | |||||
public static final String TERMINAL_LIST = "hasAuthority('ROLE_terminal:specs:list')"; | |||||
private Permissions() { | private Permissions() { | ||||
} | } | ||||
} | } |
@@ -79,6 +79,9 @@ public final class StringConstant { | |||||
public static final String RECYCLE_CALL_URI = "/api/recycle/call/"; | public static final String RECYCLE_CALL_URI = "/api/recycle/call/"; | ||||
public static final String K8S_CALLBACK_PATH_DEPLOYMENT = "/api/k8s/callback/deployment"; | public static final String K8S_CALLBACK_PATH_DEPLOYMENT = "/api/k8s/callback/deployment"; | ||||
public static final String MULTIPART = "multipart/form-data"; | public static final String MULTIPART = "multipart/form-data"; | ||||
public static final String PIP_SITE_PACKAGE ="pip-site-package"; | |||||
/** | /** | ||||
* 分页内容 | * 分页内容 | ||||
*/ | */ | ||||
@@ -105,9 +108,10 @@ public final class StringConstant { | |||||
public static final String STEP_LOW = "step"; | public static final String STEP_LOW = "step"; | ||||
/** | /** | ||||
* 测试环境 | |||||
* 任务缓存 | |||||
*/ | */ | ||||
public static final String PROFILE_ACTIVE_TEST = "test"; | |||||
public static final String CACHE_TASK_ID ="task_id"; | |||||
public static final String CACHE_TASK_NAME ="task_name"; | |||||
private StringConstant() { | private StringConstant() { | ||||
@@ -48,6 +48,8 @@ public class SymbolConstant { | |||||
public static final String EVENT_SEPARATOR = "&&"; | public static final String EVENT_SEPARATOR = "&&"; | ||||
public static final String POST = "POST"; | public static final String POST = "POST"; | ||||
public static final String HTTP_SLASH = "http://"; | public static final String HTTP_SLASH = "http://"; | ||||
public static final String PORT = "port"; | |||||
public static final String LOCAL_HOST = "localhost"; | |||||
private SymbolConstant() { | private SymbolConstant() { | ||||
} | } | ||||
@@ -91,4 +91,14 @@ public class UserConstant { | |||||
*/ | */ | ||||
public final static int REGISTER_ROLE_ID = 2; | public final static int REGISTER_ROLE_ID = 2; | ||||
/** | |||||
* 默认资源用户ID | |||||
*/ | |||||
public final static Long DEFAULT_ORIGIN_USER_ID = 0L; | |||||
/** | |||||
* 默认创建人ID | |||||
*/ | |||||
public final static Long DEFAULT_CREATE_USER_ID = 0L; | |||||
} | } |
@@ -18,6 +18,7 @@ package org.dubhe.biz.base.context; | |||||
import lombok.Data; | import lombok.Data; | ||||
import org.dubhe.biz.base.dto.SysRoleDTO; | import org.dubhe.biz.base.dto.SysRoleDTO; | ||||
import org.dubhe.biz.base.dto.SysUserConfigDTO; | |||||
import java.io.Serializable; | import java.io.Serializable; | ||||
import java.util.List; | import java.util.List; | ||||
@@ -72,5 +73,9 @@ public class UserContext implements Serializable { | |||||
* 头像路径 | * 头像路径 | ||||
*/ | */ | ||||
private String userAvatarPath; | private String userAvatarPath; | ||||
/** | |||||
* 用户配置 | |||||
*/ | |||||
private SysUserConfigDTO userConfig; | |||||
} | } |
@@ -0,0 +1,53 @@ | |||||
/** | |||||
* Copyright 2020 Tianshu AI Platform. 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.biz.base.dto; | |||||
import lombok.Data; | |||||
import lombok.experimental.Accessors; | |||||
import java.io.Serializable; | |||||
/** | |||||
* @description 系统用户配置 DTO | |||||
* @date 2021-7-5 | |||||
*/ | |||||
@Data | |||||
@Accessors(chain = true) | |||||
public class SysUserConfigDTO implements Serializable{ | |||||
private static final long serialVersionUID = 1L; | |||||
/** | |||||
* Notebook 延迟删除时间配置 | |||||
*/ | |||||
private Integer notebookDelayDeleteTime; | |||||
/** | |||||
* CPU 资源限制配置 | |||||
*/ | |||||
private Integer cpuLimit; | |||||
/** | |||||
* 内存资源限制配置 | |||||
*/ | |||||
private Integer memoryLimit; | |||||
/** | |||||
* GPU 资源限制配置 | |||||
*/ | |||||
private Integer gpuLimit; | |||||
} |
@@ -59,5 +59,10 @@ public class UserDTO implements Serializable { | |||||
*/ | */ | ||||
private List<SysRoleDTO> roles; | private List<SysRoleDTO> roles; | ||||
/** | |||||
* 用户配置 | |||||
*/ | |||||
private SysUserConfigDTO userConfig; | |||||
} | } |
@@ -56,7 +56,12 @@ public enum BizEnum { | |||||
/** | /** | ||||
* 度量管理 | * 度量管理 | ||||
*/ | */ | ||||
MEASURE("度量管理", "measure", 5); | |||||
MEASURE("度量管理", "measure", 5), | |||||
/** | |||||
* 专业版终端 | |||||
*/ | |||||
TERMINAL("专业版终端", "terminal", 7), | |||||
; | |||||
/** | /** | ||||
* 业务模块名称 | * 业务模块名称 | ||||
@@ -42,7 +42,13 @@ public enum ImageTypeEnum { | |||||
/** | /** | ||||
* Serving镜像 | * Serving镜像 | ||||
*/ | */ | ||||
SERVING("Serving镜像", "serving", 2); | |||||
SERVING("Serving镜像", "serving", 2), | |||||
/** | |||||
* terminal镜像 | |||||
*/ | |||||
TERMINAL("terminal镜像", "terminal", 3) | |||||
; | |||||
/** | /** | ||||
* 镜像项目名称 | * 镜像项目名称 | ||||
@@ -0,0 +1,60 @@ | |||||
/** | |||||
* Copyright 2020 Tianshu AI Platform. 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.biz.base.utils; | |||||
import cn.hutool.core.util.StrUtil; | |||||
import org.dubhe.biz.base.exception.BusinessException; | |||||
/** | |||||
* 调用结果处理工具类 | |||||
* | |||||
*/ | |||||
public class ResultUtil { | |||||
/** | |||||
* 判断调用结果非空 | |||||
* | |||||
* @param object | |||||
* @param errorMessageTemplate | |||||
* @param params | |||||
*/ | |||||
public static void notNull(Object object, String errorMessageTemplate, Object... params) { | |||||
if (object == null) { | |||||
throw new BusinessException(StrUtil.format(errorMessageTemplate, params)); | |||||
} | |||||
} | |||||
/** | |||||
* 判断调用结果相等 | |||||
* | |||||
* @param object1 | |||||
* @param object2 | |||||
* @param errorMessageTemplate | |||||
* @param params | |||||
*/ | |||||
public static void isEquals(Object object1, Object object2, String errorMessageTemplate, Object... params) { | |||||
if(object1 == null) { | |||||
if (object2 == null) { | |||||
return; | |||||
} | |||||
throw new BusinessException(String.format(errorMessageTemplate, params)); | |||||
} | |||||
if (!object1.equals(object2)) { | |||||
throw new BusinessException(String.format(errorMessageTemplate, params)); | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,139 @@ | |||||
/** | |||||
* Copyright 2020 Tianshu AI Platform. 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.biz.base.vo; | |||||
import lombok.Data; | |||||
import java.io.Serializable; | |||||
import java.util.Date; | |||||
/** | |||||
* @description 返回前端请求体 | |||||
* @date 2020-04-28 | |||||
*/ | |||||
@Data | |||||
public class NoteBookVO implements Serializable { | |||||
/** | |||||
* ID | |||||
*/ | |||||
private Long id; | |||||
/** | |||||
* 所属用户 | |||||
*/ | |||||
private Long userId; | |||||
/** | |||||
* NoteBook 名称 | |||||
*/ | |||||
private String name; | |||||
/** | |||||
* NoteBook 名称 | |||||
*/ | |||||
private String noteBookName; | |||||
/** | |||||
* 备注描述 | |||||
*/ | |||||
private String description; | |||||
/** | |||||
* 可访问jupyter地址 | |||||
*/ | |||||
private String url; | |||||
/** | |||||
* CPU数量 | |||||
*/ | |||||
private Integer cpuNum; | |||||
/** | |||||
* GPU数量 | |||||
*/ | |||||
private Integer gpuNum; | |||||
/** | |||||
* 内存大小(M) | |||||
*/ | |||||
private Integer memNum; | |||||
/** | |||||
* 硬盘内存大小(M) | |||||
*/ | |||||
private Integer diskMemNum; | |||||
/** | |||||
* 0运行,1停止, 2删除, 3启动中,4停止中,5删除中,6运行异常(暂未启用) | |||||
*/ | |||||
private Integer status; | |||||
/** | |||||
* 状态对应的详情信息 | |||||
*/ | |||||
private String statusDetail; | |||||
/** | |||||
* k8s响应状态码 | |||||
*/ | |||||
private String k8sStatusCode; | |||||
/** | |||||
* k8s响应状态信息 | |||||
*/ | |||||
private String k8sStatusInfo; | |||||
private String k8sImageName; | |||||
/** | |||||
* k8s中pvc存储路径 | |||||
*/ | |||||
private String k8sPvcPath; | |||||
private Date createTime; | |||||
private Date updateTime; | |||||
/** | |||||
* 数据集名称 | |||||
*/ | |||||
private String dataSourceName; | |||||
/** | |||||
* 数据集路径 | |||||
*/ | |||||
private String dataSourcePath; | |||||
/** | |||||
* 算法ID | |||||
*/ | |||||
private Long algorithmId; | |||||
/** | |||||
* 资源拥有者ID | |||||
*/ | |||||
private Long originUserId; | |||||
/** | |||||
* pip包路径 | |||||
*/ | |||||
private String pipSitePackagePath; | |||||
} |
@@ -0,0 +1,84 @@ | |||||
/** | |||||
* Copyright 2020 Tianshu AI Platform. 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.biz.base.vo; | |||||
import lombok.Data; | |||||
import org.dubhe.biz.base.constant.ResponseCode; | |||||
import org.slf4j.MDC; | |||||
import java.io.Serializable; | |||||
/** | |||||
* @description Websocket 统一的公共响应体 | |||||
* @date 2021-07-20 | |||||
*/ | |||||
@Data | |||||
public class WebsocketDataResponseBody<T> implements Serializable { | |||||
/** | |||||
* 返回状态码 | |||||
*/ | |||||
private Integer code; | |||||
/** | |||||
* 返回信息 | |||||
*/ | |||||
private String msg; | |||||
/** | |||||
* 返回主题 | |||||
*/ | |||||
private String topic; | |||||
/** | |||||
* 泛型数据 | |||||
*/ | |||||
private T data; | |||||
/** | |||||
* 链路追踪ID | |||||
*/ | |||||
private String traceId; | |||||
public WebsocketDataResponseBody() { | |||||
this(ResponseCode.SUCCESS, null,null); | |||||
} | |||||
public WebsocketDataResponseBody(String topic, T data) { | |||||
this(ResponseCode.SUCCESS, null, topic, data); | |||||
} | |||||
public WebsocketDataResponseBody(Integer code, String msg, String topic) { | |||||
this(code, msg, topic, null); | |||||
} | |||||
public WebsocketDataResponseBody(Integer code, String msg, String topic, T data) { | |||||
this.code = code; | |||||
this.msg = msg; | |||||
this.topic = topic; | |||||
this.data = data; | |||||
this.traceId = MDC.get("traceId"); | |||||
} | |||||
/** | |||||
* 判断是否响应成功 | |||||
* @return ture 成功,false 失败 | |||||
*/ | |||||
public boolean succeed(){ | |||||
return ResponseCode.SUCCESS.equals(this.code); | |||||
} | |||||
} |
@@ -57,7 +57,7 @@ public interface FileStoreApi { | |||||
*/ | */ | ||||
default String formatPath(String path) { | default String formatPath(String path) { | ||||
if (!StringUtils.isEmpty(path)) { | if (!StringUtils.isEmpty(path)) { | ||||
return path.replaceAll("///*", File.separator); | |||||
return path.replaceAll("///*", "/"); | |||||
} | } | ||||
return path; | return path; | ||||
} | } | ||||
@@ -77,7 +77,9 @@ public enum LogEnum { | |||||
//度量 | //度量 | ||||
MEASURE, | MEASURE, | ||||
//云端Serving | //云端Serving | ||||
SERVING; | |||||
SERVING, | |||||
//专业版终端 | |||||
TERMINAL; | |||||
/** | /** | ||||
* 判断日志类型不能为空 | * 判断日志类型不能为空 | ||||
@@ -25,10 +25,10 @@ | |||||
<!-- 滚动记录文件,先将日志记录到指定文件,复合条件后日志将记录到其他文件 --> | <!-- 滚动记录文件,先将日志记录到指定文件,复合条件后日志将记录到其他文件 --> | ||||
<appender name="info_file" | <appender name="info_file" | ||||
class="ch.qos.logback.core.rolling.RollingFileAppender"> | class="ch.qos.logback.core.rolling.RollingFileAppender"> | ||||
<file>logs/${log.path}/info/dubhe-info.log</file> | |||||
<file>/data/logs/${log.path}/info/dubhe-info.log</file> | |||||
<rollingPolicy | <rollingPolicy | ||||
class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"> | class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"> | ||||
<fileNamePattern>logs/${log.path}/info/dubhe-${app.active}-info-%d{yyyy-MM-dd}.%i.log | |||||
<fileNamePattern>/data/logs/${log.path}/info/dubhe-${app.active}-info-%d{yyyy-MM-dd}.%i.log | |||||
</fileNamePattern> | </fileNamePattern> | ||||
<!-- 单个日志文件最多50MB, 14天的日志周期,最大不能超过250MB --> | <!-- 单个日志文件最多50MB, 14天的日志周期,最大不能超过250MB --> | ||||
<maxFileSize>50MB</maxFileSize> | <maxFileSize>50MB</maxFileSize> | ||||
@@ -52,10 +52,10 @@ | |||||
<!-- 滚动记录文件,先将日志记录到指定文件,复合条件后日志将记录到其他文件 --> | <!-- 滚动记录文件,先将日志记录到指定文件,复合条件后日志将记录到其他文件 --> | ||||
<appender name="debug_info" | <appender name="debug_info" | ||||
class="ch.qos.logback.core.rolling.RollingFileAppender"> | class="ch.qos.logback.core.rolling.RollingFileAppender"> | ||||
<file>logs/${log.path}/debug/dubhe-debug.log</file> | |||||
<file>/data/logs/${log.path}/debug/dubhe-debug.log</file> | |||||
<rollingPolicy | <rollingPolicy | ||||
class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"> | class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"> | ||||
<fileNamePattern>logs/${log.path}/debug/dubhe-${app.active}-debug-%d{yyyy-MM-dd}.%i.log | |||||
<fileNamePattern>/data/logs/${log.path}/debug/dubhe-${app.active}-debug-%d{yyyy-MM-dd}.%i.log | |||||
</fileNamePattern> | </fileNamePattern> | ||||
<!-- 单个日志文件最多50MB, 14天的日志周期,最大不能超过250MB --> | <!-- 单个日志文件最多50MB, 14天的日志周期,最大不能超过250MB --> | ||||
<maxFileSize>50MB</maxFileSize> | <maxFileSize>50MB</maxFileSize> | ||||
@@ -79,10 +79,10 @@ | |||||
<!-- 滚动记录文件,先将日志记录到指定文件,复合条件后日志将记录到其他文件 --> | <!-- 滚动记录文件,先将日志记录到指定文件,复合条件后日志将记录到其他文件 --> | ||||
<appender name="error_file" | <appender name="error_file" | ||||
class="ch.qos.logback.core.rolling.RollingFileAppender"> | class="ch.qos.logback.core.rolling.RollingFileAppender"> | ||||
<file>logs/${log.path}/error/dubhe-error.log</file> | |||||
<file>/data/logs/${log.path}/error/dubhe-error.log</file> | |||||
<rollingPolicy | <rollingPolicy | ||||
class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"> | class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"> | ||||
<fileNamePattern>logs/${log.path}/error/dubhe-${app.active}-error-%d{yyyy-MM-dd}.%i.log | |||||
<fileNamePattern>/data/logs/${log.path}/error/dubhe-${app.active}-error-%d{yyyy-MM-dd}.%i.log | |||||
</fileNamePattern> | </fileNamePattern> | ||||
<!-- 单个日志文件最多50MB, 14天的日志周期,最大不能超过250MB --> | <!-- 单个日志文件最多50MB, 14天的日志周期,最大不能超过250MB --> | ||||
<maxFileSize>50MB</maxFileSize> | <maxFileSize>50MB</maxFileSize> | ||||
@@ -106,10 +106,10 @@ | |||||
<!-- 滚动记录文件,先将日志记录到指定文件,复合条件后日志将记录到其他文件 --> | <!-- 滚动记录文件,先将日志记录到指定文件,复合条件后日志将记录到其他文件 --> | ||||
<appender name="warn_file" | <appender name="warn_file" | ||||
class="ch.qos.logback.core.rolling.RollingFileAppender"> | class="ch.qos.logback.core.rolling.RollingFileAppender"> | ||||
<file>logs/${log.path}/warn/dubhe-warn.log</file> | |||||
<file>/data/logs/${log.path}/warn/dubhe-warn.log</file> | |||||
<rollingPolicy | <rollingPolicy | ||||
class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"> | class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"> | ||||
<fileNamePattern>logs/${log.path}/warn/dubhe-${app.active}-warn-%d{yyyy-MM-dd}.%i.log | |||||
<fileNamePattern>/data/logs/${log.path}/warn/dubhe-${app.active}-warn-%d{yyyy-MM-dd}.%i.log | |||||
</fileNamePattern> | </fileNamePattern> | ||||
<!-- 单个日志文件最多50MB, 14天的日志周期,最大不能超过250MB --> | <!-- 单个日志文件最多50MB, 14天的日志周期,最大不能超过250MB --> | ||||
<maxFileSize>50MB</maxFileSize> | <maxFileSize>50MB</maxFileSize> | ||||
@@ -134,10 +134,10 @@ | |||||
<!-- 滚动记录文件,先将日志记录到指定文件,复合条件后日志将记录到其他文件 --> | <!-- 滚动记录文件,先将日志记录到指定文件,复合条件后日志将记录到其他文件 --> | ||||
<appender name="trace_file" | <appender name="trace_file" | ||||
class="ch.qos.logback.core.rolling.RollingFileAppender"> | class="ch.qos.logback.core.rolling.RollingFileAppender"> | ||||
<file>logs/${log.path}/trace/dubhe-trace.log</file> | |||||
<file>/data/logs/${log.path}/trace/dubhe-trace.log</file> | |||||
<rollingPolicy | <rollingPolicy | ||||
class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"> | class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"> | ||||
<fileNamePattern>logs/${log.path}/trace/dubhe-${app.active}-trace-%d{yyyy-MM-dd}.%i.log | |||||
<fileNamePattern>/data/logs/${log.path}/trace/dubhe-${app.active}-trace-%d{yyyy-MM-dd}.%i.log | |||||
</fileNamePattern> | </fileNamePattern> | ||||
<!-- 单个日志文件最多50MB, 14天的日志周期,最大不能超过250MB --> | <!-- 单个日志文件最多50MB, 14天的日志周期,最大不能超过250MB --> | ||||
<maxFileSize>50MB</maxFileSize> | <maxFileSize>50MB</maxFileSize> | ||||
@@ -162,10 +162,10 @@ | |||||
<!-- 滚动记录文件,先将日志记录到指定文件,复合条件后日志将记录到其他文件 --> | <!-- 滚动记录文件,先将日志记录到指定文件,复合条件后日志将记录到其他文件 --> | ||||
<appender name="schedule_file" | <appender name="schedule_file" | ||||
class="ch.qos.logback.core.rolling.RollingFileAppender"> | class="ch.qos.logback.core.rolling.RollingFileAppender"> | ||||
<file>logs/${log.path}/info/dubhe-schedule.log</file> | |||||
<file>/data/logs/${log.path}/info/dubhe-schedule.log</file> | |||||
<rollingPolicy | <rollingPolicy | ||||
class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"> | class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"> | ||||
<fileNamePattern>logs/${log.path}/info/dubhe-${app.active}-schedule-%d{yyyy-MM-dd}.%i.log | |||||
<fileNamePattern>/data/logs/${log.path}/info/dubhe-${app.active}-schedule-%d{yyyy-MM-dd}.%i.log | |||||
</fileNamePattern> | </fileNamePattern> | ||||
<!-- 单个日志文件最多50MB, 14天的日志周期,最大不能超过250MB --> | <!-- 单个日志文件最多50MB, 14天的日志周期,最大不能超过250MB --> | ||||
<maxFileSize>50MB</maxFileSize> | <maxFileSize>50MB</maxFileSize> | ||||
@@ -189,10 +189,10 @@ | |||||
<!-- 滚动记录文件,先将日志记录到指定文件,复合条件后日志将记录到其他文件 --> | <!-- 滚动记录文件,先将日志记录到指定文件,复合条件后日志将记录到其他文件 --> | ||||
<appender name="global_request_file" | <appender name="global_request_file" | ||||
class="ch.qos.logback.core.rolling.RollingFileAppender"> | class="ch.qos.logback.core.rolling.RollingFileAppender"> | ||||
<file>logs/${log.path}/info/dubhe-request.log</file> | |||||
<file>/data/logs/${log.path}/info/dubhe-request.log</file> | |||||
<rollingPolicy | <rollingPolicy | ||||
class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"> | class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"> | ||||
<fileNamePattern>logs/${log.path}/info/dubhe-${app.active}-request-%d{yyyy-MM-dd}.%i.log | |||||
<fileNamePattern>/data/logs/${log.path}/info/dubhe-${app.active}-request-%d{yyyy-MM-dd}.%i.log | |||||
</fileNamePattern> | </fileNamePattern> | ||||
<!-- 单个日志文件最多50MB, 14天的日志周期,最大不能超过250MB --> | <!-- 单个日志文件最多50MB, 14天的日志周期,最大不能超过250MB --> | ||||
<maxFileSize>50MB</maxFileSize> | <maxFileSize>50MB</maxFileSize> | ||||
@@ -259,4 +259,4 @@ | |||||
<appender-ref ref="console" /> | <appender-ref ref="console" /> | ||||
</logger> | </logger> | ||||
</configuration> | |||||
</configuration> |
@@ -47,5 +47,4 @@ public interface AdminClient { | |||||
@GetMapping(value = "/users/findByIds") | @GetMapping(value = "/users/findByIds") | ||||
DataResponseBody<List<UserDTO>> getUserList(@RequestParam(value = "ids") List<Long> ids); | DataResponseBody<List<UserDTO>> getUserList(@RequestParam(value = "ids") List<Long> ids); | ||||
} | } |
@@ -1,7 +0,0 @@ | |||||
spring: | |||||
cloud: | |||||
nacos: | |||||
config: | |||||
namespace: dubhe-server-cloud-test-data | |||||
discovery: | |||||
namespace: dubhe-server-cloud-test-data |
@@ -1,7 +1,12 @@ | |||||
spring: | spring: | ||||
cloud: | cloud: | ||||
nacos: | nacos: | ||||
username: nacos | |||||
password: Tianshu | |||||
context-path: /nacos | |||||
config: | config: | ||||
namespace: dubhe-server-cloud-dev | namespace: dubhe-server-cloud-dev | ||||
server-addr: 10.105.1.132:8848 | |||||
discovery: | discovery: | ||||
namespace: dubhe-server-cloud-dev | namespace: dubhe-server-cloud-dev | ||||
server-addr: 10.105.1.132:8848 |
@@ -0,0 +1,9 @@ | |||||
spring: | |||||
cloud: | |||||
nacos: | |||||
config: | |||||
namespace: dubhe-server-cloud-pre | |||||
server-addr: 10.105.1.133:8848 | |||||
discovery: | |||||
namespace: dubhe-server-cloud-pre | |||||
server-addr: 10.105.1.133:8848 |
@@ -1,7 +1,12 @@ | |||||
spring: | spring: | ||||
cloud: | cloud: | ||||
nacos: | nacos: | ||||
username: nacos | |||||
password: Tianshu | |||||
context-path: /nacos | |||||
config: | config: | ||||
namespace: dubhe-server-cloud-test | namespace: dubhe-server-cloud-test | ||||
server-addr: 10.105.1.132:8848 | |||||
discovery: | discovery: | ||||
namespace: dubhe-server-cloud-test | namespace: dubhe-server-cloud-test | ||||
server-addr: 10.105.1.132:8848 |
@@ -1,7 +0,0 @@ | |||||
spring: | |||||
cloud: | |||||
nacos: | |||||
config: | |||||
namespace: dubhe-server-cloud-prod | |||||
discovery: | |||||
namespace: dubhe-server-cloud-prod |
@@ -1,7 +0,0 @@ | |||||
spring: | |||||
cloud: | |||||
nacos: | |||||
config: | |||||
namespace: dubhe-server-cloud-prod | |||||
discovery: | |||||
namespace: dubhe-server-cloud-prod |
@@ -72,6 +72,21 @@ | |||||
<version>0.0.1-SNAPSHOT</version> | <version>0.0.1-SNAPSHOT</version> | ||||
<scope>compile</scope> | <scope>compile</scope> | ||||
</dependency> | </dependency> | ||||
<dependency> | |||||
<groupId>com.auth0</groupId> | |||||
<artifactId>java-jwt</artifactId> | |||||
<version>3.4.0</version> | |||||
</dependency> | |||||
<dependency> | |||||
<groupId>org.springframework.boot</groupId> | |||||
<artifactId>spring-boot-starter-websocket</artifactId> | |||||
</dependency> | |||||
<dependency> | |||||
<groupId>com.github.docker-java</groupId> | |||||
<artifactId>docker-java</artifactId> | |||||
<version>3.2.11</version> | |||||
</dependency> | |||||
</dependencies> | </dependencies> | ||||
<build> | <build> | ||||
@@ -0,0 +1,68 @@ | |||||
/** | |||||
* Copyright 2020 Tianshu AI Platform. 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.docker.api; | |||||
import com.github.dockerjava.api.DockerClient; | |||||
import com.github.dockerjava.api.async.ResultCallback; | |||||
import com.github.dockerjava.api.async.ResultCallbackTemplate; | |||||
import com.github.dockerjava.api.model.PushResponseItem; | |||||
/** | |||||
* @description docker api | |||||
* @date 2021-07-06 | |||||
*/ | |||||
public interface DockerApi { | |||||
/** | |||||
* 非强制删除镜像 | |||||
* | |||||
* @param dockerClient docker连接 | |||||
* @param image repository:tag | |||||
* @return boolean 成功true,失败false | |||||
*/ | |||||
boolean removeImage(DockerClient dockerClient,String image); | |||||
/** | |||||
* 删除镜像 | |||||
* | |||||
* @param dockerClient docker连接 | |||||
* @param image repository:tag | |||||
* @param force true:强制删除 false:非强制 | |||||
* @return boolean 成功true,失败false | |||||
*/ | |||||
boolean removeImage(DockerClient dockerClient,String image,boolean force); | |||||
/** | |||||
* docker commit | |||||
* | |||||
* @param dockerClient docker连接 | |||||
* @param containerId 容器id | |||||
* @param repository 仓库 | |||||
* @param tag 标签 | |||||
* @return | |||||
*/ | |||||
String commit(DockerClient dockerClient,String containerId,String repository,String tag); | |||||
/** | |||||
* 推送镜像 | |||||
* | |||||
* @param dockerClient docker连接 | |||||
* @param image repository:tag | |||||
* @return | |||||
*/ | |||||
boolean push(DockerClient dockerClient, String image, ResultCallbackTemplate resultCallback); | |||||
} |
@@ -0,0 +1,112 @@ | |||||
/** | |||||
* Copyright 2020 Tianshu AI Platform. 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.docker.api.impl; | |||||
import com.github.dockerjava.api.DockerClient; | |||||
import com.github.dockerjava.api.async.ResultCallbackTemplate; | |||||
import com.github.dockerjava.api.command.CommitCmd; | |||||
import com.github.dockerjava.api.model.AuthConfig; | |||||
import org.dubhe.biz.log.enums.LogEnum; | |||||
import org.dubhe.biz.log.utils.LogUtil; | |||||
import org.dubhe.docker.api.DockerApi; | |||||
import org.dubhe.docker.config.DubheDockerJavaConfig; | |||||
import org.springframework.beans.factory.annotation.Autowired; | |||||
import org.springframework.stereotype.Service; | |||||
/** | |||||
* @description docker api实现类 | |||||
* @date 2021-07-06 | |||||
*/ | |||||
@Service | |||||
public class DockerApiImpl implements DockerApi { | |||||
@Autowired | |||||
private DubheDockerJavaConfig dubheDockerJavaConfig; | |||||
/** | |||||
* 非强制删除镜像 | |||||
* | |||||
* @param dockerClient docker连接 | |||||
* @param image repository:tag | |||||
* @return boolean 成功true,失败false | |||||
*/ | |||||
@Override | |||||
public boolean removeImage(DockerClient dockerClient, String image) { | |||||
LogUtil.info(LogEnum.TERMINAL, "DockerApiImpl removeImage image:{}",image); | |||||
try{ | |||||
dockerClient.removeImageCmd(image).withForce(false).exec(); | |||||
return true; | |||||
}catch (Exception e){ | |||||
LogUtil.error(LogEnum.TERMINAL, "DockerApiImpl removeImage error:{}",e.getMessage(), e); | |||||
return false; | |||||
} | |||||
} | |||||
/** | |||||
* 删除镜像 | |||||
* | |||||
* @param dockerClient docker连接 | |||||
* @param image repository:tag | |||||
* @param force true:强制删除 false:非强制 | |||||
* @return boolean 成功true,失败false | |||||
*/ | |||||
@Override | |||||
public boolean removeImage(DockerClient dockerClient, String image, boolean force) { | |||||
LogUtil.info(LogEnum.TERMINAL, "DockerApiImpl removeImage image:{} force:{}",image,force); | |||||
try{ | |||||
dockerClient.removeImageCmd(image).withForce(force).exec(); | |||||
return true; | |||||
}catch (Exception e){ | |||||
LogUtil.error(LogEnum.TERMINAL, "DockerApiImpl removeImage error:{}",e.getMessage(), e); | |||||
return false; | |||||
} | |||||
} | |||||
/** | |||||
* docker commit | |||||
* | |||||
* @param dockerClient docker连接 | |||||
* @param containerId 容器id | |||||
* @param repository 仓库 | |||||
* @param tag 标签 | |||||
* @return | |||||
*/ | |||||
@Override | |||||
public String commit(DockerClient dockerClient, String containerId, String repository, String tag) { | |||||
LogUtil.info(LogEnum.TERMINAL, "DockerApiImpl commit containerId:{} repository:{} tag:{}",containerId,repository,tag); | |||||
try{ | |||||
CommitCmd commitCmd = dockerClient.commitCmd(containerId).withRepository(repository).withTag(tag); | |||||
return commitCmd.exec(); | |||||
}catch (Exception e){ | |||||
LogUtil.error(LogEnum.TERMINAL, "DockerApiImpl removeImage error:{}",e.getMessage(), e); | |||||
return e.getMessage(); | |||||
} | |||||
} | |||||
@Override | |||||
public boolean push(DockerClient dockerClient, String image, ResultCallbackTemplate resultCallback) { | |||||
LogUtil.info(LogEnum.TERMINAL, "DockerApiImpl push image:{}",image); | |||||
try{ | |||||
AuthConfig authConfig = new AuthConfig(); | |||||
authConfig.withUsername(dubheDockerJavaConfig.getHarborUserName()).withPassword(dubheDockerJavaConfig.getHarborPassword()); | |||||
dockerClient.pushImageCmd(image).withAuthConfig(authConfig).exec(resultCallback); | |||||
return true; | |||||
}catch (Exception e){ | |||||
LogUtil.error(LogEnum.TERMINAL, "DockerApiImpl push error:{}",e.getMessage(), e); | |||||
return false; | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,97 @@ | |||||
/** | |||||
* Copyright 2020 Tianshu AI Platform. 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.docker.callback; | |||||
import com.github.dockerjava.api.DockerClient; | |||||
import com.github.dockerjava.api.async.ResultCallbackTemplate; | |||||
import com.github.dockerjava.api.model.PushResponseItem; | |||||
import org.dubhe.biz.base.constant.MagicNumConstant; | |||||
import org.dubhe.biz.base.exception.BusinessException; | |||||
import org.dubhe.biz.log.enums.LogEnum; | |||||
import org.dubhe.biz.log.utils.LogUtil; | |||||
import org.dubhe.docker.domain.dto.DockerPushCallbackDTO; | |||||
import org.dubhe.docker.utils.DockerCallbackTool; | |||||
import java.io.IOException; | |||||
/** | |||||
* @description 镜像推送回调 | |||||
* @date 2021-07-22 | |||||
*/ | |||||
public class TerminalPushImageResultCallback extends ResultCallbackTemplate<TerminalPushImageResultCallback,PushResponseItem> { | |||||
private Long terminalId; | |||||
//回调地址 | |||||
private String url; | |||||
private PushResponseItem latestItem = null; | |||||
private DockerClient dockerClient; | |||||
private Long userId; | |||||
public TerminalPushImageResultCallback(){ | |||||
} | |||||
public TerminalPushImageResultCallback(String url, Long terminalId, DockerClient dockerClient,Long userId){ | |||||
this.url = url; | |||||
this.terminalId = terminalId; | |||||
this.dockerClient = dockerClient; | |||||
this.userId = userId; | |||||
} | |||||
@Override | |||||
public void onNext(PushResponseItem item) { | |||||
this.latestItem = item; | |||||
LogUtil.info(LogEnum.TERMINAL,"push image item: {}",item.toString()); | |||||
if (item.getErrorDetail() != null){ | |||||
try { | |||||
DockerCallbackTool.sendPushCallback(new DockerPushCallbackDTO(terminalId,item.getErrorDetail().getMessage(),true,userId),url, MagicNumConstant.THREE); | |||||
} finally { | |||||
try { | |||||
dockerClient.close(); | |||||
} catch (IOException e) { | |||||
LogUtil.error(LogEnum.TERMINAL,"push terminalId {} error:"+e.getMessage(),terminalId,e); | |||||
throw new BusinessException("push error:"+e.getMessage()); | |||||
} | |||||
} | |||||
} | |||||
} | |||||
@Override | |||||
public void onError(Throwable throwable){ | |||||
super.onError(throwable); | |||||
LogUtil.error(LogEnum.TERMINAL,"push image onError: {}",throwable.getMessage()); | |||||
} | |||||
@Override | |||||
public void onComplete(){ | |||||
super.onComplete(); | |||||
LogUtil.info(LogEnum.TERMINAL,"push image onComplete terminalId: {}",terminalId); | |||||
try{ | |||||
DockerCallbackTool.sendPushCallback(new DockerPushCallbackDTO(terminalId,userId),url,MagicNumConstant.THREE); | |||||
}finally { | |||||
try { | |||||
dockerClient.close(); | |||||
} catch (IOException e) { | |||||
LogUtil.error(LogEnum.TERMINAL,"push terminalId {} error:"+e.getMessage(),terminalId,e); | |||||
throw new BusinessException("push error:"+e.getMessage()); | |||||
} | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,57 @@ | |||||
/** | |||||
* Copyright 2020 Tianshu AI Platform. 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.docker.config; | |||||
import com.github.dockerjava.api.DockerClient; | |||||
import com.github.dockerjava.core.DefaultDockerClientConfig; | |||||
import com.github.dockerjava.core.DockerClientBuilder; | |||||
import com.github.dockerjava.core.DockerClientConfig; | |||||
import org.dubhe.biz.base.constant.SymbolConstant; | |||||
import org.dubhe.biz.log.enums.LogEnum; | |||||
import org.dubhe.biz.log.utils.LogUtil; | |||||
import org.springframework.beans.factory.annotation.Autowired; | |||||
import org.springframework.stereotype.Component; | |||||
/** | |||||
* @description docker client 工厂类 | |||||
* @date 2021-07-05 | |||||
*/ | |||||
@Component | |||||
public class DockerClientFactory { | |||||
@Autowired | |||||
private DubheDockerJavaConfig dubheDockerJavaConfig; | |||||
/** | |||||
* 创建连接 | |||||
* | |||||
* @param host ip或域名 | |||||
* @return DockerClient | |||||
*/ | |||||
public DockerClient getDockerClient(String host){ | |||||
try{ | |||||
DockerClientConfig custom = DefaultDockerClientConfig.createDefaultConfigBuilder() | |||||
.withDockerHost("tcp://"+host+ SymbolConstant.COLON + dubheDockerJavaConfig.getDockerRemoteApiPort()) | |||||
.withDockerTlsVerify(false) | |||||
.build(); | |||||
return DockerClientBuilder.getInstance(custom).build(); | |||||
}catch (Exception e){ | |||||
LogUtil.error(LogEnum.TERMINAL, "DockerClientFactory getDockerClient error:{}",e.getMessage(), e); | |||||
return null; | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,42 @@ | |||||
/** | |||||
* Copyright 2020 Tianshu AI Platform. 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.docker.config; | |||||
import lombok.Getter; | |||||
import org.springframework.beans.factory.annotation.Value; | |||||
import org.springframework.context.annotation.Configuration; | |||||
/** | |||||
* @description docker-java相关配置 | |||||
* @date 2021-07-05 | |||||
*/ | |||||
@Getter | |||||
@Configuration | |||||
public class DubheDockerJavaConfig { | |||||
@Value("${docker.remote-api-port}") | |||||
private String dockerRemoteApiPort; | |||||
@Value("${harbor.address}") | |||||
private String harborAddress; | |||||
@Value("${harbor.username}") | |||||
private String harborUserName; | |||||
@Value("${harbor.password}") | |||||
private String harborPassword; | |||||
} |
@@ -0,0 +1,26 @@ | |||||
/** | |||||
* Copyright 2020 Tianshu AI Platform. 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.docker.constant; | |||||
/** | |||||
* @description | |||||
* @date 2021-07-27 | |||||
*/ | |||||
public class DockerCallbackConstant { | |||||
public static final String DOCKER_CALLBACK_URI = "/api/docker/callback/"; | |||||
} |
@@ -0,0 +1,62 @@ | |||||
/** | |||||
* Copyright 2020 Tianshu AI Platform. 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.docker.domain.dto; | |||||
import io.swagger.annotations.ApiModelProperty; | |||||
import lombok.Data; | |||||
import lombok.NoArgsConstructor; | |||||
import lombok.experimental.Accessors; | |||||
import org.dubhe.biz.base.constant.MagicNumConstant; | |||||
import javax.validation.constraints.Min; | |||||
import javax.validation.constraints.NotNull; | |||||
/** | |||||
* @description docker 推送镜像回调 | |||||
* @date 2021-07-27 | |||||
*/ | |||||
@Data | |||||
@NoArgsConstructor | |||||
@Accessors(chain = true) | |||||
public class DockerPushCallbackDTO { | |||||
@ApiModelProperty(value = "terminalId", required = true) | |||||
@Min(value = MagicNumConstant.ONE, message = "id数值不合法") | |||||
private Long terminalId; | |||||
@ApiModelProperty(value = "错误信息", required = false) | |||||
private String errorMessage; | |||||
@NotNull | |||||
@ApiModelProperty(value = "是否错误 true:错误 false:成功") | |||||
private boolean error; | |||||
@ApiModelProperty(value = "用户id", required = false) | |||||
private Long userId; | |||||
public DockerPushCallbackDTO(Long terminalId,Long userId){ | |||||
this.terminalId = terminalId; | |||||
this.userId = userId; | |||||
} | |||||
public DockerPushCallbackDTO(Long terminalId, String errorMessage, boolean error,Long userId){ | |||||
this.terminalId = terminalId; | |||||
this.errorMessage = errorMessage; | |||||
this.error = error; | |||||
this.userId = userId; | |||||
} | |||||
} |
@@ -0,0 +1,40 @@ | |||||
/** | |||||
* Copyright 2020 Tianshu AI Platform. 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.docker.enums; | |||||
/** | |||||
* @description docker操作枚举 | |||||
* @date 2021-07-27 | |||||
*/ | |||||
public enum DockerOperationEnum { | |||||
/** | |||||
* 推送 | |||||
*/ | |||||
PUSH("push"), | |||||
; | |||||
private String operation; | |||||
DockerOperationEnum(String operation) { | |||||
this.operation = operation; | |||||
} | |||||
public String getType() { | |||||
return operation; | |||||
} | |||||
} |
@@ -0,0 +1,83 @@ | |||||
/** | |||||
* Copyright 2020 Tianshu AI Platform. 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.docker.utils; | |||||
import cn.hutool.http.HttpRequest; | |||||
import cn.hutool.http.HttpResponse; | |||||
import cn.hutool.http.HttpStatus; | |||||
import com.alibaba.fastjson.JSON; | |||||
import org.dubhe.biz.base.constant.MagicNumConstant; | |||||
import org.dubhe.biz.base.constant.SymbolConstant; | |||||
import org.dubhe.biz.log.enums.LogEnum; | |||||
import org.dubhe.biz.log.utils.LogUtil; | |||||
import org.dubhe.docker.config.DubheDockerJavaConfig; | |||||
import org.dubhe.docker.constant.DockerCallbackConstant; | |||||
import org.dubhe.docker.domain.dto.DockerPushCallbackDTO; | |||||
import org.springframework.beans.factory.annotation.Autowired; | |||||
import org.springframework.stereotype.Component; | |||||
/** | |||||
* @description docker回调相关工具类 | |||||
* @date 2020-07-13 | |||||
*/ | |||||
@Component | |||||
public class DockerCallbackTool { | |||||
/** | |||||
* http请求超时时间 单位毫秒 | |||||
*/ | |||||
private static final int TIMEOUT_MILLISECOND = 20 * 1000; | |||||
@Autowired | |||||
private DubheDockerJavaConfig dubheDockerJavaConfig; | |||||
/** | |||||
* 获取回调地址 | |||||
* | |||||
* @param host 主机 | |||||
* @param port 端口 | |||||
* @param action 动作 | |||||
* @return | |||||
*/ | |||||
public String getCallbackUrl(String host,String port,String action){ | |||||
return SymbolConstant.HTTP_SLASH+host+SymbolConstant.COLON+port+ DockerCallbackConstant.DOCKER_CALLBACK_URI+action; | |||||
} | |||||
/** | |||||
* 镜像推送回调 | |||||
* | |||||
* @param dockerPushCallbackDTO 回调参数 | |||||
* @param url 回调地址 | |||||
* @param count 重试计数 | |||||
*/ | |||||
public static void sendPushCallback(DockerPushCallbackDTO dockerPushCallbackDTO, String url,Integer count){ | |||||
try{ | |||||
LogUtil.info(LogEnum.TERMINAL, "{} sendPushCallback {} count {}", url, dockerPushCallbackDTO,count); | |||||
HttpResponse httpResponse = HttpRequest.post(url) | |||||
.body(JSON.toJSONString(dockerPushCallbackDTO)) | |||||
.timeout(TIMEOUT_MILLISECOND) | |||||
.execute(); | |||||
LogUtil.info(LogEnum.TERMINAL, "{} sendPushCallback {} count {} status:{}", url, dockerPushCallbackDTO,count,httpResponse.getStatus()); | |||||
//重试 | |||||
if (HttpStatus.HTTP_OK != httpResponse.getStatus() && count > MagicNumConstant.ZERO){ | |||||
sendPushCallback(dockerPushCallbackDTO,url,--count); | |||||
} | |||||
}catch (Exception e){ | |||||
LogUtil.error(LogEnum.TERMINAL, "{} sendPushCallback {} count {} error:{} ", url, dockerPushCallbackDTO,count,e.getMessage(),e); | |||||
} | |||||
} | |||||
} |
@@ -103,6 +103,14 @@ public interface PersistentVolumeClaimApi { | |||||
*/ | */ | ||||
boolean deletePv(String pvName); | boolean deletePv(String pvName); | ||||
/** | |||||
* 删除PV | |||||
* | |||||
* @param resourceName 资源名称 | |||||
* @return boolean true成功 false失败 | |||||
*/ | |||||
boolean deletePvByResourceName(String resourceName); | |||||
/** | /** | ||||
* 查询PV | * 查询PV | ||||
* | * | ||||
@@ -0,0 +1,52 @@ | |||||
/** | |||||
* Copyright 2020 Tianshu AI Platform. 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.k8s.api; | |||||
import org.dubhe.k8s.domain.PtBaseResult; | |||||
import org.dubhe.k8s.domain.bo.TerminalBO; | |||||
import org.dubhe.k8s.domain.vo.TerminalResourceVO; | |||||
/** | |||||
* @description 专业版终端接口 | |||||
* @date 2021-06-29 | |||||
*/ | |||||
public interface TerminalApi { | |||||
/** | |||||
* 创建 | |||||
* | |||||
* @param bo | |||||
* @return BizDeployment | |||||
*/ | |||||
TerminalResourceVO create(TerminalBO bo); | |||||
/** | |||||
* 删除 | |||||
* @param namespace 命名空间 | |||||
* @param resourceName 资源名称 | |||||
* @return PtBaseResult 基础结果类 | |||||
*/ | |||||
PtBaseResult delete(String namespace, String resourceName); | |||||
/** | |||||
* 查询 | |||||
* @param namespace 命名空间 | |||||
* @param resourceName 资源名称 | |||||
* @return | |||||
*/ | |||||
TerminalResourceVO get(String namespace, String resourceName); | |||||
} |
@@ -147,7 +147,7 @@ public class DistributeTrainApiImpl implements DistributeTrainApi { | |||||
@Override | @Override | ||||
public BizDistributeTrain create(DistributeTrainBO bo) { | public BizDistributeTrain create(DistributeTrainBO bo) { | ||||
LogUtil.info(LogEnum.BIZ_K8S, "Params of creating DistributeTrain--create:{}", bo); | LogUtil.info(LogEnum.BIZ_K8S, "Params of creating DistributeTrain--create:{}", bo); | ||||
LimitsOfResourcesEnum limitsOfResources = resourceQuotaApi.reachLimitsOfResources(bo.getNamespace(), bo.getCpuNum() * bo.getSize(), bo.getMemNum() * bo.getSize(), bo.getGpuNum() * bo.getSize()); | |||||
LimitsOfResourcesEnum limitsOfResources = resourceQuotaApi.reachLimitsOfResources(bo.getNamespace(), bo.getCpuNum() * bo.getSize(), bo.getMemNum() * bo.getSize(), bo.getGpuNum() == null?0:bo.getGpuNum() * bo.getSize()); | |||||
if (!LimitsOfResourcesEnum.ADEQUATE.equals(limitsOfResources)) { | if (!LimitsOfResourcesEnum.ADEQUATE.equals(limitsOfResources)) { | ||||
return new BizDistributeTrain().error(K8sResponseEnum.LACK_OF_RESOURCES.getCode(), limitsOfResources.getMessage()); | return new BizDistributeTrain().error(K8sResponseEnum.LACK_OF_RESOURCES.getCode(), limitsOfResources.getMessage()); | ||||
} | } | ||||
@@ -183,6 +183,7 @@ public class DistributeTrainApiImpl implements DistributeTrainApi { | |||||
private Map<String, String> env; | private Map<String, String> env; | ||||
private Map<String, String> baseLabels; | private Map<String, String> baseLabels; | ||||
private String businessLabel; | private String businessLabel; | ||||
private String taskIdentifyLabel; | |||||
private Integer delayCreate; | private Integer delayCreate; | ||||
private Integer delayDelete; | private Integer delayDelete; | ||||
private TaskYamlBO taskYamlBO; | private TaskYamlBO taskYamlBO; | ||||
@@ -201,7 +202,8 @@ public class DistributeTrainApiImpl implements DistributeTrainApi { | |||||
this.slaveCmd = bo.getSlaveCmd(); | this.slaveCmd = bo.getSlaveCmd(); | ||||
this.env = bo.getEnv(); | this.env = bo.getEnv(); | ||||
this.businessLabel = bo.getBusinessLabel(); | this.businessLabel = bo.getBusinessLabel(); | ||||
this.baseLabels = LabelUtils.getChildLabels(baseName, distributeTrainName, K8sKindEnum.DISTRIBUTETRAIN.getKind(), businessLabel); | |||||
this.taskIdentifyLabel = bo.getTaskIdentifyLabel(); | |||||
this.baseLabels = LabelUtils.getChildLabels(baseName, distributeTrainName, K8sKindEnum.DISTRIBUTETRAIN.getKind(), businessLabel, taskIdentifyLabel); | |||||
this.delayCreate = bo.getDelayCreateTime(); | this.delayCreate = bo.getDelayCreateTime(); | ||||
this.delayDelete = bo.getDelayDeleteTime(); | this.delayDelete = bo.getDelayDeleteTime(); | ||||
this.taskYamlBO = new TaskYamlBO(); | this.taskYamlBO = new TaskYamlBO(); | ||||
@@ -225,6 +225,7 @@ public class DubheDeploymentApiImpl implements DubheDeploymentApi { | |||||
private Map<String, Quantity> resourcesLimitsMap; | private Map<String, Quantity> resourcesLimitsMap; | ||||
private Map<String, String> baseLabels; | private Map<String, String> baseLabels; | ||||
private String businessLabel; | private String businessLabel; | ||||
private String taskIdentifyLabel; | |||||
private Integer gpuNum; | private Integer gpuNum; | ||||
@@ -249,6 +250,7 @@ public class DubheDeploymentApiImpl implements DubheDeploymentApi { | |||||
Optional.ofNullable(bo.getGpuNum()).ifPresent(v -> resourcesLimitsMap.put(K8sParamConstants.GPU_RESOURCE_KEY, new Quantity(v.toString()))); | Optional.ofNullable(bo.getGpuNum()).ifPresent(v -> resourcesLimitsMap.put(K8sParamConstants.GPU_RESOURCE_KEY, new Quantity(v.toString()))); | ||||
Optional.ofNullable(bo.getMemNum()).ifPresent(v -> resourcesLimitsMap.put(K8sParamConstants.QUANTITY_MEMORY_KEY, new Quantity(v.toString(), K8sParamConstants.MEM_UNIT))); | Optional.ofNullable(bo.getMemNum()).ifPresent(v -> resourcesLimitsMap.put(K8sParamConstants.QUANTITY_MEMORY_KEY, new Quantity(v.toString(), K8sParamConstants.MEM_UNIT))); | ||||
this.businessLabel = bo.getBusinessLabel(); | this.businessLabel = bo.getBusinessLabel(); | ||||
this.taskIdentifyLabel = bo.getTaskIdentifyLabel(); | |||||
this.baseLabels = LabelUtils.getBaseLabels(baseName, businessLabel); | this.baseLabels = LabelUtils.getBaseLabels(baseName, businessLabel); | ||||
this.datasetReadOnly = true; | this.datasetReadOnly = true; | ||||
@@ -310,7 +312,7 @@ public class DubheDeploymentApiImpl implements DubheDeploymentApi { | |||||
* @return Deployment Deployment 业务类 | * @return Deployment Deployment 业务类 | ||||
*/ | */ | ||||
private Deployment buildDeployment() { | private Deployment buildDeployment() { | ||||
Map<String, String> childLabels = LabelUtils.getChildLabels(baseName, deploymentName, K8sKindEnum.DEPLOYMENT.getKind(), businessLabel); | |||||
Map<String, String> childLabels = LabelUtils.getChildLabels(baseName, deploymentName, K8sKindEnum.DEPLOYMENT.getKind(), businessLabel, taskIdentifyLabel); | |||||
LabelSelector labelSelector = new LabelSelector(); | LabelSelector labelSelector = new LabelSelector(); | ||||
labelSelector.setMatchLabels(childLabels); | labelSelector.setMatchLabels(childLabels); | ||||
return new DeploymentBuilder() | return new DeploymentBuilder() | ||||
@@ -26,6 +26,7 @@ import com.google.common.collect.ImmutableMap; | |||||
import com.google.common.collect.Maps; | import com.google.common.collect.Maps; | ||||
import io.fabric8.kubernetes.api.model.Container; | import io.fabric8.kubernetes.api.model.Container; | ||||
import io.fabric8.kubernetes.api.model.ContainerPortBuilder; | import io.fabric8.kubernetes.api.model.ContainerPortBuilder; | ||||
import io.fabric8.kubernetes.api.model.EmptyDirVolumeSource; | |||||
import io.fabric8.kubernetes.api.model.EnvVar; | import io.fabric8.kubernetes.api.model.EnvVar; | ||||
import io.fabric8.kubernetes.api.model.EnvVarBuilder; | import io.fabric8.kubernetes.api.model.EnvVarBuilder; | ||||
import io.fabric8.kubernetes.api.model.IntOrString; | import io.fabric8.kubernetes.api.model.IntOrString; | ||||
@@ -124,14 +125,19 @@ public class JupyterResourceApiImpl implements JupyterResourceApi { | |||||
private static final String DATASET = "/dataset"; | private static final String DATASET = "/dataset"; | ||||
private static final String WORKSPACE = "/workspace"; | private static final String WORKSPACE = "/workspace"; | ||||
private static final String DSHM_PATH = "/dev/shm"; | |||||
private static final String K8S_PIP_SITE_PACKAGE = "/home/admin/.local/lib/python3.8/site-packages"; | |||||
private static final String PVC_DATASET = "pvc-dataset"; | private static final String PVC_DATASET = "pvc-dataset"; | ||||
private static final String PVC_WORKSPACE = "pvc-workspace"; | private static final String PVC_WORKSPACE = "pvc-workspace"; | ||||
private static final String PVC_PIP_SITE_PACKAGE = "pvc-pip-site-package"; | |||||
private static final String CONTAINER_NAME = "web"; | private static final String CONTAINER_NAME = "web"; | ||||
private static final Integer CONTAINER_PORT = 8888; | private static final Integer CONTAINER_PORT = 8888; | ||||
private static final Integer SVC_PORT = 32680; | private static final Integer SVC_PORT = 32680; | ||||
private static final String NOTEBOOK_MAX_UPLOAD_SIZE = "100m"; | private static final String NOTEBOOK_MAX_UPLOAD_SIZE = "100m"; | ||||
private static final String DSHM = "dshm"; | |||||
private static final String DSHM_MEDIUM = "Memory"; | |||||
public JupyterResourceApiImpl(K8sUtils k8sUtils) { | public JupyterResourceApiImpl(K8sUtils k8sUtils) { | ||||
this.k8sUtils = k8sUtils; | this.k8sUtils = k8sUtils; | ||||
@@ -161,7 +167,7 @@ public class JupyterResourceApiImpl implements JupyterResourceApi { | |||||
return new PtJupyterDeployVO().error(K8sResponseEnum.LACK_OF_RESOURCES.getCode(), lack.getMessage()); | return new PtJupyterDeployVO().error(K8sResponseEnum.LACK_OF_RESOURCES.getCode(), lack.getMessage()); | ||||
} | } | ||||
if (!fileStoreApi.createDirs(bo.getWorkspaceDir(), bo.getDatasetDir())) { | |||||
if (!fileStoreApi.createDirs(bo.getWorkspaceDir(), bo.getDatasetDir(),bo.getPipSitePackageDir())) { | |||||
return new PtJupyterDeployVO().error(K8sResponseEnum.INTERNAL_SERVER_ERROR.getCode(), K8sResponseEnum.INTERNAL_SERVER_ERROR.getMessage()); | return new PtJupyterDeployVO().error(K8sResponseEnum.INTERNAL_SERVER_ERROR.getCode(), K8sResponseEnum.INTERNAL_SERVER_ERROR.getMessage()); | ||||
} | } | ||||
resourceCache.deletePodCacheByResourceName(bo.getNamespace(), bo.getName()); | resourceCache.deletePodCacheByResourceName(bo.getNamespace(), bo.getName()); | ||||
@@ -299,9 +305,12 @@ public class JupyterResourceApiImpl implements JupyterResourceApi { | |||||
private String image; | private String image; | ||||
private String datasetDir; | private String datasetDir; | ||||
private String datasetMountPath; | private String datasetMountPath; | ||||
private String pipSitePackageDir; | |||||
private String pipSitePackageMountPath; | |||||
private String workspaceMountPath; | private String workspaceMountPath; | ||||
private String workspaceDir; | private String workspaceDir; | ||||
private Boolean useGpu; | private Boolean useGpu; | ||||
private Quantity shmMemory; | |||||
//数据集默认只读 | //数据集默认只读 | ||||
private boolean datasetReadOnly; | private boolean datasetReadOnly; | ||||
@@ -316,6 +325,7 @@ public class JupyterResourceApiImpl implements JupyterResourceApi { | |||||
private String baseUrl; | private String baseUrl; | ||||
private String secondaryDomain; | private String secondaryDomain; | ||||
private String businessLabel; | private String businessLabel; | ||||
private String taskIdentifyLabel; | |||||
private Integer delayDelete; | private Integer delayDelete; | ||||
private List<VolumeMount> volumeMounts; | private List<VolumeMount> volumeMounts; | ||||
@@ -329,6 +339,8 @@ public class JupyterResourceApiImpl implements JupyterResourceApi { | |||||
this.image = bo.getImage(); | this.image = bo.getImage(); | ||||
this.datasetDir = bo.getDatasetDir(); | this.datasetDir = bo.getDatasetDir(); | ||||
this.datasetMountPath = StringUtils.isEmpty(bo.getDatasetMountPath()) ? DATASET : bo.getDatasetMountPath(); | this.datasetMountPath = StringUtils.isEmpty(bo.getDatasetMountPath()) ? DATASET : bo.getDatasetMountPath(); | ||||
this.pipSitePackageDir=bo.getPipSitePackageDir(); | |||||
this.pipSitePackageMountPath=StringUtils.isEmpty(bo.getPipSitePackageMountPath()) ? K8S_PIP_SITE_PACKAGE : bo.getPipSitePackageMountPath(); | |||||
this.workspaceDir = bo.getWorkspaceDir(); | this.workspaceDir = bo.getWorkspaceDir(); | ||||
this.workspaceMountPath = StringUtils.isEmpty(bo.getWorkspaceMountPath()) ? WORKSPACE : bo.getWorkspaceMountPath(); | this.workspaceMountPath = StringUtils.isEmpty(bo.getWorkspaceMountPath()) ? WORKSPACE : bo.getWorkspaceMountPath(); | ||||
Optional.ofNullable(bo.getDatasetReadOnly()).ifPresent(v -> datasetReadOnly = v); | Optional.ofNullable(bo.getDatasetReadOnly()).ifPresent(v -> datasetReadOnly = v); | ||||
@@ -342,12 +354,15 @@ public class JupyterResourceApiImpl implements JupyterResourceApi { | |||||
Optional.ofNullable(bo.getCpuNum()).ifPresent(v -> resourcesLimitsMap.put(K8sParamConstants.QUANTITY_CPU_KEY, new Quantity(v.toString(), K8sParamConstants.CPU_UNIT))); | Optional.ofNullable(bo.getCpuNum()).ifPresent(v -> resourcesLimitsMap.put(K8sParamConstants.QUANTITY_CPU_KEY, new Quantity(v.toString(), K8sParamConstants.CPU_UNIT))); | ||||
Optional.ofNullable(bo.getGpuNum()).ifPresent(v -> resourcesLimitsMap.put(K8sParamConstants.GPU_RESOURCE_KEY, new Quantity(v.toString()))); | Optional.ofNullable(bo.getGpuNum()).ifPresent(v -> resourcesLimitsMap.put(K8sParamConstants.GPU_RESOURCE_KEY, new Quantity(v.toString()))); | ||||
Optional.ofNullable(bo.getMemNum()).ifPresent(v -> resourcesLimitsMap.put(K8sParamConstants.QUANTITY_MEMORY_KEY, new Quantity(v.toString(), K8sParamConstants.MEM_UNIT))); | Optional.ofNullable(bo.getMemNum()).ifPresent(v -> resourcesLimitsMap.put(K8sParamConstants.QUANTITY_MEMORY_KEY, new Quantity(v.toString(), K8sParamConstants.MEM_UNIT))); | ||||
this.shmMemory = new Quantity("1024",K8sParamConstants.MEM_UNIT); | |||||
// 共享内存设置为容器内存的一半(参考 Linux 的默认设置) | |||||
Optional.ofNullable(bo.getMemNum()).ifPresent(v -> shmMemory.setAmount(String.valueOf(v/2))); | |||||
this.host = k8sUtils.getHost(); | this.host = k8sUtils.getHost(); | ||||
this.businessLabel = bo.getBusinessLabel(); | this.businessLabel = bo.getBusinessLabel(); | ||||
this.taskIdentifyLabel = bo.getTaskIdentifyLabel(); | |||||
this.delayDelete = bo.getDelayDeleteTime(); | this.delayDelete = bo.getDelayDeleteTime(); | ||||
this.baseLabels = LabelUtils.getBaseLabels(baseName, businessLabel); | this.baseLabels = LabelUtils.getBaseLabels(baseName, businessLabel); | ||||
this.podLabels = LabelUtils.getChildLabels(baseName, statefulSetName, K8sKindEnum.STATEFULSET.getKind(), businessLabel); | |||||
this.podLabels = LabelUtils.getChildLabels(baseName, statefulSetName, K8sKindEnum.STATEFULSET.getKind(), businessLabel, taskIdentifyLabel); | |||||
//生成附属资源的名称 | //生成附属资源的名称 | ||||
generateResourceName(); | generateResourceName(); | ||||
@@ -454,6 +469,41 @@ public class JupyterResourceApiImpl implements JupyterResourceApi { | |||||
} | } | ||||
} | } | ||||
/** | |||||
* 构建 Shm VolumeMount | |||||
*/ | |||||
private void buildShmFsVolume() { | |||||
volumeMounts.add(new VolumeMountBuilder() | |||||
.withName(DSHM) | |||||
.withMountPath(DSHM_PATH) | |||||
.build()); | |||||
volumes.add(new VolumeBuilder() | |||||
.withName(DSHM) | |||||
.withEmptyDir(new EmptyDirVolumeSource(DSHM_MEDIUM, shmMemory)) | |||||
.build()); | |||||
} | |||||
/** | |||||
* 挂载pip包路径 | |||||
*/ | |||||
private void buildPipSitePackageFsVolume(){ | |||||
if (StrUtil.isNotBlank(pipSitePackageDir)) { | |||||
volumeMounts.add(new VolumeMountBuilder() | |||||
.withName(PVC_PIP_SITE_PACKAGE) | |||||
.withMountPath(pipSitePackageMountPath) | |||||
.build()); | |||||
volumes.add(new VolumeBuilder() | |||||
.withName(PVC_PIP_SITE_PACKAGE) | |||||
.withNewHostPath() | |||||
.withPath(pipSitePackageDir) | |||||
.withType(K8sParamConstants.HOST_PATH_TYPE) | |||||
.endHostPath() | |||||
.build()); | |||||
} | |||||
} | |||||
/** | /** | ||||
* 构建VolumeMount | * 构建VolumeMount | ||||
*/ | */ | ||||
@@ -498,8 +548,10 @@ public class JupyterResourceApiImpl implements JupyterResourceApi { | |||||
* @return JupyterDeployer Notebook 部署类 | * @return JupyterDeployer Notebook 部署类 | ||||
*/ | */ | ||||
private JupyterDeployer buildFsVolumes() { | private JupyterDeployer buildFsVolumes() { | ||||
buildPipSitePackageFsVolume(); | |||||
buildDatasetFsVolume(); | buildDatasetFsVolume(); | ||||
buildWorkspaceFsVolume(); | buildWorkspaceFsVolume(); | ||||
buildShmFsVolume(); | |||||
return this; | return this; | ||||
} | } | ||||
@@ -509,8 +561,10 @@ public class JupyterResourceApiImpl implements JupyterResourceApi { | |||||
* @return JupyterDeployer Notebook 部署类 | * @return JupyterDeployer Notebook 部署类 | ||||
*/ | */ | ||||
private JupyterDeployer buildFsPvcVolumes() { | private JupyterDeployer buildFsPvcVolumes() { | ||||
buildPipSitePackageFsVolume(); | |||||
buildDatasetFsVolume(); | buildDatasetFsVolume(); | ||||
buildWorkspaceFsPvcVolume(); | buildWorkspaceFsPvcVolume(); | ||||
buildShmFsVolume(); | |||||
return this; | return this; | ||||
} | } | ||||
@@ -585,7 +639,6 @@ public class JupyterResourceApiImpl implements JupyterResourceApi { | |||||
.withNewSpec() | .withNewSpec() | ||||
.withTerminationGracePeriodSeconds(ZERO_LONG) | .withTerminationGracePeriodSeconds(ZERO_LONG) | ||||
.addToNodeSelector(gpuLabel) | .addToNodeSelector(gpuLabel) | ||||
.withTerminationGracePeriodSeconds(SIXTY_LONG) | |||||
.addToContainers(container) | .addToContainers(container) | ||||
.addToVolumes(volumes.toArray(new Volume[0])) | .addToVolumes(volumes.toArray(new Volume[0])) | ||||
.endSpec() | .endSpec() | ||||
@@ -18,7 +18,6 @@ | |||||
package org.dubhe.k8s.api.impl; | package org.dubhe.k8s.api.impl; | ||||
import cn.hutool.core.util.NumberUtil; | import cn.hutool.core.util.NumberUtil; | ||||
import cn.hutool.core.util.StrUtil; | |||||
import io.fabric8.kubernetes.api.model.Quantity; | import io.fabric8.kubernetes.api.model.Quantity; | ||||
import io.fabric8.kubernetes.api.model.metrics.v1beta1.ContainerMetrics; | import io.fabric8.kubernetes.api.model.metrics.v1beta1.ContainerMetrics; | ||||
import io.fabric8.kubernetes.api.model.metrics.v1beta1.NodeMetricsList; | import io.fabric8.kubernetes.api.model.metrics.v1beta1.NodeMetricsList; | ||||
@@ -40,10 +39,7 @@ import org.dubhe.k8s.domain.dto.PodQueryDTO; | |||||
import org.dubhe.k8s.domain.resource.BizContainer; | import org.dubhe.k8s.domain.resource.BizContainer; | ||||
import org.dubhe.k8s.domain.resource.BizPod; | import org.dubhe.k8s.domain.resource.BizPod; | ||||
import org.dubhe.k8s.domain.resource.BizQuantity; | import org.dubhe.k8s.domain.resource.BizQuantity; | ||||
import org.dubhe.k8s.domain.vo.PodRangeMetricsVO; | |||||
import org.dubhe.k8s.domain.vo.PtContainerMetricsVO; | |||||
import org.dubhe.k8s.domain.vo.PtNodeMetricsVO; | |||||
import org.dubhe.k8s.domain.vo.PtPodsVO; | |||||
import org.dubhe.k8s.domain.vo.*; | |||||
import org.dubhe.k8s.utils.BizConvertUtils; | import org.dubhe.k8s.utils.BizConvertUtils; | ||||
import org.dubhe.k8s.utils.K8sUtils; | import org.dubhe.k8s.utils.K8sUtils; | ||||
import org.dubhe.k8s.utils.PrometheusUtil; | import org.dubhe.k8s.utils.PrometheusUtil; | ||||
@@ -83,6 +79,17 @@ public class MetricsApiImpl implements MetricsApi { | |||||
*/ | */ | ||||
@Value("${k8s.prometheus.gpu-query-param}") | @Value("${k8s.prometheus.gpu-query-param}") | ||||
private String k8sPrometheusGpuQueryParam; | private String k8sPrometheusGpuQueryParam; | ||||
/** | |||||
* prometheus gpu显存总量指标查询参数 | |||||
*/ | |||||
@Value("${k8s.prometheus.gpu-mem-total-query-param}") | |||||
private String k8sPrometheusGpuMemTotalQueryParam; | |||||
/** | |||||
* prometheus gpu显存使用量指标查询参数 | |||||
*/ | |||||
@Value("${k8s.prometheus.gpu-mem-use-query-param}") | |||||
private String k8sPrometheusGpuMemUseQueryParam; | |||||
/** | /** | ||||
* prometheus cpu指标范围查询参数 | * prometheus cpu指标范围查询参数 | ||||
*/ | */ | ||||
@@ -99,6 +106,18 @@ public class MetricsApiImpl implements MetricsApi { | |||||
@Value("${k8s.prometheus.gpu-range-query-param}") | @Value("${k8s.prometheus.gpu-range-query-param}") | ||||
private String k8sPrometheusGpuRangeQueryParam; | private String k8sPrometheusGpuRangeQueryParam; | ||||
/** | |||||
* prometheus gpu显存总量指标范围查询参数 | |||||
*/ | |||||
@Value("${k8s.prometheus.gpu-mem-total-range-query-param}") | |||||
private String k8sPrometheusGpuMemTotalRangeQueryParam; | |||||
/** | |||||
* prometheus gpu显存使用量指标范围查询参数 | |||||
*/ | |||||
@Value("${k8s.prometheus.gpu-mem-use-range-query-param}") | |||||
private String k8sPrometheusGpuMemUseRangeQueryParam; | |||||
public MetricsApiImpl(K8sUtils k8sUtils) { | public MetricsApiImpl(K8sUtils k8sUtils) { | ||||
this.client = k8sUtils.getClient(); | this.client = k8sUtils.getClient(); | ||||
} | } | ||||
@@ -141,7 +160,7 @@ public class MetricsApiImpl implements MetricsApi { | |||||
List<PtPodsVO> list = new ArrayList<>(); | List<PtPodsVO> list = new ArrayList<>(); | ||||
/**将Pod和podName形成映射关系**/ | /**将Pod和podName形成映射关系**/ | ||||
Map<String, List<BizPod>> listMap = client.pods().inAnyNamespace().list().getItems().parallelStream().map(obj -> BizConvertUtils.toBizPod(obj)).collect(Collectors.groupingBy(BizPod::getName)); | Map<String, List<BizPod>> listMap = client.pods().inAnyNamespace().list().getItems().parallelStream().map(obj -> BizConvertUtils.toBizPod(obj)).collect(Collectors.groupingBy(BizPod::getName)); | ||||
if(null == listMap) { | |||||
if (null == listMap) { | |||||
return list; | return list; | ||||
} | } | ||||
metrics.getItems().stream().forEach(metric -> { | metrics.getItems().stream().forEach(metric -> { | ||||
@@ -149,7 +168,7 @@ public class MetricsApiImpl implements MetricsApi { | |||||
List<ContainerMetrics> containers = metric.getContainers(); | List<ContainerMetrics> containers = metric.getContainers(); | ||||
containers.stream().forEach(containerMetrics -> { | containers.stream().forEach(containerMetrics -> { | ||||
Map<String, Quantity> usage = containerMetrics.getUsage(); | Map<String, Quantity> usage = containerMetrics.getUsage(); | ||||
PtPodsVO ptContainerMetricsResult = new PtPodsVO(metric.getMetadata().getNamespace(),metric.getMetadata().getName(), | |||||
PtPodsVO ptContainerMetricsResult = new PtPodsVO(metric.getMetadata().getNamespace(), metric.getMetadata().getName(), | |||||
usage.get(K8sParamConstants.QUANTITY_CPU_KEY).getAmount(), | usage.get(K8sParamConstants.QUANTITY_CPU_KEY).getAmount(), | ||||
usage.get(K8sParamConstants.QUANTITY_CPU_KEY).getFormat(), | usage.get(K8sParamConstants.QUANTITY_CPU_KEY).getFormat(), | ||||
usage.get(K8sParamConstants.QUANTITY_MEMORY_KEY).getAmount(), | usage.get(K8sParamConstants.QUANTITY_MEMORY_KEY).getAmount(), | ||||
@@ -158,7 +177,7 @@ public class MetricsApiImpl implements MetricsApi { | |||||
listMap.get(metric.getMetadata().getName()).get(0).getPhase(), null); | listMap.get(metric.getMetadata().getName()).get(0).getPhase(), null); | ||||
List<BizContainer> containerList = listMap.get(metric.getMetadata().getName()).get(0).getContainers(); | List<BizContainer> containerList = listMap.get(metric.getMetadata().getName()).get(0).getContainers(); | ||||
countGpuUsed(containerList,ptContainerMetricsResult); | |||||
countGpuUsed(containerList, ptContainerMetricsResult); | |||||
list.add(ptContainerMetricsResult); | list.add(ptContainerMetricsResult); | ||||
}); | }); | ||||
}); | }); | ||||
@@ -185,7 +204,7 @@ public class MetricsApiImpl implements MetricsApi { | |||||
containers.stream().forEach(containerMetrics -> | containers.stream().forEach(containerMetrics -> | ||||
{ | { | ||||
Map<String, Quantity> usage = containerMetrics.getUsage(); | Map<String, Quantity> usage = containerMetrics.getUsage(); | ||||
PtPodsVO ptContainerMetricsResult = new PtPodsVO(metric.getMetadata().getNamespace(),metric.getMetadata().getName(), | |||||
PtPodsVO ptContainerMetricsResult = new PtPodsVO(metric.getMetadata().getNamespace(), metric.getMetadata().getName(), | |||||
usage.get(K8sParamConstants.QUANTITY_CPU_KEY).getAmount(), | usage.get(K8sParamConstants.QUANTITY_CPU_KEY).getAmount(), | ||||
usage.get(K8sParamConstants.QUANTITY_CPU_KEY).getFormat(), | usage.get(K8sParamConstants.QUANTITY_CPU_KEY).getFormat(), | ||||
usage.get(K8sParamConstants.QUANTITY_MEMORY_KEY).getAmount(), | usage.get(K8sParamConstants.QUANTITY_MEMORY_KEY).getAmount(), | ||||
@@ -194,7 +213,7 @@ public class MetricsApiImpl implements MetricsApi { | |||||
bizPod.getPhase(), null | bizPod.getPhase(), null | ||||
); | ); | ||||
List<BizContainer> containerList = bizPod.getContainers(); | List<BizContainer> containerList = bizPod.getContainers(); | ||||
countGpuUsed(containerList,ptContainerMetricsResult); | |||||
countGpuUsed(containerList, ptContainerMetricsResult); | |||||
list.add(ptContainerMetricsResult); | list.add(ptContainerMetricsResult); | ||||
}); | }); | ||||
} | } | ||||
@@ -215,7 +234,7 @@ public class MetricsApiImpl implements MetricsApi { | |||||
* @param containerList BizContainer对象 | * @param containerList BizContainer对象 | ||||
* @param ptContainerMetricsResult 封装pod信息 | * @param ptContainerMetricsResult 封装pod信息 | ||||
*/ | */ | ||||
private void countGpuUsed(List<BizContainer> containerList,PtPodsVO ptContainerMetricsResult){ | |||||
private void countGpuUsed(List<BizContainer> containerList, PtPodsVO ptContainerMetricsResult) { | |||||
for (BizContainer container : containerList) { | for (BizContainer container : containerList) { | ||||
Map<String, BizQuantity> limits = container.getLimits(); | Map<String, BizQuantity> limits = container.getLimits(); | ||||
if (limits == null) { | if (limits == null) { | ||||
@@ -238,24 +257,24 @@ public class MetricsApiImpl implements MetricsApi { | |||||
@Override | @Override | ||||
public List<PtPodsVO> getPodMetricsRealTime(String namespace, String resourceName) { | public List<PtPodsVO> getPodMetricsRealTime(String namespace, String resourceName) { | ||||
List<PtPodsVO> ptPodsVOS = new ArrayList<>(); | List<PtPodsVO> ptPodsVOS = new ArrayList<>(); | ||||
if (StringUtils.isEmpty(namespace) || StringUtils.isEmpty(resourceName)){ | |||||
if (StringUtils.isEmpty(namespace) || StringUtils.isEmpty(resourceName)) { | |||||
return ptPodsVOS; | return ptPodsVOS; | ||||
} | } | ||||
List<BizPod> pods = podApi.getListByResourceName(namespace,resourceName); | |||||
if (CollectionUtils.isEmpty(pods)){ | |||||
List<BizPod> pods = podApi.getListByResourceName(namespace, resourceName); | |||||
if (CollectionUtils.isEmpty(pods)) { | |||||
return ptPodsVOS; | return ptPodsVOS; | ||||
} | } | ||||
List<PodMetrics> podMetricsList = client.top().pods().metrics(namespace).getItems(); | List<PodMetrics> podMetricsList = client.top().pods().metrics(namespace).getItems(); | ||||
if (!CollectionUtils.isEmpty(pods)){ | |||||
Map<String,PodMetrics> podMetricsMap = podMetricsList.stream().collect(Collectors.toMap(obj -> obj.getMetadata().getName(), obj -> obj)); | |||||
for (BizPod pod : pods){ | |||||
List<PtPodsVO> ptPodsVOList = getPtPodsVO(pod,podMetricsMap.get(pod.getName())); | |||||
if (!CollectionUtils.isEmpty(ptPodsVOList)){ | |||||
if (!CollectionUtils.isEmpty(pods)) { | |||||
Map<String, PodMetrics> podMetricsMap = podMetricsList.stream().collect(Collectors.toMap(obj -> obj.getMetadata().getName(), obj -> obj)); | |||||
for (BizPod pod : pods) { | |||||
List<PtPodsVO> ptPodsVOList = getPtPodsVO(pod, podMetricsMap.get(pod.getName())); | |||||
if (!CollectionUtils.isEmpty(ptPodsVOList)) { | |||||
ptPodsVOS.addAll(ptPodsVOList); | ptPodsVOS.addAll(ptPodsVOList); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
for (PtPodsVO ptPodsVO : ptPodsVOS){ | |||||
for (PtPodsVO ptPodsVO : ptPodsVOS) { | |||||
generateGpuUsage(ptPodsVO); | generateGpuUsage(ptPodsVO); | ||||
ptPodsVO.calculationPercent(); | ptPodsVO.calculationPercent(); | ||||
} | } | ||||
@@ -271,21 +290,21 @@ public class MetricsApiImpl implements MetricsApi { | |||||
@Override | @Override | ||||
public List<PtPodsVO> getPodMetricsRealTimeByPodName(String namespace, String podName) { | public List<PtPodsVO> getPodMetricsRealTimeByPodName(String namespace, String podName) { | ||||
List<PtPodsVO> ptPodsVOS = new ArrayList<>(); | List<PtPodsVO> ptPodsVOS = new ArrayList<>(); | ||||
if (StringUtils.isEmpty(namespace) || StringUtils.isEmpty(podName)){ | |||||
if (StringUtils.isEmpty(namespace) || StringUtils.isEmpty(podName)) { | |||||
return ptPodsVOS; | return ptPodsVOS; | ||||
} | } | ||||
BizPod pod = podApi.get(namespace,podName); | |||||
if (null == pod){ | |||||
BizPod pod = podApi.get(namespace, podName); | |||||
if (null == pod) { | |||||
return ptPodsVOS; | return ptPodsVOS; | ||||
} | } | ||||
PodMetrics podMetrics = null; | PodMetrics podMetrics = null; | ||||
try{ | |||||
podMetrics = client.top().pods().metrics(namespace,podName); | |||||
}catch (KubernetesClientException e){ | |||||
try { | |||||
podMetrics = client.top().pods().metrics(namespace, podName); | |||||
} catch (KubernetesClientException e) { | |||||
LogUtil.error(LogEnum.BIZ_K8S, "MetricsApiImpl.getPodMetricsRealTimeByPodName error:{}", e); | LogUtil.error(LogEnum.BIZ_K8S, "MetricsApiImpl.getPodMetricsRealTimeByPodName error:{}", e); | ||||
} | } | ||||
ptPodsVOS = getPtPodsVO(pod,podMetrics); | |||||
for (PtPodsVO ptPodsVO : ptPodsVOS){ | |||||
ptPodsVOS = getPtPodsVO(pod, podMetrics); | |||||
for (PtPodsVO ptPodsVO : ptPodsVOS) { | |||||
generateGpuUsage(ptPodsVO); | generateGpuUsage(ptPodsVO); | ||||
ptPodsVO.calculationPercent(); | ptPodsVO.calculationPercent(); | ||||
} | } | ||||
@@ -301,8 +320,8 @@ public class MetricsApiImpl implements MetricsApi { | |||||
@Override | @Override | ||||
public List<PtPodsVO> getPodMetricsRealTimeByPodName(String namespace, List<String> podNames) { | public List<PtPodsVO> getPodMetricsRealTimeByPodName(String namespace, List<String> podNames) { | ||||
List<PtPodsVO> ptPodsVOS = new ArrayList<>(); | List<PtPodsVO> ptPodsVOS = new ArrayList<>(); | ||||
for (String podName : podNames){ | |||||
ptPodsVOS.addAll(getPodMetricsRealTimeByPodName(namespace,podName)); | |||||
for (String podName : podNames) { | |||||
ptPodsVOS.addAll(getPodMetricsRealTimeByPodName(namespace, podName)); | |||||
} | } | ||||
return ptPodsVOS; | return ptPodsVOS; | ||||
} | } | ||||
@@ -315,16 +334,16 @@ public class MetricsApiImpl implements MetricsApi { | |||||
@Override | @Override | ||||
public List<PodRangeMetricsVO> getPodRangeMetrics(PodQueryDTO podQueryDTO) { | public List<PodRangeMetricsVO> getPodRangeMetrics(PodQueryDTO podQueryDTO) { | ||||
List<PodRangeMetricsVO> podRangeMetricsVOS = new ArrayList<>(); | List<PodRangeMetricsVO> podRangeMetricsVOS = new ArrayList<>(); | ||||
if (StringUtils.isEmpty(podQueryDTO.getNamespace()) || StringUtils.isEmpty(podQueryDTO.getResourceName())){ | |||||
if (StringUtils.isEmpty(podQueryDTO.getNamespace()) || StringUtils.isEmpty(podQueryDTO.getResourceName())) { | |||||
return podRangeMetricsVOS; | return podRangeMetricsVOS; | ||||
} | } | ||||
List<BizPod> pods = podApi.getListByResourceName(podQueryDTO.getNamespace(),podQueryDTO.getResourceName()); | |||||
if (CollectionUtils.isEmpty(pods)){ | |||||
List<BizPod> pods = podApi.getListByResourceName(podQueryDTO.getNamespace(), podQueryDTO.getResourceName()); | |||||
if (CollectionUtils.isEmpty(pods)) { | |||||
return podRangeMetricsVOS; | return podRangeMetricsVOS; | ||||
} | } | ||||
podQueryDTO.generateDefaultParam(); | podQueryDTO.generateDefaultParam(); | ||||
for (BizPod pod : pods){ | |||||
podRangeMetricsVOS.add(getPodRangeMetricsVO(pod,podQueryDTO)); | |||||
for (BizPod pod : pods) { | |||||
podRangeMetricsVOS.add(getPodRangeMetricsVO(pod, podQueryDTO)); | |||||
} | } | ||||
return podRangeMetricsVOS; | return podRangeMetricsVOS; | ||||
} | } | ||||
@@ -337,16 +356,16 @@ public class MetricsApiImpl implements MetricsApi { | |||||
@Override | @Override | ||||
public List<PodRangeMetricsVO> getPodRangeMetricsByPodName(PodQueryDTO podQueryDTO) { | public List<PodRangeMetricsVO> getPodRangeMetricsByPodName(PodQueryDTO podQueryDTO) { | ||||
List<PodRangeMetricsVO> podRangeMetricsVOS = new ArrayList<>(); | List<PodRangeMetricsVO> podRangeMetricsVOS = new ArrayList<>(); | ||||
if (StringUtils.isEmpty(podQueryDTO.getNamespace()) || CollectionUtils.isEmpty(podQueryDTO.getPodNames())){ | |||||
if (StringUtils.isEmpty(podQueryDTO.getNamespace()) || CollectionUtils.isEmpty(podQueryDTO.getPodNames())) { | |||||
return podRangeMetricsVOS; | return podRangeMetricsVOS; | ||||
} | } | ||||
List<BizPod> pods = podApi.get(podQueryDTO.getNamespace(),podQueryDTO.getPodNames()); | |||||
if (null == pods){ | |||||
List<BizPod> pods = podApi.get(podQueryDTO.getNamespace(), podQueryDTO.getPodNames()); | |||||
if (null == pods) { | |||||
return podRangeMetricsVOS; | return podRangeMetricsVOS; | ||||
} | } | ||||
podQueryDTO.generateDefaultParam(); | podQueryDTO.generateDefaultParam(); | ||||
for (BizPod pod : pods){ | |||||
podRangeMetricsVOS.add(getPodRangeMetricsVO(pod,podQueryDTO)); | |||||
for (BizPod pod : pods) { | |||||
podRangeMetricsVOS.add(getPodRangeMetricsVO(pod, podQueryDTO)); | |||||
} | } | ||||
return podRangeMetricsVOS; | return podRangeMetricsVOS; | ||||
} | } | ||||
@@ -358,22 +377,40 @@ public class MetricsApiImpl implements MetricsApi { | |||||
* @param podQueryDTO 查询参数 | * @param podQueryDTO 查询参数 | ||||
* @return PodRangeMetricsVO Pod历史监控指标 VO | * @return PodRangeMetricsVO Pod历史监控指标 VO | ||||
*/ | */ | ||||
private PodRangeMetricsVO getPodRangeMetricsVO(BizPod pod,PodQueryDTO podQueryDTO){ | |||||
private PodRangeMetricsVO getPodRangeMetricsVO(BizPod pod, PodQueryDTO podQueryDTO) { | |||||
PodRangeMetricsVO podRangeMetricsVO = new PodRangeMetricsVO(pod.getName()); | PodRangeMetricsVO podRangeMetricsVO = new PodRangeMetricsVO(pod.getName()); | ||||
PrometheusMetricBO cpuRangeMetrics = PrometheusUtil.getQuery(k8sPrometheusUrl+k8sPrometheusQueryRange,PrometheusUtil.getQueryParamMap(k8sPrometheusCpuRangeQueryParam,pod.getName(),podQueryDTO)); | |||||
PrometheusMetricBO memRangeMetrics = PrometheusUtil.getQuery(k8sPrometheusUrl+k8sPrometheusQueryRange,PrometheusUtil.getQueryParamMap(k8sPrometheusMemRangeQueryParam,pod.getName(),podQueryDTO)); | |||||
PrometheusMetricBO gpuRangeMetrics = PrometheusUtil.getQuery(k8sPrometheusUrl+k8sPrometheusQueryRange,PrometheusUtil.getQueryParamMap(k8sPrometheusGpuRangeQueryParam,pod.getName(),podQueryDTO)); | |||||
PrometheusMetricBO cpuRangeMetrics = PrometheusUtil.getQuery(k8sPrometheusUrl + k8sPrometheusQueryRange, PrometheusUtil.getQueryParamMap(k8sPrometheusCpuRangeQueryParam, pod.getName(), podQueryDTO)); | |||||
PrometheusMetricBO memRangeMetrics = PrometheusUtil.getQuery(k8sPrometheusUrl + k8sPrometheusQueryRange, PrometheusUtil.getQueryParamMap(k8sPrometheusMemRangeQueryParam, pod.getName(), podQueryDTO)); | |||||
PrometheusMetricBO gpuRangeMetrics = PrometheusUtil.getQuery(k8sPrometheusUrl + k8sPrometheusQueryRange, PrometheusUtil.getQueryParamMap(k8sPrometheusGpuRangeQueryParam, pod.getName(), podQueryDTO)); | |||||
PrometheusMetricBO gpuMemTotalRangeMetrics = PrometheusUtil.getQuery(k8sPrometheusUrl + k8sPrometheusQueryRange, PrometheusUtil.getQueryParamMap(k8sPrometheusGpuMemTotalRangeQueryParam, pod.getName(), podQueryDTO)); | |||||
PrometheusMetricBO gpuMemUseRangeMetrics = PrometheusUtil.getQuery(k8sPrometheusUrl + k8sPrometheusQueryRange, PrometheusUtil.getQueryParamMap(k8sPrometheusGpuMemUseRangeQueryParam, pod.getName(), podQueryDTO)); | |||||
StringFormat cpuMetricsFormat = (value)->{ | |||||
StringFormat cpuMetricsFormat = (value) -> { | |||||
return value == null ? String.valueOf(MagicNumConstant.ZERO) : NumberUtil.round(Double.valueOf(value.toString()), MagicNumConstant.TWO).toString(); | return value == null ? String.valueOf(MagicNumConstant.ZERO) : NumberUtil.round(Double.valueOf(value.toString()), MagicNumConstant.TWO).toString(); | ||||
}; | }; | ||||
podRangeMetricsVO.setCpuMetrics(cpuRangeMetrics.getValues(cpuMetricsFormat)); | podRangeMetricsVO.setCpuMetrics(cpuRangeMetrics.getValues(cpuMetricsFormat)); | ||||
StringFormat memMetricsFormat = (value)->{ | |||||
StringFormat memMetricsFormat = (value) -> { | |||||
return NumberUtil.isNumber(String.valueOf(value)) ? String.valueOf(Long.valueOf(String.valueOf(value)) / MagicNumConstant.BINARY_TEN_EXP) : String.valueOf(MagicNumConstant.ZERO); | return NumberUtil.isNumber(String.valueOf(value)) ? String.valueOf(Long.valueOf(String.valueOf(value)) / MagicNumConstant.BINARY_TEN_EXP) : String.valueOf(MagicNumConstant.ZERO); | ||||
}; | }; | ||||
podRangeMetricsVO.setMemoryMetrics(memRangeMetrics.getValues(memMetricsFormat)); | podRangeMetricsVO.setMemoryMetrics(memRangeMetrics.getValues(memMetricsFormat)); | ||||
podRangeMetricsVO.setGpuMetrics(gpuRangeMetrics.getResults()); | |||||
Map<String, List<MetricsDataResultValueVO>> gpuMetricsResults = gpuRangeMetrics.getGpuMetricsResults(); | |||||
List<GpuTotalMemResultVO> gpuTotalMemResults = gpuMemTotalRangeMetrics.getGpuTotalMemResults(); | |||||
Map<String, List<MetricsDataResultValueVO>> gpuMemResults = gpuMemUseRangeMetrics.getGpuMemResults(); | |||||
List<GpuMetricsDataResultVO> gpuMetricsDataResultVOS = gpuTotalMemResults.stream().map(x -> { | |||||
GpuMetricsDataResultVO gpuMetricsDataResultVO = new GpuMetricsDataResultVO(); | |||||
gpuMetricsDataResultVO.setAccId(x.getAccId()).setTotalMemValues(x.getGpuTotalMemValue()); | |||||
if (gpuMemResults.containsKey(x.getAccId())) { | |||||
gpuMetricsDataResultVO.setGpuMemValues(gpuMemResults.get(x.getAccId())); | |||||
} | |||||
if (gpuMetricsResults.containsKey(x.getAccId())) { | |||||
gpuMetricsDataResultVO.setGpuMetricsValues(gpuMetricsResults.get(x.getAccId())); | |||||
} | |||||
return gpuMetricsDataResultVO; | |||||
} | |||||
).collect(Collectors.toList()); | |||||
podRangeMetricsVO.setGpuMetrics(gpuMetricsDataResultVOS); | |||||
return podRangeMetricsVO; | return podRangeMetricsVO; | ||||
} | } | ||||
@@ -381,12 +418,31 @@ public class MetricsApiImpl implements MetricsApi { | |||||
* 查询Gpu使用率 | * 查询Gpu使用率 | ||||
* @param ptPodsVO pod信息 | * @param ptPodsVO pod信息 | ||||
*/ | */ | ||||
private void generateGpuUsage(PtPodsVO ptPodsVO){ | |||||
PrometheusMetricBO prometheusMetricBO = PrometheusUtil.getQuery(k8sPrometheusUrl+k8sPrometheusQuery, PrometheusUtil.getQueryParamMap(k8sPrometheusGpuQueryParam,ptPodsVO.getPodName())); | |||||
if (prometheusMetricBO == null){ | |||||
private void generateGpuUsage(PtPodsVO ptPodsVO) { | |||||
PrometheusMetricBO prometheusMetricBO = PrometheusUtil.getQuery(k8sPrometheusUrl + k8sPrometheusQuery, PrometheusUtil.getQueryParamMap(k8sPrometheusGpuQueryParam, ptPodsVO.getPodName())); | |||||
PrometheusMetricBO gpuMemTotalMetrics = PrometheusUtil.getQuery(k8sPrometheusUrl + k8sPrometheusQuery, PrometheusUtil.getQueryParamMap(k8sPrometheusGpuMemTotalQueryParam, ptPodsVO.getPodName())); | |||||
PrometheusMetricBO gpuMemUseMetrics = PrometheusUtil.getQuery(k8sPrometheusUrl + k8sPrometheusQuery, PrometheusUtil.getQueryParamMap(k8sPrometheusGpuMemUseQueryParam, ptPodsVO.getPodName())); | |||||
if (prometheusMetricBO == null || gpuMemTotalMetrics == null || gpuMemUseMetrics == null) { | |||||
return; | return; | ||||
} | } | ||||
ptPodsVO.setGpuUsagePersent(prometheusMetricBO.getGpuUsage()); | |||||
List<GpuTotalMemResultVO> gpuTotalMemValue = gpuMemTotalMetrics.getGpuTotalMemValue(); | |||||
Map<String, String> gpuMemValue = gpuMemUseMetrics.getGpuMemValue(); | |||||
Map<String, Float> gpuUsage = prometheusMetricBO.getGpuUsage(); | |||||
List<GpuValueVO> gpuValueVOS = gpuTotalMemValue.stream().map(x -> { | |||||
GpuValueVO gpuValueVO = new GpuValueVO(); | |||||
gpuValueVO.setAccId(x.getAccId()).setGpuTotalMemValue(x.getGpuTotalMemValue()); | |||||
if (gpuMemValue.containsKey(x.getAccId())) { | |||||
gpuValueVO.setGpuMemValue(gpuMemValue.get(x.getAccId())); | |||||
} | |||||
if (gpuUsage.containsKey(x.getAccId())) { | |||||
gpuValueVO.setUsage(gpuUsage.get(x.getAccId())); | |||||
} | |||||
return gpuValueVO; | |||||
} | |||||
).collect(Collectors.toList()); | |||||
ptPodsVO.setGpuUsagePersent(gpuValueVOS); | |||||
} | } | ||||
/** | /** | ||||
@@ -395,22 +451,22 @@ public class MetricsApiImpl implements MetricsApi { | |||||
* @param metric 查询指标 | * @param metric 查询指标 | ||||
* @return List<PtPodsVO> pod信息列表 | * @return List<PtPodsVO> pod信息列表 | ||||
*/ | */ | ||||
private List<PtPodsVO> getPtPodsVO(BizPod bizPod,PodMetrics metric){ | |||||
private List<PtPodsVO> getPtPodsVO(BizPod bizPod, PodMetrics metric) { | |||||
List<PtPodsVO> ptPodsVOList = new ArrayList<>(); | List<PtPodsVO> ptPodsVOList = new ArrayList<>(); | ||||
if (metric == null){ | |||||
if (metric == null) { | |||||
return ptPodsVOList; | return ptPodsVOList; | ||||
} | } | ||||
Map<String,ContainerMetrics> containerMetricsMap = metric.getContainers().stream().collect(Collectors.toMap(obj -> obj.getName(), obj -> obj)); | |||||
for (BizContainer container : bizPod.getContainers()){ | |||||
Map<String, ContainerMetrics> containerMetricsMap = metric.getContainers().stream().collect(Collectors.toMap(obj -> obj.getName(), obj -> obj)); | |||||
for (BizContainer container : bizPod.getContainers()) { | |||||
Map<String, BizQuantity> request = container.getRequests(); | Map<String, BizQuantity> request = container.getRequests(); | ||||
if (containerMetricsMap.get(container.getName()) == null){ | |||||
if (containerMetricsMap.get(container.getName()) == null) { | |||||
continue; | continue; | ||||
} | } | ||||
Map<String, Quantity> usage = containerMetricsMap.get(container.getName()).getUsage(); | Map<String, Quantity> usage = containerMetricsMap.get(container.getName()).getUsage(); | ||||
PtPodsVO ptContainerMetricsResult = new PtPodsVO(metric.getMetadata().getNamespace(),metric.getMetadata().getName(), | |||||
request.get(K8sParamConstants.QUANTITY_CPU_KEY) ==null ? null : request.get(K8sParamConstants.QUANTITY_CPU_KEY).getAmount(), | |||||
PtPodsVO ptContainerMetricsResult = new PtPodsVO(metric.getMetadata().getNamespace(), metric.getMetadata().getName(), | |||||
request.get(K8sParamConstants.QUANTITY_CPU_KEY) == null ? null : request.get(K8sParamConstants.QUANTITY_CPU_KEY).getAmount(), | |||||
usage.get(K8sParamConstants.QUANTITY_CPU_KEY).getAmount(), | usage.get(K8sParamConstants.QUANTITY_CPU_KEY).getAmount(), | ||||
request.get(K8sParamConstants.QUANTITY_CPU_KEY) ==null ? null : request.get(K8sParamConstants.QUANTITY_CPU_KEY).getFormat(), | |||||
request.get(K8sParamConstants.QUANTITY_CPU_KEY) == null ? null : request.get(K8sParamConstants.QUANTITY_CPU_KEY).getFormat(), | |||||
usage.get(K8sParamConstants.QUANTITY_CPU_KEY).getFormat(), | usage.get(K8sParamConstants.QUANTITY_CPU_KEY).getFormat(), | ||||
request.get(K8sParamConstants.QUANTITY_MEMORY_KEY) == null ? null : request.get(K8sParamConstants.QUANTITY_MEMORY_KEY).getAmount(), | request.get(K8sParamConstants.QUANTITY_MEMORY_KEY) == null ? null : request.get(K8sParamConstants.QUANTITY_MEMORY_KEY).getAmount(), | ||||
usage.get(K8sParamConstants.QUANTITY_MEMORY_KEY).getAmount(), | usage.get(K8sParamConstants.QUANTITY_MEMORY_KEY).getAmount(), | ||||
@@ -430,7 +486,8 @@ public class MetricsApiImpl implements MetricsApi { | |||||
ptContainerMetricsResult.setGpuUsed(count); | ptContainerMetricsResult.setGpuUsed(count); | ||||
} | } | ||||
ptPodsVOList.add(ptContainerMetricsResult); | ptPodsVOList.add(ptContainerMetricsResult); | ||||
}; | |||||
} | |||||
; | |||||
return ptPodsVOList; | return ptPodsVOList; | ||||
} | } | ||||
@@ -443,7 +500,7 @@ public class MetricsApiImpl implements MetricsApi { | |||||
*/ | */ | ||||
@Override | @Override | ||||
public List<PtContainerMetricsVO> getContainerMetrics(String namespace) { | public List<PtContainerMetricsVO> getContainerMetrics(String namespace) { | ||||
if(StringUtils.isEmpty(namespace)){ | |||||
if (StringUtils.isEmpty(namespace)) { | |||||
return Collections.EMPTY_LIST; | return Collections.EMPTY_LIST; | ||||
} | } | ||||
try { | try { | ||||
@@ -212,6 +212,7 @@ public class ModelOptJobApiImpl implements ModelOptJobApi { | |||||
private List<VolumeMount> volumeMounts; | private List<VolumeMount> volumeMounts; | ||||
private List<Volume> volumes; | private List<Volume> volumes; | ||||
private String businessLabel; | private String businessLabel; | ||||
private String taskIdentifyLabel; | |||||
private Integer gpuNum; | private Integer gpuNum; | ||||
private String errCode; | private String errCode; | ||||
@@ -231,6 +232,7 @@ public class ModelOptJobApiImpl implements ModelOptJobApi { | |||||
Optional.ofNullable(bo.getGpuNum()).ifPresent(v -> resourcesLimitsMap.put(K8sParamConstants.GPU_RESOURCE_KEY, new Quantity(v.toString()))); | Optional.ofNullable(bo.getGpuNum()).ifPresent(v -> resourcesLimitsMap.put(K8sParamConstants.GPU_RESOURCE_KEY, new Quantity(v.toString()))); | ||||
Optional.ofNullable(bo.getMemNum()).ifPresent(v -> resourcesLimitsMap.put(K8sParamConstants.QUANTITY_MEMORY_KEY, new Quantity(v.toString(), K8sParamConstants.MEM_UNIT))); | Optional.ofNullable(bo.getMemNum()).ifPresent(v -> resourcesLimitsMap.put(K8sParamConstants.QUANTITY_MEMORY_KEY, new Quantity(v.toString(), K8sParamConstants.MEM_UNIT))); | ||||
this.businessLabel = bo.getBusinessLabel(); | this.businessLabel = bo.getBusinessLabel(); | ||||
this.taskIdentifyLabel = bo.getTaskIdentifyLabel(); | |||||
this.fsMounts = bo.getFsMounts(); | this.fsMounts = bo.getFsMounts(); | ||||
this.baseLabels = LabelUtils.getBaseLabels(baseName, businessLabel); | this.baseLabels = LabelUtils.getBaseLabels(baseName, businessLabel); | ||||
@@ -372,7 +374,7 @@ public class ModelOptJobApiImpl implements ModelOptJobApi { | |||||
* @return Job 任务job类 | * @return Job 任务job类 | ||||
*/ | */ | ||||
private Job buildJob() { | private Job buildJob() { | ||||
Map<String, String> childLabels = LabelUtils.getChildLabels(baseName, jobName, K8sKindEnum.JOB.getKind(), businessLabel); | |||||
Map<String, String> childLabels = LabelUtils.getChildLabels(baseName, jobName, K8sKindEnum.JOB.getKind(), businessLabel, taskIdentifyLabel); | |||||
return new JobBuilder() | return new JobBuilder() | ||||
.withNewMetadata() | .withNewMetadata() | ||||
.withName(jobName) | .withName(jobName) | ||||
@@ -148,7 +148,7 @@ public class ModelServingApiImpl implements ModelServingApi { | |||||
//标签生成 | //标签生成 | ||||
Map<String, String> baseLabels = LabelUtils.getBaseLabels(bo.getResourceName(), bo.getBusinessLabel()); | Map<String, String> baseLabels = LabelUtils.getBaseLabels(bo.getResourceName(), bo.getBusinessLabel()); | ||||
Map<String, String> podLabels = LabelUtils.getChildLabels(bo.getResourceName(), deploymentName, K8sKindEnum.DEPLOYMENT.getKind(), bo.getBusinessLabel()); | |||||
Map<String, String> podLabels = LabelUtils.getChildLabels(bo.getResourceName(), deploymentName, K8sKindEnum.DEPLOYMENT.getKind(), bo.getBusinessLabel(), bo.getTaskIdentifyLabel()); | |||||
//部署deployment | //部署deployment | ||||
Deployment deployment = buildDeployment(bo, volumeVO, deploymentName); | Deployment deployment = buildDeployment(bo, volumeVO, deploymentName); | ||||
@@ -266,7 +266,7 @@ public class ModelServingApiImpl implements ModelServingApi { | |||||
* @return Deployment | * @return Deployment | ||||
*/ | */ | ||||
private Deployment buildDeployment(ModelServingBO bo, VolumeVO volumeVO, String deploymentName) { | private Deployment buildDeployment(ModelServingBO bo, VolumeVO volumeVO, String deploymentName) { | ||||
Map<String, String> childLabels = LabelUtils.getChildLabels(bo.getResourceName(), deploymentName, K8sKindEnum.DEPLOYMENT.getKind(), bo.getBusinessLabel()); | |||||
Map<String, String> childLabels = LabelUtils.getChildLabels(bo.getResourceName(), deploymentName, K8sKindEnum.DEPLOYMENT.getKind(), bo.getBusinessLabel(),bo.getTaskIdentifyLabel()); | |||||
LabelSelector labelSelector = new LabelSelector(); | LabelSelector labelSelector = new LabelSelector(); | ||||
labelSelector.setMatchLabels(childLabels); | labelSelector.setMatchLabels(childLabels); | ||||
return new DeploymentBuilder() | return new DeploymentBuilder() | ||||
@@ -285,7 +285,7 @@ public class ModelServingApiImpl implements ModelServingApi { | |||||
.withNamespace(bo.getNamespace()) | .withNamespace(bo.getNamespace()) | ||||
.endMetadata() | .endMetadata() | ||||
.withNewSpec() | .withNewSpec() | ||||
.addToNodeSelector(k8sUtils.gpuSelector(bo.getGpuNum())) | |||||
.addToNodeSelector(K8sUtils.gpuSelector(bo.getGpuNum())) | |||||
.addToContainers(buildContainer(bo, volumeVO, deploymentName)) | .addToContainers(buildContainer(bo, volumeVO, deploymentName)) | ||||
.addToVolumes(volumeVO.getVolumes().toArray(new Volume[0])) | .addToVolumes(volumeVO.getVolumes().toArray(new Volume[0])) | ||||
.withRestartPolicy(RestartPolicyEnum.ALWAYS.getRestartPolicy()) | .withRestartPolicy(RestartPolicyEnum.ALWAYS.getRestartPolicy()) | ||||
@@ -24,6 +24,7 @@ import io.fabric8.kubernetes.api.model.NamespaceList; | |||||
import io.fabric8.kubernetes.api.model.ResourceQuota; | import io.fabric8.kubernetes.api.model.ResourceQuota; | ||||
import io.fabric8.kubernetes.client.KubernetesClient; | import io.fabric8.kubernetes.client.KubernetesClient; | ||||
import io.fabric8.kubernetes.client.KubernetesClientException; | import io.fabric8.kubernetes.client.KubernetesClientException; | ||||
import org.dubhe.biz.base.service.UserContextService; | |||||
import org.dubhe.biz.log.enums.LogEnum; | import org.dubhe.biz.log.enums.LogEnum; | ||||
import org.dubhe.k8s.annotation.K8sValidation; | import org.dubhe.k8s.annotation.K8sValidation; | ||||
import org.dubhe.k8s.api.NamespaceApi; | import org.dubhe.k8s.api.NamespaceApi; | ||||
@@ -60,13 +61,16 @@ public class NamespaceApiImpl implements NamespaceApi { | |||||
@Autowired | @Autowired | ||||
private ResourceQuotaApi resourceQuotaApi; | private ResourceQuotaApi resourceQuotaApi; | ||||
@Value("${k8s.namespace-limits.cpu}") | |||||
@Autowired | |||||
private UserContextService userContextService; | |||||
@Value("${user.config.cpu-limit}") | |||||
private Integer cpuLimit; | private Integer cpuLimit; | ||||
@Value("${k8s.namespace-limits.memory}") | |||||
@Value("${user.config.memory-limit}") | |||||
private Integer memoryLimit; | private Integer memoryLimit; | ||||
@Value("${k8s.namespace-limits.gpu}") | |||||
@Value("${user.config.gpu-limit}") | |||||
private Integer gpuLimit; | private Integer gpuLimit; | ||||
@@ -110,7 +114,8 @@ public class NamespaceApiImpl implements NamespaceApi { | |||||
if (StringUtils.isEmpty(namespace)) { | if (StringUtils.isEmpty(namespace)) { | ||||
return new BizNamespace().baseErrorBadRequest(); | return new BizNamespace().baseErrorBadRequest(); | ||||
} | } | ||||
return BizConvertUtils.toBizNamespace(client.namespaces().withName(namespace).get()); | |||||
Namespace namespaceEntity = client.namespaces().withName(namespace).get(); | |||||
return BizConvertUtils.toBizNamespace(namespaceEntity); | |||||
} | } | ||||
/** | /** | ||||
@@ -27,6 +27,7 @@ import org.dubhe.biz.base.utils.StringUtils; | |||||
import org.dubhe.biz.log.enums.LogEnum; | import org.dubhe.biz.log.enums.LogEnum; | ||||
import org.dubhe.biz.log.utils.LogUtil; | import org.dubhe.biz.log.utils.LogUtil; | ||||
import org.dubhe.k8s.api.PersistentVolumeClaimApi; | import org.dubhe.k8s.api.PersistentVolumeClaimApi; | ||||
import org.dubhe.k8s.constant.K8sLabelConstants; | |||||
import org.dubhe.k8s.constant.K8sParamConstants; | import org.dubhe.k8s.constant.K8sParamConstants; | ||||
import org.dubhe.k8s.domain.PtBaseResult; | import org.dubhe.k8s.domain.PtBaseResult; | ||||
import org.dubhe.k8s.domain.bo.PtPersistentVolumeClaimBO; | import org.dubhe.k8s.domain.bo.PtPersistentVolumeClaimBO; | ||||
@@ -137,7 +138,7 @@ public class PersistentVolumeClaimApiImpl implements PersistentVolumeClaimApi { | |||||
//创建pv | //创建pv | ||||
PersistentVolume pv = new PersistentVolumeBuilder() | PersistentVolume pv = new PersistentVolumeBuilder() | ||||
.withNewMetadata().addToLabels(pvLabels).withName(bo.getPvcName() + PV_SUFFIX).endMetadata() | .withNewMetadata().addToLabels(pvLabels).withName(bo.getPvcName() + PV_SUFFIX).endMetadata() | ||||
.withNewSpec().addToCapacity(STORAGE, new Quantity(bo.getRequest())).addNewAccessMode(AccessModeEnum.READ_WRITE_ONCE.getType()).withNewPersistentVolumeReclaimPolicy(PvReclaimPolicyEnum.RECYCLE.getPolicy()) | |||||
.withNewSpec().addToCapacity(STORAGE, new Quantity(bo.getRequest())).addNewAccessMode(AccessModeEnum.READ_WRITE_ONCE.getType()).withNewPersistentVolumeReclaimPolicy(StringUtils.isNotEmpty(bo.getReclaimPolicy())?PvReclaimPolicyEnum.RECYCLE.getPolicy():bo.getReclaimPolicy()) | |||||
.withNewHostPath().withNewPath(bo.getPath()).withType(K8sParamConstants.HOST_PATH_TYPE).endHostPath() | .withNewHostPath().withNewPath(bo.getPath()).withType(K8sParamConstants.HOST_PATH_TYPE).endHostPath() | ||||
.endSpec() | .endSpec() | ||||
.build(); | .build(); | ||||
@@ -356,6 +357,17 @@ public class PersistentVolumeClaimApiImpl implements PersistentVolumeClaimApi { | |||||
return client.persistentVolumes().withName(pvName).delete(); | return client.persistentVolumes().withName(pvName).delete(); | ||||
} | } | ||||
/** | |||||
* 删除PV | |||||
* | |||||
* @param resourceName 资源名称 | |||||
* @return boolean true成功 false失败 | |||||
*/ | |||||
@Override | |||||
public boolean deletePvByResourceName(String resourceName) { | |||||
return client.persistentVolumes().withLabel(K8sLabelConstants.BASE_TAG_SOURCE,resourceName).delete(); | |||||
} | |||||
/** | /** | ||||
* 查询PV | * 查询PV | ||||
* | * | ||||
@@ -90,7 +90,7 @@ public class ResourceQuotaApiImpl implements ResourceQuotaApi { | |||||
resourceQuota = new ResourceQuotaBuilder().withNewMetadata().withName(bo.getName()).endMetadata() | resourceQuota = new ResourceQuotaBuilder().withNewMetadata().withName(bo.getName()).endMetadata() | ||||
.withNewSpec().withHard(hard).endSpec().build(); | .withNewSpec().withHard(hard).endSpec().build(); | ||||
} | } | ||||
BizResourceQuota bizResourceQuota = BizConvertUtils.toBizResourceQuota(client.resourceQuotas().inNamespace(bo.getNamespace()).create(resourceQuota)); | |||||
BizResourceQuota bizResourceQuota = BizConvertUtils.toBizResourceQuota(client.resourceQuotas().inNamespace(bo.getNamespace()).createOrReplace(resourceQuota)); | |||||
LogUtil.info(LogEnum.BIZ_K8S,"Output {}", bizResourceQuota); | LogUtil.info(LogEnum.BIZ_K8S,"Output {}", bizResourceQuota); | ||||
return bizResourceQuota; | return bizResourceQuota; | ||||
} catch (KubernetesClientException e) { | } catch (KubernetesClientException e) { | ||||
@@ -217,7 +217,7 @@ public class ResourceQuotaApiImpl implements ResourceQuotaApi { | |||||
} | } | ||||
BizQuantity memRemainder = remainder.get(K8sParamConstants.RESOURCE_QUOTA_MEMORY_LIMITS_KEY); | BizQuantity memRemainder = remainder.get(K8sParamConstants.RESOURCE_QUOTA_MEMORY_LIMITS_KEY); | ||||
if (memRemainder != null && memRemainder != null){ | |||||
if (memRemainder != null && memNum != null){ | |||||
if (UnitConvertUtils.memFormatToMi(memRemainder.getAmount(),memRemainder.getFormat()) < memNum){ | if (UnitConvertUtils.memFormatToMi(memRemainder.getAmount(),memRemainder.getFormat()) < memNum){ | ||||
return LimitsOfResourcesEnum.LIMITS_OF_MEM; | return LimitsOfResourcesEnum.LIMITS_OF_MEM; | ||||
} | } | ||||
@@ -0,0 +1,205 @@ | |||||
/** | |||||
* Copyright 2020 Tianshu AI Platform. 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.k8s.api.impl; | |||||
import cn.hutool.core.collection.CollectionUtil; | |||||
import cn.hutool.core.util.RandomUtil; | |||||
import cn.hutool.core.util.StrUtil; | |||||
import io.fabric8.kubernetes.api.model.Quantity; | |||||
import io.fabric8.kubernetes.api.model.Service; | |||||
import io.fabric8.kubernetes.api.model.ServiceList; | |||||
import io.fabric8.kubernetes.api.model.apps.Deployment; | |||||
import io.fabric8.kubernetes.api.model.apps.DeploymentList; | |||||
import io.fabric8.kubernetes.client.KubernetesClient; | |||||
import io.fabric8.kubernetes.client.KubernetesClientException; | |||||
import org.dubhe.biz.base.constant.MagicNumConstant; | |||||
import org.dubhe.biz.base.constant.SymbolConstant; | |||||
import org.dubhe.biz.file.api.FileStoreApi; | |||||
import org.dubhe.biz.log.enums.LogEnum; | |||||
import org.dubhe.biz.log.utils.LogUtil; | |||||
import org.dubhe.k8s.api.NodeApi; | |||||
import org.dubhe.k8s.api.PersistentVolumeClaimApi; | |||||
import org.dubhe.k8s.api.PodApi; | |||||
import org.dubhe.k8s.api.ResourceIisolationApi; | |||||
import org.dubhe.k8s.api.ResourceQuotaApi; | |||||
import org.dubhe.k8s.api.TerminalApi; | |||||
import org.dubhe.k8s.api.VolumeApi; | |||||
import org.dubhe.k8s.constant.K8sParamConstants; | |||||
import org.dubhe.k8s.domain.PtBaseResult; | |||||
import org.dubhe.k8s.domain.bo.BuildFsVolumeBO; | |||||
import org.dubhe.k8s.domain.bo.BuildServiceBO; | |||||
import org.dubhe.k8s.domain.bo.TerminalBO; | |||||
import org.dubhe.k8s.domain.vo.PtJupyterDeployVO; | |||||
import org.dubhe.k8s.domain.vo.TerminalResourceVO; | |||||
import org.dubhe.k8s.domain.vo.VolumeVO; | |||||
import org.dubhe.k8s.enums.K8sKindEnum; | |||||
import org.dubhe.k8s.enums.K8sResponseEnum; | |||||
import org.dubhe.k8s.enums.LackOfResourcesEnum; | |||||
import org.dubhe.k8s.enums.LimitsOfResourcesEnum; | |||||
import org.dubhe.k8s.enums.ServiceTypeENum; | |||||
import org.dubhe.k8s.utils.BizConvertUtils; | |||||
import org.dubhe.k8s.utils.K8sUtils; | |||||
import org.dubhe.k8s.utils.LabelUtils; | |||||
import org.dubhe.k8s.utils.ResourceBuildUtils; | |||||
import org.dubhe.k8s.utils.YamlUtils; | |||||
import org.springframework.beans.factory.annotation.Autowired; | |||||
import org.springframework.util.CollectionUtils; | |||||
import javax.annotation.Resource; | |||||
import java.util.Map; | |||||
/** | |||||
* @description 专业版终端接口实现 | |||||
* @date 2021-06-29 | |||||
*/ | |||||
public class TerminalApiImpl implements TerminalApi { | |||||
private K8sUtils k8sUtils; | |||||
private KubernetesClient client; | |||||
@Resource(name = "hostFileStoreApiImpl") | |||||
private FileStoreApi fileStoreApi; | |||||
@Autowired | |||||
private VolumeApi volumeApi; | |||||
@Autowired | |||||
private PersistentVolumeClaimApi persistentVolumeClaimApi; | |||||
@Autowired | |||||
private NodeApi nodeApi; | |||||
@Autowired | |||||
private PodApi podApi; | |||||
@Autowired | |||||
private ResourceQuotaApi resourceQuotaApi; | |||||
@Autowired | |||||
private ResourceIisolationApi resourceIisolationApi; | |||||
public TerminalApiImpl(K8sUtils k8sUtils) { | |||||
this.k8sUtils = k8sUtils; | |||||
this.client = k8sUtils.getClient(); | |||||
} | |||||
/** | |||||
* 创建 | |||||
* | |||||
* @param bo | |||||
* @return BizDeployment | |||||
*/ | |||||
@Override | |||||
public TerminalResourceVO create(TerminalBO bo) { | |||||
try { | |||||
LogUtil.info(LogEnum.BIZ_K8S, "Params of creating TerminalApiImpl--create:{}", bo); | |||||
//资源配额校验 | |||||
LimitsOfResourcesEnum limitsOfResources = resourceQuotaApi.reachLimitsOfResources(bo.getNamespace(), bo.getCpuNum(), bo.getMemNum(), bo.getGpuNum()); | |||||
if (!LimitsOfResourcesEnum.ADEQUATE.equals(limitsOfResources)) { | |||||
return new TerminalResourceVO().error(K8sResponseEnum.LACK_OF_RESOURCES.getCode(), limitsOfResources.getMessage()); | |||||
} | |||||
LackOfResourcesEnum lack = nodeApi.isAllocatable(bo.getCpuNum(), bo.getMemNum(), bo.getGpuNum()); | |||||
if (!LackOfResourcesEnum.ADEQUATE.equals(lack)) { | |||||
return new TerminalResourceVO().error(K8sResponseEnum.LACK_OF_RESOURCES.getCode(), lack.getMessage()); | |||||
} | |||||
if (!fileStoreApi.createDirs(bo.getDirList().toArray(new String[MagicNumConstant.ZERO]))) { | |||||
return new TerminalResourceVO().error(K8sResponseEnum.INTERNAL_SERVER_ERROR.getCode(), K8sResponseEnum.INTERNAL_SERVER_ERROR.getMessage()); | |||||
} | |||||
//存储卷构建 | |||||
VolumeVO volumeVO = volumeApi.buildFsVolumes(new BuildFsVolumeBO(bo.getNamespace(), bo.getResourceName(), bo.getFsMounts())); | |||||
if (!K8sResponseEnum.SUCCESS.getCode().equals(volumeVO.getCode())) { | |||||
return new TerminalResourceVO().error(volumeVO.getCode(), volumeVO.getMessage()); | |||||
} | |||||
//共享存储 | |||||
Integer ShmMemAmount = bo.getMemNum() == null?MagicNumConstant.BINARY_TEN_EXP:bo.getMemNum()/MagicNumConstant.TWO; | |||||
volumeVO.addShmFsVolume(new Quantity(String.valueOf(ShmMemAmount),K8sParamConstants.MEM_UNIT)); | |||||
//名称生成 | |||||
String deploymentName = StrUtil.format(K8sParamConstants.RESOURCE_NAME_TEMPLATE, bo.getResourceName(), RandomUtil.randomString(MagicNumConstant.EIGHT)); | |||||
String svcName = StrUtil.format(K8sParamConstants.SUB_RESOURCE_NAME_TEMPLATE, bo.getResourceName(), K8sParamConstants.SVC_SUFFIX, RandomUtil.randomString(MagicNumConstant.FIVE)); | |||||
//标签生成 | |||||
Map<String, String> baseLabels = LabelUtils.getBaseLabels(bo.getResourceName(), bo.getBusinessLabel()); | |||||
Map<String, String> podLabels = LabelUtils.getChildLabels(bo.getResourceName(), deploymentName, K8sKindEnum.DEPLOYMENT.getKind(), bo.getBusinessLabel(), bo.getTaskIdentifyLabel()); | |||||
//部署deployment | |||||
Deployment deployment = ResourceBuildUtils.buildDeployment(bo, volumeVO, deploymentName); | |||||
LogUtil.info(LogEnum.BIZ_K8S, "Ready to deploy {}, yaml信息为{}", deploymentName, YamlUtils.dumpAsYaml(deployment)); | |||||
resourceIisolationApi.addIisolationInfo(deployment); | |||||
Deployment deploymentResult = client.apps().deployments().inNamespace(bo.getNamespace()).create(deployment); | |||||
//部署service | |||||
BuildServiceBO buildServiceBO = new BuildServiceBO(bo.getNamespace(), svcName, baseLabels, podLabels, ServiceTypeENum.NODE_PORT.getType()); | |||||
if (!CollectionUtils.isEmpty(bo.getPorts())){ | |||||
bo.getPorts().forEach(port -> { | |||||
buildServiceBO.addPort(ResourceBuildUtils.buildServicePort(port, port, SymbolConstant.PORT+SymbolConstant.HYPHEN+port)); | |||||
}); | |||||
} | |||||
Service service = ResourceBuildUtils.buildService(buildServiceBO); | |||||
LogUtil.info(LogEnum.BIZ_K8S, "Ready to deploy {}, yaml信息为{}", svcName, YamlUtils.dumpAsYaml(service)); | |||||
Service serviceResult = client.services().create(service); | |||||
return new TerminalResourceVO(BizConvertUtils.toBizDeployment(deploymentResult),BizConvertUtils.toBizService(serviceResult)); | |||||
}catch (KubernetesClientException e) { | |||||
LogUtil.error(LogEnum.BIZ_K8S, "TerminalApiImpl.create error, param:{} error:", bo, e); | |||||
return new TerminalResourceVO().error(String.valueOf(e.getCode()), e.getMessage()); | |||||
} | |||||
} | |||||
/** | |||||
* 删除 | |||||
* @param namespace 命名空间 | |||||
* @param resourceName 资源名称 | |||||
* @return PtBaseResult 基础结果类 | |||||
*/ | |||||
@Override | |||||
public PtBaseResult delete(String namespace, String resourceName) { | |||||
try { | |||||
LogUtil.info(LogEnum.BIZ_K8S, "delete Terminal namespace:{} resourceName:{}",namespace,resourceName); | |||||
DeploymentList deploymentList = client.apps().deployments().inNamespace(namespace).withLabels(LabelUtils.withEnvResourceName(resourceName)).list(); | |||||
if (deploymentList == null || deploymentList.getItems().size() == 0){ | |||||
return new PtBaseResult(); | |||||
} | |||||
persistentVolumeClaimApi.delete(namespace,resourceName); | |||||
persistentVolumeClaimApi.deletePvByResourceName(resourceName); | |||||
Boolean res = client.services().inNamespace(namespace).withLabels(LabelUtils.withEnvResourceName(resourceName)).delete() | |||||
&& client.apps().deployments().inNamespace(namespace).withLabels(LabelUtils.withEnvResourceName(resourceName)).delete(); | |||||
if (res) { | |||||
return new PtBaseResult(); | |||||
} else { | |||||
return K8sResponseEnum.REPEAT.toPtBaseResult(); | |||||
} | |||||
} catch (KubernetesClientException e) { | |||||
LogUtil.error(LogEnum.BIZ_K8S, "delete error:", e); | |||||
return new PtBaseResult(String.valueOf(e.getCode()), e.getMessage()); | |||||
} | |||||
} | |||||
/** | |||||
* 查询 | |||||
* @param namespace 命名空间 | |||||
* @param resourceName 资源名称 | |||||
* @return | |||||
*/ | |||||
@Override | |||||
public TerminalResourceVO get(String namespace, String resourceName) { | |||||
try { | |||||
ServiceList svcList = client.services().inNamespace(namespace).withLabels(LabelUtils.withEnvResourceName(resourceName)).list(); | |||||
Service svc = CollectionUtil.isEmpty(svcList.getItems()) ? null : svcList.getItems().get(0); | |||||
DeploymentList deploymentList = client.apps().deployments().inNamespace(namespace).withLabels(LabelUtils.withEnvResourceName(resourceName)).list(); | |||||
Deployment deployment = CollectionUtil.isEmpty(deploymentList.getItems()) ? null : deploymentList.getItems().get(0); | |||||
return new TerminalResourceVO(BizConvertUtils.toBizDeployment(deployment), BizConvertUtils.toBizService(svc)); | |||||
} catch (KubernetesClientException e) { | |||||
LogUtil.error(LogEnum.BIZ_K8S, "get error:", e); | |||||
return new TerminalResourceVO().error(String.valueOf(e.getCode()), e.getMessage()); | |||||
} | |||||
} | |||||
} |
@@ -151,7 +151,7 @@ public class TrainJobApiImpl implements TrainJobApi { | |||||
/** | /** | ||||
* 根据命名空间和资源名删除Job | * 根据命名空间和资源名删除Job | ||||
* | * | ||||
* @param namespace 命名空间 | |||||
* @param namespace 命名空间 | |||||
* @param resourceName 资源名称 | * @param resourceName 资源名称 | ||||
* @return Boolean true成功 false失败 | * @return Boolean true成功 false失败 | ||||
*/ | */ | ||||
@@ -224,6 +224,7 @@ public class TrainJobApiImpl implements TrainJobApi { | |||||
private List<VolumeMount> volumeMounts; | private List<VolumeMount> volumeMounts; | ||||
private List<Volume> volumes; | private List<Volume> volumes; | ||||
private String businessLabel; | private String businessLabel; | ||||
private String taskIdentifyLabel; | |||||
private Integer delayCreate; | private Integer delayCreate; | ||||
private Integer delayDelete; | private Integer delayDelete; | ||||
private TaskYamlBO taskYamlBO; | private TaskYamlBO taskYamlBO; | ||||
@@ -249,6 +250,7 @@ public class TrainJobApiImpl implements TrainJobApi { | |||||
this.fsMounts = bo.getFsMounts(); | this.fsMounts = bo.getFsMounts(); | ||||
businessLabel = bo.getBusinessLabel(); | businessLabel = bo.getBusinessLabel(); | ||||
this.taskIdentifyLabel = bo.getTaskIdentifyLabel(); | |||||
this.baseLabels = LabelUtils.getBaseLabels(baseName,bo.getBusinessLabel()); | this.baseLabels = LabelUtils.getBaseLabels(baseName,bo.getBusinessLabel()); | ||||
this.volumeMounts = new ArrayList<>(); | this.volumeMounts = new ArrayList<>(); | ||||
@@ -345,8 +347,8 @@ public class TrainJobApiImpl implements TrainJobApi { | |||||
* 挂载存储 | * 挂载存储 | ||||
* | * | ||||
* @param mountPath 挂载路径 | * @param mountPath 挂载路径 | ||||
* @param dirBO 挂载路径参数 | |||||
* @param num 名称序号 | |||||
* @param dirBO 挂载路径参数 | |||||
* @param num 名称序号 | |||||
* @return boolean true成功 false失败 | * @return boolean true成功 false失败 | ||||
*/ | */ | ||||
private boolean buildFsVolumes(String mountPath,PtMountDirBO dirBO,int num){ | private boolean buildFsVolumes(String mountPath,PtMountDirBO dirBO,int num){ | ||||
@@ -369,8 +371,8 @@ public class TrainJobApiImpl implements TrainJobApi { | |||||
* 按照存储资源声明挂载存储 | * 按照存储资源声明挂载存储 | ||||
* | * | ||||
* @param mountPath 挂载路径 | * @param mountPath 挂载路径 | ||||
* @param dirBO 挂载路径参数 | |||||
* @param i 名称序号 | |||||
* @param dirBO 挂载路径参数 | |||||
* @param i 名称序号 | |||||
* @return boolean true成功 false失败 | * @return boolean true成功 false失败 | ||||
*/ | */ | ||||
private boolean buildFsPvcVolumes(String mountPath,PtMountDirBO dirBO,int i){ | private boolean buildFsPvcVolumes(String mountPath,PtMountDirBO dirBO,int i){ | ||||
@@ -456,7 +458,7 @@ public class TrainJobApiImpl implements TrainJobApi { | |||||
.withNewTemplate() | .withNewTemplate() | ||||
.withNewMetadata() | .withNewMetadata() | ||||
.withName(jobName) | .withName(jobName) | ||||
.addToLabels(LabelUtils.getChildLabels(baseName, jobName, K8sKindEnum.JOB.getKind(),businessLabel)) | |||||
.addToLabels(LabelUtils.getChildLabels(baseName, jobName, K8sKindEnum.JOB.getKind(),businessLabel, taskIdentifyLabel)) | |||||
.withNamespace(namespace) | .withNamespace(namespace) | ||||
.endMetadata() | .endMetadata() | ||||
.withNewSpec() | .withNewSpec() | ||||
@@ -61,7 +61,7 @@ public class VolumeApiImpl implements VolumeApi { | |||||
for (Map.Entry<String, PtMountDirBO> mount : bo.getFsMounts().entrySet()) { | for (Map.Entry<String, PtMountDirBO> mount : bo.getFsMounts().entrySet()) { | ||||
boolean availableMount = (mount != null && StringUtils.isNotEmpty(mount.getKey()) && mount.getValue() != null && StringUtils.isNotEmpty(mount.getValue().getDir())); | boolean availableMount = (mount != null && StringUtils.isNotEmpty(mount.getKey()) && mount.getValue() != null && StringUtils.isNotEmpty(mount.getValue().getDir())); | ||||
if (availableMount){ | if (availableMount){ | ||||
boolean success = mount.getValue().isRecycle()?buildFsPvcVolumes(bo,volumeVO,mount.getKey(),mount.getValue(),i):buildFsVolumes(volumeVO,mount.getKey(),mount.getValue(),i); | |||||
boolean success = (mount.getValue().isRecycle() || (StringUtils.isNotEmpty(mount.getValue().getLimit()) || StringUtils.isNotEmpty(mount.getValue().getRequest())))?buildFsPvcVolumes(bo,volumeVO,mount.getKey(),mount.getValue(),i):buildFsVolumes(volumeVO,mount.getKey(),mount.getValue(),i); | |||||
if (!success){ | if (!success){ | ||||
break; | break; | ||||
} | } | ||||
@@ -19,6 +19,8 @@ package org.dubhe.k8s.cache; | |||||
import cn.hutool.core.collection.CollectionUtil; | import cn.hutool.core.collection.CollectionUtil; | ||||
import org.dubhe.biz.base.constant.MagicNumConstant; | import org.dubhe.biz.base.constant.MagicNumConstant; | ||||
import org.dubhe.biz.base.constant.NumberConstant; | |||||
import org.dubhe.biz.base.constant.StringConstant; | |||||
import org.dubhe.biz.log.enums.LogEnum; | import org.dubhe.biz.log.enums.LogEnum; | ||||
import org.dubhe.biz.redis.utils.RedisUtils; | import org.dubhe.biz.redis.utils.RedisUtils; | ||||
import org.dubhe.k8s.api.PodApi; | import org.dubhe.k8s.api.PodApi; | ||||
@@ -33,6 +35,7 @@ import org.springframework.beans.factory.annotation.Autowired; | |||||
import org.springframework.beans.factory.annotation.Value; | import org.springframework.beans.factory.annotation.Value; | ||||
import org.springframework.util.CollectionUtils; | import org.springframework.util.CollectionUtils; | ||||
import java.util.HashMap; | |||||
import java.util.HashSet; | import java.util.HashSet; | ||||
import java.util.List; | import java.util.List; | ||||
import java.util.Set; | import java.util.Set; | ||||
@@ -188,6 +191,17 @@ public class ResourceCache { | |||||
} | } | ||||
} | } | ||||
/** | |||||
* 查询该 podName 缓存是否存在 | |||||
* | |||||
* @param podName Pod的名称 | |||||
* @return boolean true 存在 false 不存在 | |||||
*/ | |||||
public boolean isPodNameCached(String podName){ | |||||
String resourceName = (String) redisUtils.get(podNamePrefix +podName); | |||||
return StringUtils.isNotEmpty(resourceName); | |||||
} | |||||
/** | /** | ||||
* 删除pod名称缓存 | * 删除pod名称缓存 | ||||
* | * | ||||
@@ -235,4 +249,41 @@ public class ResourceCache { | |||||
return false; | return false; | ||||
} | } | ||||
} | } | ||||
/** | |||||
* 添加任务身份标识缓存 | |||||
* | |||||
* @param taskIdentify 任务身份标识 | |||||
* @param taskId 任务 ID | |||||
* @param taskName 任务名称 | |||||
* @param taskIdPrefix 任务 ID 前缀 | |||||
* @return boolean true 添加成功 false添加失败 | |||||
*/ | |||||
public boolean addTaskCache(String taskIdentify, Long taskId, String taskName, String taskIdPrefix){ | |||||
return redisUtils.hmset(taskIdentify, new HashMap<String, Object>(){{ | |||||
put(StringConstant.CACHE_TASK_ID, taskId); | |||||
put(StringConstant.CACHE_TASK_NAME, taskName); | |||||
}}, NumberConstant.MONTH_SECOND) && redisUtils.set(taskIdPrefix + String.valueOf(taskId), taskIdentify, NumberConstant.MONTH_SECOND); | |||||
} | |||||
/** | |||||
* 获取任务身份标识 | |||||
* | |||||
* @param taskId 任务 ID | |||||
* @param taskName 任务名称 | |||||
* @param taskIdPrefix 任务 ID 前缀 | |||||
* @return String 任务身份标识 | |||||
*/ | |||||
public String getTaskIdentify(Long taskId, String taskName, String taskIdPrefix){ | |||||
String taskIdentify = (String) redisUtils.get(taskIdPrefix + String.valueOf(taskId)); | |||||
if (taskIdentify == null){ | |||||
taskIdentify = StringUtils.getUUID(); | |||||
redisUtils.hmset(taskIdentify, new HashMap<String, Object>(){{ | |||||
put(StringConstant.CACHE_TASK_ID, taskId); | |||||
put(StringConstant.CACHE_TASK_NAME, taskName); | |||||
}}, NumberConstant.MONTH_SECOND); | |||||
redisUtils.set(taskIdPrefix + taskId, taskIdentify, NumberConstant.MONTH_SECOND); | |||||
} | |||||
return taskIdentify; | |||||
} | |||||
} | } |
@@ -23,8 +23,38 @@ import org.apache.http.HttpHost; | |||||
import org.apache.http.client.config.RequestConfig; | import org.apache.http.client.config.RequestConfig; | ||||
import org.dubhe.biz.log.enums.LogEnum; | import org.dubhe.biz.log.enums.LogEnum; | ||||
import org.dubhe.biz.log.utils.LogUtil; | import org.dubhe.biz.log.utils.LogUtil; | ||||
import org.dubhe.k8s.api.*; | |||||
import org.dubhe.k8s.api.impl.*; | |||||
import org.dubhe.k8s.api.DistributeTrainApi; | |||||
import org.dubhe.k8s.api.DubheDeploymentApi; | |||||
import org.dubhe.k8s.api.JupyterResourceApi; | |||||
import org.dubhe.k8s.api.LimitRangeApi; | |||||
import org.dubhe.k8s.api.LogMonitoringApi; | |||||
import org.dubhe.k8s.api.MetricsApi; | |||||
import org.dubhe.k8s.api.ModelOptJobApi; | |||||
import org.dubhe.k8s.api.ModelServingApi; | |||||
import org.dubhe.k8s.api.NamespaceApi; | |||||
import org.dubhe.k8s.api.NativeResourceApi; | |||||
import org.dubhe.k8s.api.NodeApi; | |||||
import org.dubhe.k8s.api.PersistentVolumeClaimApi; | |||||
import org.dubhe.k8s.api.PodApi; | |||||
import org.dubhe.k8s.api.ResourceQuotaApi; | |||||
import org.dubhe.k8s.api.TerminalApi; | |||||
import org.dubhe.k8s.api.TrainJobApi; | |||||
import org.dubhe.k8s.api.impl.DistributeTrainApiImpl; | |||||
import org.dubhe.k8s.api.impl.DubheDeploymentApiImpl; | |||||
import org.dubhe.k8s.api.impl.JupyterResourceApiImpl; | |||||
import org.dubhe.k8s.api.impl.LimitRangeApiImpl; | |||||
import org.dubhe.k8s.api.impl.LogMonitoringApiImpl; | |||||
import org.dubhe.k8s.api.impl.MetricsApiImpl; | |||||
import org.dubhe.k8s.api.impl.ModelOptJobApiImpl; | |||||
import org.dubhe.k8s.api.impl.ModelServingApiImpl; | |||||
import org.dubhe.k8s.api.impl.NamespaceApiImpl; | |||||
import org.dubhe.k8s.api.impl.NativeResourceApiImpl; | |||||
import org.dubhe.k8s.api.impl.NodeApiImpl; | |||||
import org.dubhe.k8s.api.impl.PersistentVolumeClaimApiImpl; | |||||
import org.dubhe.k8s.api.impl.PodApiImpl; | |||||
import org.dubhe.k8s.api.impl.ResourceQuotaApiImpl; | |||||
import org.dubhe.k8s.api.impl.TerminalApiImpl; | |||||
import org.dubhe.k8s.api.impl.TrainJobApiImpl; | |||||
import org.dubhe.k8s.cache.ResourceCache; | import org.dubhe.k8s.cache.ResourceCache; | ||||
import org.dubhe.k8s.properties.ClusterProperties; | import org.dubhe.k8s.properties.ClusterProperties; | ||||
import org.dubhe.k8s.utils.K8sUtils; | import org.dubhe.k8s.utils.K8sUtils; | ||||
@@ -37,6 +67,7 @@ import org.springframework.beans.factory.annotation.Value; | |||||
import org.springframework.boot.context.properties.EnableConfigurationProperties; | import org.springframework.boot.context.properties.EnableConfigurationProperties; | ||||
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.web.socket.server.standard.ServerEndpointExporter; | |||||
import java.io.IOException; | import java.io.IOException; | ||||
@@ -166,7 +197,6 @@ public class K8sConfig { | |||||
public RequestConfig.Builder customizeRequestConfig(RequestConfig.Builder builder) { | public RequestConfig.Builder customizeRequestConfig(RequestConfig.Builder builder) { | ||||
builder.setSocketTimeout(TEN_THOUSAND); | builder.setSocketTimeout(TEN_THOUSAND); | ||||
return builder; | return builder; | ||||
} | } | ||||
})); | })); | ||||
} | } | ||||
@@ -175,4 +205,16 @@ public class K8sConfig { | |||||
public ModelServingApi modelServingApi(K8sUtils k8sUtils){ | public ModelServingApi modelServingApi(K8sUtils k8sUtils){ | ||||
return new ModelServingApiImpl(k8sUtils); | return new ModelServingApiImpl(k8sUtils); | ||||
} | } | ||||
@Bean | |||||
public ServerEndpointExporter handlerAdapter() { | |||||
return new ServerEndpointExporter(); | |||||
} | |||||
@Bean | |||||
public TerminalApi terminalApi(K8sUtils k8sUtils){ | |||||
return new TerminalApiImpl(k8sUtils); | |||||
} | |||||
} | } |
@@ -38,6 +38,10 @@ public class K8sLabelConstants { | |||||
* 业务标签,用于标识业务,由业务层传入 | * 业务标签,用于标识业务,由业务层传入 | ||||
*/ | */ | ||||
public final static String BASE_TAG_BUSINESS = "platform/business"; | public final static String BASE_TAG_BUSINESS = "platform/business"; | ||||
/** | |||||
* 任务身份标签,用于标识任务身份,由业务层传入 | |||||
*/ | |||||
public final static String BASE_TAG_TASK_IDENTIFY = "platform/task-identify"; | |||||
/** | /** | ||||
* 运行环境标签,用于对不同环境回调进行分流 | * 运行环境标签,用于对不同环境回调进行分流 | ||||
*/ | */ | ||||
@@ -94,4 +94,9 @@ public class K8sParamConstants { | |||||
*/ | */ | ||||
public static final String RESOURCE_QUOTA_GPU_LIMITS_KEY = "requests.nvidia.com/gpu"; | public static final String RESOURCE_QUOTA_GPU_LIMITS_KEY = "requests.nvidia.com/gpu"; | ||||
//pod containerID 前缀 | |||||
public static final String CONTAINER_ID_PREFIX = "docker://"; | |||||
public static final String WAITING_REASON_CONTAINER_CREATING = "ContainerCreating"; | |||||
} | } |
@@ -37,6 +37,7 @@ public class BuildServiceBO { | |||||
private Map<String, String> labels; | private Map<String, String> labels; | ||||
private Map<String, String> selector; | private Map<String, String> selector; | ||||
private List<ServicePort> ports; | private List<ServicePort> ports; | ||||
private String type; | |||||
public BuildServiceBO(String namespace, String name, Map<String, String> labels, Map<String, String> selector){ | public BuildServiceBO(String namespace, String name, Map<String, String> labels, Map<String, String> selector){ | ||||
this.namespace = namespace; | this.namespace = namespace; | ||||
@@ -45,6 +46,14 @@ public class BuildServiceBO { | |||||
this.selector = selector; | this.selector = selector; | ||||
} | } | ||||
public BuildServiceBO(String namespace, String name, Map<String, String> labels, Map<String, String> selector,String type){ | |||||
this.namespace = namespace; | |||||
this.name = name; | |||||
this.labels = labels; | |||||
this.selector = selector; | |||||
this.type = type; | |||||
} | |||||
/** | /** | ||||
* 添加端口 | * 添加端口 | ||||
* @param port | * @param port | ||||
@@ -0,0 +1,168 @@ | |||||
/** | |||||
* Copyright 2020 Tianshu AI Platform. 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.k8s.domain.bo; | |||||
import cn.hutool.core.collection.CollectionUtil; | |||||
import lombok.Data; | |||||
import lombok.experimental.Accessors; | |||||
import org.dubhe.biz.base.constant.MagicNumConstant; | |||||
import org.dubhe.biz.base.utils.StringUtils; | |||||
import org.dubhe.k8s.annotation.K8sValidation; | |||||
import org.dubhe.k8s.enums.ValidationTypeEnum; | |||||
import org.springframework.util.CollectionUtils; | |||||
import java.util.ArrayList; | |||||
import java.util.HashMap; | |||||
import java.util.HashSet; | |||||
import java.util.List; | |||||
import java.util.Map; | |||||
import java.util.Set; | |||||
import java.util.stream.Collectors; | |||||
/** | |||||
* @description deployment BO | |||||
* @date 2021-06-30 | |||||
*/ | |||||
@Data | |||||
@Accessors(chain = true) | |||||
public class DeploymentBO { | |||||
/** | |||||
* 命名空间 | |||||
**/ | |||||
@K8sValidation(ValidationTypeEnum.K8S_RESOURCE_NAME) | |||||
private String namespace; | |||||
/** | |||||
* 资源名称 | |||||
**/ | |||||
@K8sValidation(ValidationTypeEnum.K8S_RESOURCE_NAME) | |||||
private String resourceName; | |||||
/** | |||||
* Number of desired pods | |||||
*/ | |||||
private Integer replicas; | |||||
/** | |||||
* GPU数量 | |||||
**/ | |||||
private Integer gpuNum; | |||||
/** | |||||
* 内存数量 单位Mi | |||||
**/ | |||||
private Integer memNum; | |||||
/** | |||||
* CPU数量 | |||||
**/ | |||||
private Integer cpuNum; | |||||
/** | |||||
* 镜像名称 | |||||
**/ | |||||
private String image; | |||||
/** | |||||
* 执行命令 | |||||
**/ | |||||
private List<String> cmdLines; | |||||
/** | |||||
* 文件存储服务挂载 key:pod内挂载路径 value:文件存储路径及配置 | |||||
**/ | |||||
private Map<String, PtMountDirBO> fsMounts; | |||||
/** | |||||
* 业务标签,用于标识业务模块 | |||||
**/ | |||||
@K8sValidation(ValidationTypeEnum.K8S_RESOURCE_NAME) | |||||
private String businessLabel; | |||||
/** | |||||
* 任务身份标签,用于标识任务身份 | |||||
**/ | |||||
private String taskIdentifyLabel; | |||||
/** | |||||
* 端口 | |||||
*/ | |||||
private Set<Integer> ports; | |||||
/** | |||||
* 获取nfs路径 | |||||
* @return | |||||
*/ | |||||
public List<String> getDirList(){ | |||||
if (CollectionUtil.isNotEmpty(fsMounts)){ | |||||
return fsMounts.values().stream().map(PtMountDirBO::getDir).collect(Collectors.toList()); | |||||
} | |||||
return new ArrayList<>(); | |||||
} | |||||
/** | |||||
* 设置nfs挂载 | |||||
* @param mountPath 容器内路径 | |||||
* @param dir nfs路径 | |||||
* @return | |||||
*/ | |||||
public DeploymentBO putfsMounts(String mountPath, String dir){ | |||||
if (StringUtils.isNotEmpty(mountPath) && StringUtils.isNotEmpty(dir)){ | |||||
if (fsMounts == null){ | |||||
fsMounts = new HashMap<>(MagicNumConstant.TWO); | |||||
} | |||||
fsMounts.put(mountPath,new PtMountDirBO(dir)); | |||||
} | |||||
return this; | |||||
} | |||||
/** | |||||
* 设置nfs挂载 | |||||
* @param mountPath 容器内路径 | |||||
* @param dir nfs路径及配置 | |||||
* @return | |||||
*/ | |||||
public DeploymentBO putfsMounts(String mountPath, PtMountDirBO dir){ | |||||
if (StringUtils.isNotEmpty(mountPath) && dir != null){ | |||||
if (fsMounts == null){ | |||||
fsMounts = new HashMap<>(MagicNumConstant.TWO); | |||||
} | |||||
fsMounts.put(mountPath,dir); | |||||
} | |||||
return this; | |||||
} | |||||
/** | |||||
* 添加端口 | |||||
* | |||||
* @param port | |||||
*/ | |||||
public void addPort(Integer port){ | |||||
if (port == null){ | |||||
return; | |||||
} | |||||
if (ports == null){ | |||||
ports = new HashSet<>(); | |||||
} | |||||
ports.add(port); | |||||
} | |||||
/** | |||||
* 添加端口 | |||||
* | |||||
* @param ports | |||||
*/ | |||||
public void addPorts(Set<Integer> ports){ | |||||
if (CollectionUtils.isEmpty(ports)){ | |||||
return; | |||||
} | |||||
if (ports == null){ | |||||
ports = new HashSet<>(); | |||||
} | |||||
ports.addAll(ports); | |||||
} | |||||
} |
@@ -84,6 +84,10 @@ public class DistributeTrainBO { | |||||
* 业务标签,用于标识业务模块 | * 业务标签,用于标识业务模块 | ||||
**/ | **/ | ||||
private String businessLabel; | private String businessLabel; | ||||
/** | |||||
* 任务身份标签,用于标识任务身份 | |||||
*/ | |||||
private String taskIdentifyLabel; | |||||
/** | /** | ||||
* 延时创建时间,单位:分钟 | * 延时创建时间,单位:分钟 | ||||
***/ | ***/ | ||||
@@ -81,6 +81,10 @@ public class ModelServingBO { | |||||
**/ | **/ | ||||
@K8sValidation(ValidationTypeEnum.K8S_RESOURCE_NAME) | @K8sValidation(ValidationTypeEnum.K8S_RESOURCE_NAME) | ||||
private String businessLabel; | private String businessLabel; | ||||
/** | |||||
* 任务身份标签,用于标识任务身份 | |||||
**/ | |||||
private String taskIdentifyLabel; | |||||
/** | /** | ||||
* http服务端口,null则不开放http服务 | * http服务端口,null则不开放http服务 | ||||
*/ | */ | ||||
@@ -17,15 +17,18 @@ | |||||
package org.dubhe.k8s.domain.bo; | package org.dubhe.k8s.domain.bo; | ||||
import cn.hutool.core.util.NumberUtil; | |||||
import lombok.Data; | import lombok.Data; | ||||
import org.dubhe.biz.base.constant.MagicNumConstant; | |||||
import org.dubhe.biz.base.functional.StringFormat; | import org.dubhe.biz.base.functional.StringFormat; | ||||
import org.dubhe.k8s.domain.vo.GpuUsageVO; | |||||
import org.dubhe.k8s.domain.vo.MetricsDataResultVO; | |||||
import org.dubhe.k8s.domain.vo.GpuTotalMemResultVO; | |||||
import org.dubhe.k8s.domain.vo.MetricsDataResultValueVO; | import org.dubhe.k8s.domain.vo.MetricsDataResultValueVO; | ||||
import org.springframework.util.CollectionUtils; | import org.springframework.util.CollectionUtils; | ||||
import java.util.ArrayList; | import java.util.ArrayList; | ||||
import java.util.HashMap; | |||||
import java.util.List; | import java.util.List; | ||||
import java.util.Map; | |||||
/** | /** | ||||
* @description Gpu 指标 BO | * @description Gpu 指标 BO | ||||
@@ -35,34 +38,70 @@ import java.util.List; | |||||
public class PrometheusMetricBO { | public class PrometheusMetricBO { | ||||
private String status; | private String status; | ||||
private MetricData data; | private MetricData data; | ||||
/** | /** | ||||
* 获取Gpu 使用率 | * 获取Gpu 使用率 | ||||
* @return List<GpuUsageVO> gpu使用列表 | |||||
* @return Map<String, Float> gpu使用率列表 | |||||
*/ | |||||
public Map<String, Float> getGpuUsage() { | |||||
Map<String, Float> gpuUsageMap = new HashMap<>(); | |||||
if (data == null || CollectionUtils.isEmpty(data.getResult())) { | |||||
return gpuUsageMap; | |||||
} | |||||
for (MetricResult result : data.getResult()) { | |||||
gpuUsageMap.put(result.getMetric().getAcc_id(), Float.valueOf(result.getValue().get(1).toString())); | |||||
} | |||||
return gpuUsageMap; | |||||
} | |||||
/** | |||||
* 获取GPU显存使用量 | |||||
* @return Map<String, String> gpu使用量列表 | |||||
*/ | |||||
public Map<String, String> getGpuMemValue() { | |||||
Map<String, String> gpuMemValueMap = new HashMap<>(); | |||||
if (data == null || CollectionUtils.isEmpty(data.getResult())) { | |||||
return gpuMemValueMap; | |||||
} | |||||
StringFormat memMetricsFormat = (value) -> { | |||||
return NumberUtil.isNumber(String.valueOf(value)) ? String.valueOf(Long.valueOf(String.valueOf(value)) / MagicNumConstant.BINARY_TEN_EXP) : String.valueOf(MagicNumConstant.ZERO); | |||||
}; | |||||
for (MetricResult result : data.getResult()) { | |||||
gpuMemValueMap.put(result.getMetric().getAcc_id(), memMetricsFormat.format(result.getValue().get(1).toString())); | |||||
} | |||||
return gpuMemValueMap; | |||||
} | |||||
/** | |||||
* 获取GPU显存总大小 | |||||
* @return List<GpuTotalMemResultVO> GPU显存总大小列表 | |||||
*/ | */ | ||||
public List<GpuUsageVO> getGpuUsage(){ | |||||
List<GpuUsageVO> gpuUsageVOList = new ArrayList<>(); | |||||
if (data == null || CollectionUtils.isEmpty(data.getResult())){ | |||||
return gpuUsageVOList; | |||||
public List<GpuTotalMemResultVO> getGpuTotalMemValue() { | |||||
List<GpuTotalMemResultVO> gpuTotalMemValueVOList = new ArrayList<>(); | |||||
if (data == null || CollectionUtils.isEmpty(data.getResult())) { | |||||
return gpuTotalMemValueVOList; | |||||
} | } | ||||
for (MetricResult result : data.getResult()){ | |||||
gpuUsageVOList.add(new GpuUsageVO(result.getMetric().getAcc_id(),Float.valueOf(result.getValue().get(1).toString()))); | |||||
StringFormat memMetricsFormat = (value) -> { | |||||
return NumberUtil.isNumber(String.valueOf(value)) ? String.valueOf(Long.valueOf(String.valueOf(value)) / MagicNumConstant.BINARY_TEN_EXP) : String.valueOf(MagicNumConstant.ZERO); | |||||
}; | |||||
for (MetricResult result : data.getResult()) { | |||||
gpuTotalMemValueVOList.add(new GpuTotalMemResultVO(result.getMetric().getAcc_id(), memMetricsFormat.format(result.getValue().get(1).toString()))); | |||||
} | } | ||||
return gpuUsageVOList; | |||||
return gpuTotalMemValueVOList; | |||||
} | } | ||||
/** | /** | ||||
* 获取value 列表 | * 获取value 列表 | ||||
* @return List<MetricsDataResultValueVO> 监控指标列表 | * @return List<MetricsDataResultValueVO> 监控指标列表 | ||||
*/ | */ | ||||
public List<MetricsDataResultValueVO> getValues(StringFormat stringFormat){ | |||||
public List<MetricsDataResultValueVO> getValues(StringFormat stringFormat) { | |||||
List<MetricsDataResultValueVO> list = new ArrayList<>(); | List<MetricsDataResultValueVO> list = new ArrayList<>(); | ||||
if (data == null || CollectionUtils.isEmpty(data.getResult())){ | |||||
if (data == null || CollectionUtils.isEmpty(data.getResult())) { | |||||
return list; | return list; | ||||
} | } | ||||
for (MetricResult result : data.getResult()){ | |||||
result.getValues().forEach(obj->{ | |||||
list.add(new MetricsDataResultValueVO(obj.get(0).toString(),stringFormat.format(obj.get(1).toString()))); | |||||
for (MetricResult result : data.getResult()) { | |||||
result.getValues().forEach(obj -> { | |||||
list.add(new MetricsDataResultValueVO(obj.get(0).toString(), stringFormat.format(obj.get(1).toString()))); | |||||
}); | }); | ||||
} | } | ||||
return list; | return list; | ||||
@@ -72,31 +111,98 @@ public class PrometheusMetricBO { | |||||
* 获取value 列表 | * 获取value 列表 | ||||
* @return List<MetricsDataResultValueVO> 监控指标列表 | * @return List<MetricsDataResultValueVO> 监控指标列表 | ||||
*/ | */ | ||||
public List<MetricsDataResultValueVO> getValues(MetricResult metricResult){ | |||||
public List<MetricsDataResultValueVO> getValues(MetricResult metricResult) { | |||||
List<MetricsDataResultValueVO> list = new ArrayList<>(); | List<MetricsDataResultValueVO> list = new ArrayList<>(); | ||||
if (metricResult == null || CollectionUtils.isEmpty(metricResult.getValues())){ | |||||
if (metricResult == null || CollectionUtils.isEmpty(metricResult.getValues())) { | |||||
return list; | return list; | ||||
} | } | ||||
metricResult.getValues().forEach(obj->{ | |||||
list.add(new MetricsDataResultValueVO(obj.get(0).toString(),obj.get(1).toString())); | |||||
metricResult.getValues().forEach(obj -> { | |||||
list.add(new MetricsDataResultValueVO(obj.get(0).toString(), obj.get(1).toString())); | |||||
}); | }); | ||||
return list; | return list; | ||||
} | } | ||||
/** | /** | ||||
* 获取 result列表 | |||||
* 获取 GPU使用率result列表 | |||||
* @return List<MetricsDataResultVO> 监控指标列表 | * @return List<MetricsDataResultVO> 监控指标列表 | ||||
*/ | */ | ||||
public List<MetricsDataResultVO> getResults(){ | |||||
List<MetricsDataResultVO> list = new ArrayList<>(); | |||||
if (data == null || CollectionUtils.isEmpty(data.getResult())){ | |||||
public Map<String, List<MetricsDataResultValueVO>> getGpuMetricsResults() { | |||||
Map<String, List<MetricsDataResultValueVO>> map = new HashMap<>(); | |||||
if (data == null || CollectionUtils.isEmpty(data.getResult())) { | |||||
return map; | |||||
} | |||||
for (MetricResult result : data.getResult()) { | |||||
map.put(result.getMetric().getAcc_id(), getValues(result)); | |||||
} | |||||
return map; | |||||
} | |||||
/** | |||||
* 获取value 列表 | |||||
* @return List<MetricsDataResultValueVO> 监控指标列表 | |||||
*/ | |||||
public List<MetricsDataResultValueVO> getFormatValues(MetricResult metricResult, StringFormat stringFormat) { | |||||
List<MetricsDataResultValueVO> list = new ArrayList<>(); | |||||
if (metricResult == null || CollectionUtils.isEmpty(metricResult.getValues())) { | |||||
return list; | return list; | ||||
} | } | ||||
for (MetricResult result : data.getResult()){ | |||||
list.add(new MetricsDataResultVO(result.getMetric().getAcc_id(),getValues(result))); | |||||
metricResult.getValues().forEach(obj -> { | |||||
list.add(new MetricsDataResultValueVO(obj.get(0).toString(), stringFormat.format(obj.get(1).toString()))); | |||||
}); | |||||
return list; | |||||
} | |||||
/** | |||||
* 获取 GPU显存使用量result列表 | |||||
* @return Map<String, List < MetricsDataResultValueVO>> 监控指标列表 | |||||
*/ | |||||
public Map<String, List<MetricsDataResultValueVO>> getGpuMemResults() { | |||||
Map<String, List<MetricsDataResultValueVO>> map = new HashMap<>(); | |||||
if (data == null || CollectionUtils.isEmpty(data.getResult())) { | |||||
return map; | |||||
} | |||||
StringFormat memMetricsFormat = (value) -> { | |||||
return NumberUtil.isNumber(String.valueOf(value)) ? String.valueOf(Long.valueOf(String.valueOf(value)) / MagicNumConstant.BINARY_TEN_EXP) : String.valueOf(MagicNumConstant.ZERO); | |||||
}; | |||||
for (MetricResult result : data.getResult()) { | |||||
map.put(result.getMetric().getAcc_id(), getFormatValues(result, memMetricsFormat)); | |||||
} | |||||
return map; | |||||
} | |||||
/** | |||||
* 获取value 列表 | |||||
* @return List<MetricsDataResultValueVO> 监控指标列表 | |||||
*/ | |||||
public String getGpuTotalValues(MetricResult metricResult, StringFormat stringFormat) { | |||||
List<String> strings = new ArrayList<>(); | |||||
if (metricResult == null || CollectionUtils.isEmpty(metricResult.getValues())) { | |||||
return ""; | |||||
} | |||||
metricResult.getValues().forEach(obj -> { | |||||
strings.add(stringFormat.format(obj.get(1).toString())); | |||||
}); | |||||
return strings.get(0); | |||||
} | |||||
/** | |||||
* 获取 GPU显存总量result列表 | |||||
* @return List<MetricsDataResultVO> 监控指标列表 | |||||
*/ | |||||
public List<GpuTotalMemResultVO> getGpuTotalMemResults() { | |||||
List<GpuTotalMemResultVO> list = new ArrayList<>(); | |||||
if (data == null || CollectionUtils.isEmpty(data.getResult())) { | |||||
return list; | |||||
} | |||||
StringFormat memMetricsFormat = (value) -> { | |||||
return NumberUtil.isNumber(String.valueOf(value)) ? String.valueOf(Long.valueOf(String.valueOf(value)) / MagicNumConstant.BINARY_TEN_EXP) : String.valueOf(MagicNumConstant.ZERO); | |||||
}; | |||||
for (MetricResult result : data.getResult()) { | |||||
list.add(new GpuTotalMemResultVO(result.getMetric().getAcc_id(), getGpuTotalValues(result, memMetricsFormat))); | |||||
} | } | ||||
return list; | return list; | ||||
} | } | ||||
} | } | ||||
@Data | @Data | ||||
@@ -57,4 +57,8 @@ public class PtDeploymentBO { | |||||
* 业务标签,用于标识业务模块 | * 业务标签,用于标识业务模块 | ||||
**/ | **/ | ||||
private String businessLabel; | private String businessLabel; | ||||
/** | |||||
* 任务身份标签,用于标识任务身份 | |||||
**/ | |||||
private String taskIdentifyLabel; | |||||
} | } |
@@ -57,4 +57,8 @@ public class PtJobBO { | |||||
* 业务标签,用于标识业务模块 | * 业务标签,用于标识业务模块 | ||||
**/ | **/ | ||||
private String businessLabel; | private String businessLabel; | ||||
/** | |||||
* 任务身份标签,用于标识任务身份 | |||||
**/ | |||||
private String taskIdentifyLabel; | |||||
} | } |
@@ -65,10 +65,16 @@ public class PtJupyterJobBO { | |||||
private GraphicsCardTypeEnum graphicsCardType; | private GraphicsCardTypeEnum graphicsCardType; | ||||
/**业务标签,用于标识业务模块**/ | /**业务标签,用于标识业务模块**/ | ||||
private String businessLabel; | private String businessLabel; | ||||
/**任务身份标签,用于标识任务身份**/ | |||||
private String taskIdentifyLabel; | |||||
/**延时创建时间,单位:分钟**/ | /**延时创建时间,单位:分钟**/ | ||||
private Integer delayCreateTime; | private Integer delayCreateTime; | ||||
/**定时删除时间,相对于实际创建时间,单位:分钟**/ | /**定时删除时间,相对于实际创建时间,单位:分钟**/ | ||||
private Integer delayDeleteTime; | private Integer delayDeleteTime; | ||||
/**pip包路径**/ | |||||
private String pipSitePackagePath; | |||||
/**pip包挂载路径**/ | |||||
private String pipSitePackageMountPath; | |||||
public List<String> getDirList(){ | public List<String> getDirList(){ | ||||
@@ -97,8 +97,20 @@ public class PtJupyterResourceBO { | |||||
* 业务标签,用于标识业务模块 | * 业务标签,用于标识业务模块 | ||||
**/ | **/ | ||||
private String businessLabel; | private String businessLabel; | ||||
/** | |||||
* 任务身份标签,用于标识任务唯一身份 | |||||
**/ | |||||
private String taskIdentifyLabel; | |||||
/** | /** | ||||
* 定时删除时间,单位:分钟 | * 定时删除时间,单位:分钟 | ||||
**/ | **/ | ||||
private Integer delayDeleteTime; | private Integer delayDeleteTime; | ||||
/** | |||||
* pip包路径 | |||||
*/ | |||||
private String pipSitePackageDir; | |||||
/** | |||||
* k8s内pip包路径 | |||||
*/ | |||||
private String pipSitePackageMountPath; | |||||
} | } |
@@ -33,9 +33,9 @@ public class PtMountDirBO { | |||||
private String dir; | private String dir; | ||||
/**是否只读 ture:是 false:否**/ | /**是否只读 ture:是 false:否**/ | ||||
private boolean readOnly; | private boolean readOnly; | ||||
/**是否回收 true:创建pv、pvc进行挂载,删除时同时删除数据 false:直接挂载**/ | |||||
/**是否回收 true:创建pv、pvc进行挂载,删除时同时删除数据 false且request和limit均为空:直接挂载**/ | |||||
private boolean recycle; | private boolean recycle; | ||||
/**存储配额 示例:500Mi 仅在pvc=true时生效**/ | |||||
/**存储配额 示例:500Mi* 仅在pvc=true时生效*/ | |||||
private String request; | private String request; | ||||
/**存储限额 示例:500Mi 仅在pvc=true时生效**/ | /**存储限额 示例:500Mi 仅在pvc=true时生效**/ | ||||
private String limit; | private String limit; | ||||
@@ -48,4 +48,22 @@ public class PtMountDirBO { | |||||
this.dir = dir; | this.dir = dir; | ||||
this.request = request; | this.request = request; | ||||
} | } | ||||
public PtMountDirBO(String dir, boolean readOnly){ | |||||
this.dir = dir; | |||||
this.readOnly = readOnly; | |||||
} | |||||
public PtMountDirBO(String dir, String request,boolean readOnly){ | |||||
this.dir = dir; | |||||
this.request = request; | |||||
this.readOnly = readOnly; | |||||
} | |||||
public PtMountDirBO(String dir, String request, String limit,boolean readOnly){ | |||||
this.dir = dir; | |||||
this.request = request; | |||||
this.limit = limit; | |||||
this.readOnly = readOnly; | |||||
} | |||||
} | } |
@@ -23,6 +23,7 @@ import org.dubhe.k8s.domain.resource.BizQuantity; | |||||
import lombok.Data; | import lombok.Data; | ||||
import lombok.experimental.Accessors; | import lombok.experimental.Accessors; | ||||
import org.dubhe.k8s.enums.AccessModeEnum; | import org.dubhe.k8s.enums.AccessModeEnum; | ||||
import org.dubhe.k8s.enums.PvReclaimPolicyEnum; | |||||
import java.util.HashMap; | import java.util.HashMap; | ||||
import java.util.HashSet; | import java.util.HashSet; | ||||
@@ -79,6 +80,11 @@ public class PtPersistentVolumeClaimBO { | |||||
**/ | **/ | ||||
private String path; | private String path; | ||||
/** | |||||
* 回收策略 | |||||
*/ | |||||
private String reclaimPolicy; | |||||
public PtPersistentVolumeClaimBO() { | public PtPersistentVolumeClaimBO() { | ||||
} | } | ||||
@@ -107,5 +113,10 @@ public class PtPersistentVolumeClaimBO { | |||||
add(AccessModeEnum.READ_WRITE_ONCE.getType()); | add(AccessModeEnum.READ_WRITE_ONCE.getType()); | ||||
}}; | }}; | ||||
this.setPvcName(resourceName+"-"+RandomUtil.randomString(MagicNumConstant.FIVE)); | this.setPvcName(resourceName+"-"+RandomUtil.randomString(MagicNumConstant.FIVE)); | ||||
if (bo.isRecycle()){ | |||||
this.reclaimPolicy = PvReclaimPolicyEnum.RECYCLE.getPolicy(); | |||||
}else { | |||||
this.reclaimPolicy = PvReclaimPolicyEnum.RETAIN.getPolicy(); | |||||
} | |||||
} | } | ||||
} | } |
@@ -57,7 +57,7 @@ public class PtResourceQuotaBO { | |||||
} | } | ||||
/** | /** | ||||
* 添加cpu 限制 | |||||
* 添加memory限制 | |||||
* @param amount 值 | * @param amount 值 | ||||
* @param format 单位 | * @param format 单位 | ||||
*/ | */ | ||||
@@ -0,0 +1,14 @@ | |||||
package org.dubhe.k8s.domain.bo; | |||||
import lombok.Data; | |||||
import lombok.experimental.Accessors; | |||||
/** | |||||
* @description 专业版终端 BO | |||||
* @date 2021-06-30 | |||||
*/ | |||||
@Data | |||||
@Accessors(chain = true) | |||||
public class TerminalBO extends DeploymentBO{ | |||||
} |
@@ -38,4 +38,7 @@ public class BizContainerStatus { | |||||
*/ | */ | ||||
@K8sField("state:waiting") | @K8sField("state:waiting") | ||||
private BizContainerStateWaiting waiting; | private BizContainerStateWaiting waiting; | ||||
@K8sField("containerID") | |||||
private String containerID; | |||||
} | } |
@@ -34,4 +34,12 @@ public class BizIntOrString { | |||||
private Integer Kind; | private Integer Kind; | ||||
@K8sField("StrVal") | @K8sField("StrVal") | ||||
private String StrVal; | private String StrVal; | ||||
public boolean equals(Integer value){ | |||||
return IntVal != null && IntVal.equals(value); | |||||
} | |||||
public boolean equals(String value){ | |||||
return StrVal != null && StrVal.equals(value); | |||||
} | |||||
} | } |
@@ -18,12 +18,18 @@ | |||||
package org.dubhe.k8s.domain.resource; | package org.dubhe.k8s.domain.resource; | ||||
import cn.hutool.core.util.StrUtil; | import cn.hutool.core.util.StrUtil; | ||||
import com.alibaba.fastjson.JSON; | |||||
import org.dubhe.biz.base.constant.MagicNumConstant; | |||||
import org.dubhe.biz.base.utils.StringUtils; | |||||
import org.dubhe.k8s.annotation.K8sField; | import org.dubhe.k8s.annotation.K8sField; | ||||
import org.dubhe.k8s.constant.K8sParamConstants; | |||||
import org.dubhe.k8s.domain.PtBaseResult; | import org.dubhe.k8s.domain.PtBaseResult; | ||||
import com.google.common.collect.Maps; | import com.google.common.collect.Maps; | ||||
import lombok.Data; | import lombok.Data; | ||||
import lombok.experimental.Accessors; | import lombok.experimental.Accessors; | ||||
import org.dubhe.k8s.constant.K8sLabelConstants; | import org.dubhe.k8s.constant.K8sLabelConstants; | ||||
import org.dubhe.k8s.enums.PodPhaseEnum; | |||||
import org.springframework.util.CollectionUtils; | |||||
import java.util.List; | import java.util.List; | ||||
import java.util.Map; | import java.util.Map; | ||||
@@ -59,6 +65,8 @@ public class BizPod extends PtBaseResult<BizPod> { | |||||
private String podIp; | private String podIp; | ||||
@K8sField("spec:volumes") | @K8sField("spec:volumes") | ||||
private List<BizVolume> volumes; | private List<BizVolume> volumes; | ||||
@K8sField("status:hostIP") | |||||
private String hostIP; | |||||
/** | /** | ||||
* Pending:待处理 | * Pending:待处理 | ||||
@@ -90,10 +98,20 @@ public class BizPod extends PtBaseResult<BizPod> { | |||||
*/ | */ | ||||
private String completedTime; | private String completedTime; | ||||
/** | |||||
* 获取业务标签 | |||||
*/ | |||||
public String getBusinessLabel() { | public String getBusinessLabel() { | ||||
return labels.get(K8sLabelConstants.BASE_TAG_BUSINESS); | return labels.get(K8sLabelConstants.BASE_TAG_BUSINESS); | ||||
} | } | ||||
/** | |||||
* 获取任务身份标识 | |||||
*/ | |||||
public String getTaskIdentifyLabel() { | |||||
return labels.get(K8sLabelConstants.BASE_TAG_TASK_IDENTIFY); | |||||
} | |||||
/** | /** | ||||
* 根据键获取label | * 根据键获取label | ||||
* | * | ||||
@@ -114,15 +132,40 @@ public class BizPod extends PtBaseResult<BizPod> { | |||||
if (containerStatuses == null) { | if (containerStatuses == null) { | ||||
return null; | return null; | ||||
} | } | ||||
containerStatuses.stream().map(obj -> { | |||||
containerStatuses.forEach(obj -> { | |||||
if (obj.getTerminated() != null) { | if (obj.getTerminated() != null) { | ||||
messages.append(StrUtil.format(CONTAINER_STATE_MESSAGE, name, phase, obj.getTerminated().getReason(), obj.getTerminated().getMessage())); | messages.append(StrUtil.format(CONTAINER_STATE_MESSAGE, name, phase, obj.getTerminated().getReason(), obj.getTerminated().getMessage())); | ||||
} | } | ||||
if (obj.getWaiting() != null) { | if (obj.getWaiting() != null) { | ||||
messages.append(StrUtil.format(CONTAINER_STATE_MESSAGE, name, phase, obj.getWaiting().getReason(), obj.getWaiting().getMessage())); | messages.append(StrUtil.format(CONTAINER_STATE_MESSAGE, name, phase, obj.getWaiting().getReason(), obj.getWaiting().getMessage())); | ||||
} | } | ||||
return null; | |||||
}); | }); | ||||
return messages.toString(); | return messages.toString(); | ||||
} | } | ||||
//获取 容器镜像id | |||||
public String getContainerId(){ | |||||
String containerID = null; | |||||
if (!CollectionUtils.isEmpty(containerStatuses)){ | |||||
for (BizContainerStatus bizContainerStatus : containerStatuses){ | |||||
if (StringUtils.isNotEmpty(bizContainerStatus.getContainerID())){ | |||||
containerID = bizContainerStatus.getContainerID(); | |||||
} | |||||
} | |||||
} | |||||
if (StringUtils.isNotEmpty(containerID)){ | |||||
return containerID.replace(K8sParamConstants.CONTAINER_ID_PREFIX,""); | |||||
} | |||||
return containerID; | |||||
} | |||||
public String getRealPodPhase(){ | |||||
if (PodPhaseEnum.RUNNING.getPhase().equals(phase) && !CollectionUtils.isEmpty(containerStatuses) && containerStatuses.get(MagicNumConstant.ZERO).getWaiting() != null){ | |||||
String waitingReason = containerStatuses.get(MagicNumConstant.ZERO).getWaiting().getReason(); | |||||
if(waitingReason != null && !K8sParamConstants.WAITING_REASON_CONTAINER_CREATING.equals(waitingReason)){ | |||||
return PodPhaseEnum.FAILED.getPhase(); | |||||
} | |||||
} | |||||
return phase; | |||||
} | |||||
} | } |
@@ -20,7 +20,10 @@ package org.dubhe.k8s.domain.resource; | |||||
import lombok.Data; | import lombok.Data; | ||||
import lombok.experimental.Accessors; | import lombok.experimental.Accessors; | ||||
import org.dubhe.biz.base.utils.MathUtils; | import org.dubhe.biz.base.utils.MathUtils; | ||||
import org.dubhe.biz.base.utils.StringUtils; | |||||
import org.dubhe.k8s.annotation.K8sField; | import org.dubhe.k8s.annotation.K8sField; | ||||
import org.dubhe.k8s.constant.K8sParamConstants; | |||||
import org.dubhe.k8s.utils.UnitConvertUtils; | |||||
/** | /** | ||||
* @description BizQuantity实体类 | * @description BizQuantity实体类 | ||||
@@ -43,19 +46,28 @@ public class BizQuantity { | |||||
this.format = format; | this.format = format; | ||||
} | } | ||||
public boolean isIllegal() { | |||||
return true; | |||||
} | |||||
/** | /** | ||||
* 单位相同时相减 | |||||
* 不同单位相减 | |||||
* | |||||
* @param bizQuantity 减数 | * @param bizQuantity 减数 | ||||
* @return | |||||
* @param limitsKey 类型 | |||||
* @return BizQuantity | |||||
*/ | */ | ||||
public BizQuantity reduce(BizQuantity bizQuantity){ | |||||
if (bizQuantity == null || !bizQuantity.getFormat().equals(format)){ | |||||
public BizQuantity reduce(BizQuantity bizQuantity,String limitsKey){ | |||||
if (bizQuantity == null || StringUtils.isAllEmpty(limitsKey)){ | |||||
return this; | return this; | ||||
} | } | ||||
return new BizQuantity(MathUtils.reduce(amount,bizQuantity.getAmount()),format); | |||||
switch (limitsKey){ | |||||
case K8sParamConstants.RESOURCE_QUOTA_CPU_LIMITS_KEY : | |||||
Long cpuDiff = UnitConvertUtils.cpuFormatToN(amount,format) - UnitConvertUtils.cpuFormatToN(bizQuantity.getAmount(),bizQuantity.getFormat()); | |||||
return new BizQuantity(String.valueOf(cpuDiff),K8sParamConstants.CPU_UNIT_N); | |||||
case K8sParamConstants.RESOURCE_QUOTA_MEMORY_LIMITS_KEY : | |||||
Long memDiff = UnitConvertUtils.memFormatToMi(amount,format) - UnitConvertUtils.memFormatToMi(bizQuantity.getAmount(),bizQuantity.getFormat()); | |||||
return new BizQuantity(String.valueOf(memDiff),K8sParamConstants.MEM_UNIT); | |||||
case K8sParamConstants.RESOURCE_QUOTA_GPU_LIMITS_KEY : | |||||
return new BizQuantity(MathUtils.reduce(amount,bizQuantity.getAmount()),format); | |||||
default: | |||||
return this; | |||||
} | |||||
} | } | ||||
} | } |
@@ -68,7 +68,7 @@ public class BizResourceQuota extends PtBaseResult<BizResourceQuota> { | |||||
if (!CollectionUtils.isEmpty(hard)){ | if (!CollectionUtils.isEmpty(hard)){ | ||||
for (Map.Entry<String, BizQuantity> entry : hard.entrySet()) { | for (Map.Entry<String, BizQuantity> entry : hard.entrySet()) { | ||||
if (used.get(entry.getKey()) != null){ | if (used.get(entry.getKey()) != null){ | ||||
remainder.put(entry.getKey(),entry.getValue().reduce(used.get(entry.getKey()))); | |||||
remainder.put(entry.getKey(),entry.getValue().reduce(used.get(entry.getKey()),entry.getKey())); | |||||
} | } | ||||
} | } | ||||
} | } | ||||
@@ -20,6 +20,9 @@ package org.dubhe.k8s.domain.resource; | |||||
import lombok.Data; | import lombok.Data; | ||||
import lombok.experimental.Accessors; | import lombok.experimental.Accessors; | ||||
import org.dubhe.k8s.annotation.K8sField; | import org.dubhe.k8s.annotation.K8sField; | ||||
import org.springframework.util.CollectionUtils; | |||||
import java.util.List; | |||||
/** | /** | ||||
* @description Kubernetes Service | * @description Kubernetes Service | ||||
@@ -30,8 +33,25 @@ import org.dubhe.k8s.annotation.K8sField; | |||||
public class BizService { | public class BizService { | ||||
@K8sField("metadata:name") | @K8sField("metadata:name") | ||||
private String name; | private String name; | ||||
@K8sField("metadata:namespace") | @K8sField("metadata:namespace") | ||||
private String namespace; | private String namespace; | ||||
@K8sField("metadata:uid") | @K8sField("metadata:uid") | ||||
private String uid; | private String uid; | ||||
@K8sField("spec:ports") | |||||
private List<BizServicePort> ports; | |||||
public BizServicePort getServicePortByTargetPort(Integer targetPort){ | |||||
if (CollectionUtils.isEmpty(ports) || targetPort == null){ | |||||
return null; | |||||
} | |||||
for (BizServicePort port : ports) { | |||||
if (port.getTargetPort() != null && port.getTargetPort().equals(targetPort)){ | |||||
return port; | |||||
} | |||||
} | |||||
return null; | |||||
} | |||||
} | } |
@@ -0,0 +1,46 @@ | |||||
/** | |||||
* Copyright 2020 Tianshu AI Platform. 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.k8s.domain.resource; | |||||
import lombok.Data; | |||||
import lombok.experimental.Accessors; | |||||
import org.dubhe.k8s.annotation.K8sField; | |||||
/** | |||||
* @description Kubernetes ServicePort | |||||
* @date 2020-09-09 | |||||
*/ | |||||
@Data | |||||
@Accessors(chain = true) | |||||
public class BizServicePort { | |||||
@K8sField("name") | |||||
private String name; | |||||
@K8sField("nodePort") | |||||
private Integer nodePort; | |||||
@K8sField("port") | |||||
private Integer port; | |||||
@K8sField("protocol") | |||||
private String protocol; | |||||
@K8sField("targetPort") | |||||
private BizIntOrString targetPort; | |||||
} |
@@ -0,0 +1,54 @@ | |||||
/** | |||||
* Copyright 2020 Tianshu AI Platform. 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.k8s.domain.vo; | |||||
import lombok.AllArgsConstructor; | |||||
import lombok.Data; | |||||
import lombok.NoArgsConstructor; | |||||
import lombok.experimental.Accessors; | |||||
import java.util.List; | |||||
/** | |||||
* @description GPU监控数据 | |||||
* @date 2021-07-22 | |||||
*/ | |||||
@Data | |||||
@NoArgsConstructor | |||||
@AllArgsConstructor | |||||
@Accessors(chain = true) | |||||
public class GpuMetricsDataResultVO { | |||||
/** | |||||
* 显卡编号 | |||||
*/ | |||||
private String accId; | |||||
/** | |||||
* GPU显存总大小 | |||||
*/ | |||||
private String totalMemValues; | |||||
/** | |||||
* GPU使用率监控指标值 | |||||
*/ | |||||
List<MetricsDataResultValueVO> gpuMetricsValues; | |||||
/** | |||||
* GPU显存使用量监控指标值 | |||||
*/ | |||||
List<MetricsDataResultValueVO> gpuMemValues; | |||||
} |
@@ -0,0 +1,44 @@ | |||||
/** | |||||
* Copyright 2020 Tianshu AI Platform. 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.k8s.domain.vo; | |||||
import lombok.AllArgsConstructor; | |||||
import lombok.Data; | |||||
import lombok.NoArgsConstructor; | |||||
import lombok.experimental.Accessors; | |||||
/** | |||||
* @description GPU显存总量result | |||||
* @date 2021-07-22 | |||||
*/ | |||||
@Data | |||||
@NoArgsConstructor | |||||
@AllArgsConstructor | |||||
@Accessors(chain = true) | |||||
public class GpuTotalMemResultVO { | |||||
/** | |||||
* 显卡编号 | |||||
*/ | |||||
private String accId; | |||||
/** | |||||
* GPU显存总大小 | |||||
*/ | |||||
private String gpuTotalMemValue; | |||||
} |
@@ -0,0 +1,52 @@ | |||||
/** | |||||
* Copyright 2020 Tianshu AI Platform. 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.k8s.domain.vo; | |||||
import lombok.AllArgsConstructor; | |||||
import lombok.Data; | |||||
import lombok.NoArgsConstructor; | |||||
import lombok.experimental.Accessors; | |||||
/** | |||||
* @description GPU实时监控数据 | |||||
* @date 2021-07-23 | |||||
*/ | |||||
@Data | |||||
@NoArgsConstructor | |||||
@AllArgsConstructor | |||||
@Accessors(chain = true) | |||||
public class GpuValueVO { | |||||
/** | |||||
* 显卡id | |||||
*/ | |||||
private String accId; | |||||
/** | |||||
* 使用率 百分比 | |||||
*/ | |||||
Float usage; | |||||
/** | |||||
* GPU显存总大小 | |||||
*/ | |||||
private String gpuTotalMemValue; | |||||
/** | |||||
* GPU显存使用量 | |||||
*/ | |||||
String gpuMemValue; | |||||
} |
@@ -40,9 +40,9 @@ public class PodRangeMetricsVO { | |||||
*/ | */ | ||||
List<MetricsDataResultValueVO> cpuMetrics; | List<MetricsDataResultValueVO> cpuMetrics; | ||||
/** | /** | ||||
* gpu 监控指标 value为使用百分比 | |||||
* gpu 监控指标 | |||||
*/ | */ | ||||
List<MetricsDataResultVO> gpuMetrics; | |||||
List<GpuMetricsDataResultVO> gpuMetrics; | |||||
/** | /** | ||||
* 内存 监控指标 value为占用内存 单位 Ki | * 内存 监控指标 value为占用内存 单位 Ki | ||||
*/ | */ | ||||
@@ -24,10 +24,8 @@ import org.dubhe.biz.base.constant.MagicNumConstant; | |||||
import org.dubhe.biz.base.utils.MathUtils; | import org.dubhe.biz.base.utils.MathUtils; | ||||
import org.dubhe.biz.base.utils.StringUtils; | import org.dubhe.biz.base.utils.StringUtils; | ||||
import org.dubhe.k8s.utils.UnitConvertUtils; | import org.dubhe.k8s.utils.UnitConvertUtils; | ||||
import org.springframework.util.CollectionUtils; | |||||
import java.io.Serializable; | import java.io.Serializable; | ||||
import java.util.ArrayList; | |||||
import java.util.List; | import java.util.List; | ||||
/** | /** | ||||
@@ -98,9 +96,9 @@ public class PtPodsVO implements Serializable { | |||||
**/ | **/ | ||||
private String gpuUsed; | private String gpuUsed; | ||||
/** | /** | ||||
* gpu使用百分比 | |||||
* gpu实时监控数据 | |||||
*/ | */ | ||||
private List<GpuUsageVO> gpuUsagePersent; | |||||
private List<GpuValueVO> gpuUsagePersent; | |||||
public PtPodsVO(String namespace,String podName,String cpuRequestAmount,String cpuUsageAmount,String cpuRequestFormat,String cpuUsageFormat,String memoryRequestAmount,String memoryUsageAmount,String memoryRequestFormat,String memoryUsageFormat,String nodeName,String status,String gpuUsed){ | public PtPodsVO(String namespace,String podName,String cpuRequestAmount,String cpuUsageAmount,String cpuRequestFormat,String cpuUsageFormat,String memoryRequestAmount,String memoryUsageAmount,String memoryRequestFormat,String memoryUsageFormat,String nodeName,String status,String gpuUsed){ | ||||
this.namespace = namespace; | this.namespace = namespace; | ||||
@@ -142,10 +140,4 @@ public class PtPodsVO implements Serializable { | |||||
} | } | ||||
} | } | ||||
public void addGpuUsage(String accId,Float usage){ | |||||
if (CollectionUtils.isEmpty(gpuUsagePersent)){ | |||||
gpuUsagePersent = new ArrayList<>(); | |||||
} | |||||
gpuUsagePersent.add(new GpuUsageVO(accId,usage)); | |||||
} | |||||
} | } |
@@ -0,0 +1,42 @@ | |||||
/** | |||||
* Copyright 2020 Tianshu AI Platform. 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.k8s.domain.vo; | |||||
import lombok.Data; | |||||
import lombok.NoArgsConstructor; | |||||
import lombok.experimental.Accessors; | |||||
import org.dubhe.k8s.domain.PtBaseResult; | |||||
import org.dubhe.k8s.domain.resource.BizDeployment; | |||||
import org.dubhe.k8s.domain.resource.BizService; | |||||
/** | |||||
* @description 专业版终端 VO | |||||
* @date 2021-06-30 | |||||
*/ | |||||
@Data | |||||
@NoArgsConstructor | |||||
@Accessors(chain = true) | |||||
public class TerminalResourceVO extends PtBaseResult<TerminalResourceVO> { | |||||
private BizDeployment bizDeployment; | |||||
private BizService bizService; | |||||
public TerminalResourceVO(BizDeployment bizDeployment, BizService bizService){ | |||||
this.bizDeployment = bizDeployment; | |||||
this.bizService = bizService; | |||||
} | |||||
} |
@@ -17,10 +17,15 @@ | |||||
package org.dubhe.k8s.domain.vo; | package org.dubhe.k8s.domain.vo; | ||||
import io.fabric8.kubernetes.api.model.EmptyDirVolumeSource; | |||||
import io.fabric8.kubernetes.api.model.Quantity; | |||||
import io.fabric8.kubernetes.api.model.Volume; | import io.fabric8.kubernetes.api.model.Volume; | ||||
import io.fabric8.kubernetes.api.model.VolumeBuilder; | |||||
import io.fabric8.kubernetes.api.model.VolumeMount; | import io.fabric8.kubernetes.api.model.VolumeMount; | ||||
import io.fabric8.kubernetes.api.model.VolumeMountBuilder; | |||||
import lombok.Data; | import lombok.Data; | ||||
import lombok.experimental.Accessors; | import lombok.experimental.Accessors; | ||||
import org.dubhe.k8s.constant.K8sParamConstants; | |||||
import org.dubhe.k8s.domain.PtBaseResult; | import org.dubhe.k8s.domain.PtBaseResult; | ||||
import java.util.ArrayList; | import java.util.ArrayList; | ||||
@@ -57,4 +62,19 @@ public class VolumeVO extends PtBaseResult<VolumeVO> { | |||||
} | } | ||||
volumes.add(volume); | volumes.add(volume); | ||||
} | } | ||||
/** | |||||
* 添加shm | |||||
*/ | |||||
public void addShmFsVolume(Quantity shmMemory){ | |||||
addVolumeMount(new VolumeMountBuilder() | |||||
.withName(K8sParamConstants.SHM_NAME) | |||||
.withMountPath(K8sParamConstants.SHM_MOUNTPATH) | |||||
.build()); | |||||
addVolume(new VolumeBuilder() | |||||
.withName(K8sParamConstants.SHM_NAME) | |||||
.withEmptyDir(new EmptyDirVolumeSource(K8sParamConstants.SHM_MEDIUM, shmMemory)) | |||||
.build()); | |||||
} | |||||
} | } |
@@ -48,6 +48,10 @@ public enum BusinessLabelServiceNameEnum { | |||||
* 批量服务 | * 批量服务 | ||||
*/ | */ | ||||
BATCH_SERVING(BizEnum.BATCH_SERVING.getBizCode(), ApplicationNameConst.SERVER_SERVING), | BATCH_SERVING(BizEnum.BATCH_SERVING.getBizCode(), ApplicationNameConst.SERVER_SERVING), | ||||
/** | |||||
* 专业版终端 | |||||
*/ | |||||
TERMINAL(BizEnum.TERMINAL.getBizCode(), ApplicationNameConst.TERMINAL), | |||||
; | ; | ||||
/** | /** | ||||
* 业务标签 | * 业务标签 | ||||
@@ -0,0 +1,40 @@ | |||||
/** | |||||
* Copyright 2020 Tianshu AI Platform. 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.k8s.enums; | |||||
import lombok.Getter; | |||||
/** | |||||
* @description service 类型 | |||||
* @date 2021-07-26 | |||||
*/ | |||||
@Getter | |||||
public enum ServiceTypeENum { | |||||
CLUSTER_IP("ClusterIP"), | |||||
NODE_PORT("NodePort"), | |||||
LOAD_BALANCER("LoadBalancer"), | |||||
; | |||||
private String type; | |||||
ServiceTypeENum(String type) { | |||||
this.type = type; | |||||
} | |||||
} |
@@ -0,0 +1,42 @@ | |||||
/** | |||||
* Copyright 2020 Tianshu AI Platform. 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.k8s.enums; | |||||
/** | |||||
* @description Websocket tocpic 枚举 | |||||
* @date 2021-7-20 | |||||
*/ | |||||
public enum WebsocketTopicEnum { | |||||
/** | |||||
* 资源监控 topic | |||||
*/ | |||||
RESOURCE_MONITOR("resourceMonitor"), | |||||
; | |||||
private String topic; | |||||
WebsocketTopicEnum(String topic) { | |||||
this.topic = topic; | |||||
} | |||||
public String getTopic() { | |||||
return topic; | |||||
} | |||||
} |
@@ -150,7 +150,7 @@ public class K8sUtils implements ApplicationContextAware { | |||||
* @param gpuNum | * @param gpuNum | ||||
* @return | * @return | ||||
*/ | */ | ||||
public Map<String, String> gpuSelector(Integer gpuNum) { | |||||
public static Map<String, String> gpuSelector(Integer gpuNum) { | |||||
Map<String, String> gpuSelector = new HashMap<>(2); | Map<String, String> gpuSelector = new HashMap<>(2); | ||||
if (gpuNum != null && gpuNum > 0) { | if (gpuNum != null && gpuNum > 0) { | ||||
gpuSelector.put(K8sLabelConstants.NODE_GPU_LABEL_KEY, K8sLabelConstants.NODE_GPU_LABEL_VALUE); | gpuSelector.put(K8sLabelConstants.NODE_GPU_LABEL_KEY, K8sLabelConstants.NODE_GPU_LABEL_VALUE); | ||||