| @@ -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); | ||||