diff --git a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/controller/service/ServiceController.java b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/controller/service/ServiceController.java new file mode 100644 index 00000000..c5df3ec9 --- /dev/null +++ b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/controller/service/ServiceController.java @@ -0,0 +1,87 @@ +package com.ruoyi.platform.controller.service; + +import com.ruoyi.common.core.web.controller.BaseController; +import com.ruoyi.common.core.web.domain.GenericsAjaxResult; +import com.ruoyi.platform.domain.Service; +import com.ruoyi.platform.domain.ServiceVersion; +import com.ruoyi.platform.service.ServiceService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.io.IOException; + +@RestController +@RequestMapping("service") +@Api("服务") +public class ServiceController extends BaseController { + @Resource + private ServiceService serviceService; + + + @GetMapping + @ApiOperation("分页查询服务列表") + public GenericsAjaxResult> queryByPageService(Service service, int page, int size) throws IOException { + PageRequest pageRequest = PageRequest.of(page, size); + return genericsSuccess(serviceService.queryByPageService(service, pageRequest)); + } + + @GetMapping("/serviceVersion") + @ApiOperation("分页查询服务版本列表") + public GenericsAjaxResult> queryByPageServiceVersion(ServiceVersion serviceVersion, int page, int size) throws IOException { + PageRequest pageRequest = PageRequest.of(page, size); + return genericsSuccess(serviceService.queryByPageServiceVersion(serviceVersion, pageRequest)); + } + + @PostMapping + @ApiOperation("新增服务") + public GenericsAjaxResult addService(@RequestBody Service service) { + return genericsSuccess(serviceService.addService(service)); + } + + @PostMapping("/serviceVersion") + @ApiOperation("新增服务版本") + public GenericsAjaxResult addServiceVersion(@RequestBody ServiceVersion serviceVersion) { + return genericsSuccess(serviceService.addServiceVersion(serviceVersion)); + } + + @PutMapping + @ApiOperation("编辑服务") + public GenericsAjaxResult editService(@RequestBody Service service) { + return genericsSuccess(serviceService.editService(service)); + } + + @PutMapping("/serviceVersion") + @ApiOperation("编辑服务版本") + public GenericsAjaxResult editServiceVersion(@RequestBody ServiceVersion serviceVersion) { + return genericsSuccess(serviceService.editServiceVersion(serviceVersion)); + } + + @GetMapping("/serviceVersionDetail/{id}") + @ApiOperation("查询服务版本详细信息") + public GenericsAjaxResult getServiceVersion(@PathVariable("id") Long id) { + return genericsSuccess(serviceService.getServiceVersion(id)); + } + + @DeleteMapping("{id}") + @ApiOperation("删除服务") + public GenericsAjaxResult deleteService(@PathVariable("id") Long id){ + return genericsSuccess(serviceService.deleteService(id)); + } + + @DeleteMapping("/serviceVersion/{id}") + @ApiOperation("删除服务版本") + public GenericsAjaxResult deleteServiceVersion(@PathVariable("id") Long id){ + return genericsSuccess(serviceService.deleteServiceVersion(id)); + } + + @GetMapping("/runServiceVersion/{id}") + @ApiOperation("启动服务版本") + public GenericsAjaxResult runServiceVersion(@PathVariable("id") Long id){ + serviceService.runServiceVersion(id); + return genericsSuccess(""); + } +} diff --git a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/domain/Service.java b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/domain/Service.java new file mode 100644 index 00000000..6c7168ce --- /dev/null +++ b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/domain/Service.java @@ -0,0 +1,36 @@ +package com.ruoyi.platform.domain; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.fasterxml.jackson.databind.PropertyNamingStrategy; +import com.fasterxml.jackson.databind.annotation.JsonNaming; +import io.swagger.annotations.ApiModel; +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; + +@JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class) +@ApiModel("服务") +@Data +public class Service implements Serializable { + private Long id; + + private String serviceName; + + private Integer serviceType; + + private String description; + + private String createBy; + + private String updateBy; + + private Date createTime; + + private Date updateTime; + + private Integer state; + + @TableField(exist = false) + private Integer versionCount; +} diff --git a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/domain/ServiceVersion.java b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/domain/ServiceVersion.java new file mode 100644 index 00000000..ed998779 --- /dev/null +++ b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/domain/ServiceVersion.java @@ -0,0 +1,48 @@ +package com.ruoyi.platform.domain; + +import com.fasterxml.jackson.databind.PropertyNamingStrategy; +import com.fasterxml.jackson.databind.annotation.JsonNaming; +import io.swagger.annotations.ApiModel; +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; + +@JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class) +@ApiModel("服务") +@Data +public class ServiceVersion implements Serializable { + private Long id; + + private Long serviceId; + + private String version; + + private String model; + + private String image; + + private String resource; + + private Integer replicas; + + private String mountPath; + + private String envVariables; + + private String codeConfig; + + private String command; + + private String url; + + private String createBy; + + private String updateBy; + + private Date createTime; + + private Date updateTime; + + private Integer state; +} diff --git a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/mapper/ServiceDao.java b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/mapper/ServiceDao.java new file mode 100644 index 00000000..dfaa4e37 --- /dev/null +++ b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/mapper/ServiceDao.java @@ -0,0 +1,32 @@ +package com.ruoyi.platform.mapper; + +import com.ruoyi.platform.domain.Service; +import com.ruoyi.platform.domain.ServiceVersion; +import org.apache.ibatis.annotations.Param; +import org.springframework.data.domain.Pageable; + +import java.util.List; + +public interface ServiceDao { + + long countService(@Param("service") com.ruoyi.platform.domain.Service service); + + long countServiceVersion(@Param("serviceVersion") ServiceVersion serviceVersion); + + List queryByPageService(@Param("service") com.ruoyi.platform.domain.Service service, @Param("pageable") Pageable pageable); + + List queryByPageServiceVersion(@Param("serviceVersion") ServiceVersion serviceVersion, @Param("pageable") Pageable pageable); + + int insertService(@Param("service") com.ruoyi.platform.domain.Service service); + + int insertServiceVersion(@Param("serviceVersion") ServiceVersion serviceVersion); + + int updateService(@Param("service") Service service); + + int updateServiceVersion(@Param("serviceVersion") ServiceVersion serviceVersion); + + Service getServiceById(Long id); + + ServiceVersion getServiceVersionById(Long id); + +} diff --git a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/ServiceService.java b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/ServiceService.java new file mode 100644 index 00000000..1129e698 --- /dev/null +++ b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/ServiceService.java @@ -0,0 +1,30 @@ +package com.ruoyi.platform.service; + +import com.ruoyi.platform.domain.Service; +import com.ruoyi.platform.domain.ServiceVersion; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; + +import java.io.IOException; + +public interface ServiceService { + Page queryByPageService(Service service, PageRequest pageRequest) throws IOException; + + Page queryByPageServiceVersion(ServiceVersion serviceVersion, PageRequest pageRequest) throws IOException; + + Service addService(Service service); + + ServiceVersion addServiceVersion(ServiceVersion serviceVersion); + + Service editService(Service service); + + ServiceVersion editServiceVersion(ServiceVersion serviceVersion); + + ServiceVersion getServiceVersion(Long id); + + String deleteService(Long id); + + String deleteServiceVersion(Long id); + + void runServiceVersion(Long id); +} diff --git a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/ServiceServiceImpl.java b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/ServiceServiceImpl.java new file mode 100644 index 00000000..21b7d9aa --- /dev/null +++ b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/ServiceServiceImpl.java @@ -0,0 +1,117 @@ +package com.ruoyi.platform.service.impl; + +import com.ruoyi.common.security.utils.SecurityUtils; +import com.ruoyi.platform.constant.Constant; +import com.ruoyi.platform.domain.ServiceVersion; +import com.ruoyi.platform.mapper.ServiceDao; +import com.ruoyi.platform.service.ServiceService; +import com.ruoyi.system.api.model.LoginUser; +import org.apache.commons.lang3.StringUtils; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.PageRequest; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.io.IOException; +import java.util.List; + +@Service("serviceService") +public class ServiceServiceImpl implements ServiceService { + + @Resource + private ServiceDao serviceDao; + + @Override + public Page queryByPageService(com.ruoyi.platform.domain.Service service, PageRequest pageRequest) throws IOException { + long total = serviceDao.countService(service); + List services = serviceDao.queryByPageService(service, pageRequest); + return new PageImpl<>(services, pageRequest, total); + } + + @Override + public Page queryByPageServiceVersion(ServiceVersion serviceVersion, PageRequest pageRequest) throws IOException { + long total = serviceDao.countServiceVersion(serviceVersion); + List serviceVersions = serviceDao.queryByPageServiceVersion(serviceVersion, pageRequest); + return new PageImpl<>(serviceVersions, pageRequest, total); + } + + @Override + public com.ruoyi.platform.domain.Service addService(com.ruoyi.platform.domain.Service service) { + LoginUser loginUser = SecurityUtils.getLoginUser(); + service.setCreateBy(loginUser.getUsername()); + service.setUpdateBy(loginUser.getUsername()); + serviceDao.insertService(service); + return service; + } + + @Override + public ServiceVersion addServiceVersion(ServiceVersion serviceVersion) { + LoginUser loginUser = SecurityUtils.getLoginUser(); + serviceVersion.setCreateBy(loginUser.getUsername()); + serviceVersion.setUpdateBy(loginUser.getUsername()); + serviceDao.insertServiceVersion(serviceVersion); + return serviceVersion; + } + + @Override + public com.ruoyi.platform.domain.Service editService(com.ruoyi.platform.domain.Service service) { + LoginUser loginUser = SecurityUtils.getLoginUser(); + service.setUpdateBy(loginUser.getUsername()); + serviceDao.updateService(service); + return serviceDao.getServiceById(service.getId()); + } + + @Override + public ServiceVersion editServiceVersion(ServiceVersion serviceVersion) { + LoginUser loginUser = SecurityUtils.getLoginUser(); + serviceVersion.setUpdateBy(loginUser.getUsername()); + serviceDao.updateServiceVersion(serviceVersion); + return serviceDao.getServiceVersionById(serviceVersion.getId()); + } + + @Override + public ServiceVersion getServiceVersion(Long id) { + return serviceDao.getServiceVersionById(id); + } + + @Override + public String deleteService(Long id) { + com.ruoyi.platform.domain.Service service = serviceDao.getServiceById(id); + if (service == null) { + return "服务不存在"; + } + + LoginUser loginUser = SecurityUtils.getLoginUser(); + String username = loginUser.getUsername(); + String createBy = service.getCreateBy(); + if (!(StringUtils.equals(username, "admin") || StringUtils.equals(username, createBy))) { + return "无权限删除该服务"; + } + + ServiceVersion serviceVersion = new ServiceVersion(); + serviceVersion.setServiceId(id); + long versionCount = serviceDao.countServiceVersion(serviceVersion); + if (versionCount != 0) { + return "该服务下还有版本,不能删除"; + } + + service.setState(Constant.State_invalid); + return serviceDao.updateService(service) > 0 ? "删除成功" : "删除失败"; + } + + @Override + public String deleteServiceVersion(Long id) { + ServiceVersion serviceVersion = serviceDao.getServiceVersionById(id); + serviceVersion.setState(Constant.State_invalid); + return serviceDao.updateServiceVersion(serviceVersion) > 0 ? "删除成功" : "删除失败"; + } + + @Override + public void runServiceVersion(Long id) { + ServiceVersion serviceVersion = serviceDao.getServiceVersionById(id); + + + + } +} diff --git a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/utils/K8sClientUtil.java b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/utils/K8sClientUtil.java index 49d56853..6b2f06b9 100644 --- a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/utils/K8sClientUtil.java +++ b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/utils/K8sClientUtil.java @@ -1,5 +1,6 @@ package com.ruoyi.platform.utils; +import com.alibaba.fastjson2.JSON; import com.ruoyi.platform.constant.Constant; import com.ruoyi.platform.domain.DevEnvironment; import com.ruoyi.platform.mapper.ComputingResourceDao; @@ -8,6 +9,7 @@ import io.kubernetes.client.custom.IntOrString; import io.kubernetes.client.custom.Quantity; import io.kubernetes.client.openapi.ApiClient; import io.kubernetes.client.openapi.ApiException; +import io.kubernetes.client.openapi.apis.AppsV1Api; import io.kubernetes.client.openapi.apis.CoreV1Api; import io.kubernetes.client.openapi.models.*; import io.kubernetes.client.util.ClientBuilder; @@ -471,24 +473,7 @@ public class K8sClientUtil { //配置资源 - JSONObject standardJson = new JSONObject(devEnvironment.getStandard()); - JSONObject valueJson = (JSONObject) standardJson.get("value"); - int cpu = (int) valueJson.get("cpu"); - String memory = (String) valueJson.get("memory"); - memory = memory.substring(0, memory.length() - 1).concat("i"); - int gpu = (int) valueJson.get("gpu"); - - HashMap limitMap = new HashMap<>(); - if (Constant.Computing_Resource_GPU.equals(devEnvironment.getComputingResource())) { - limitMap.put("nvidia.com/gpu", new Quantity(String.valueOf(gpu))); - } - limitMap.put("cpu", new Quantity(String.valueOf(cpu))); - limitMap.put("memory", new Quantity(memory)); - limitMap.put("ephemeral-storage", new Quantity("100Gi")); - - V1ResourceRequirements v1ResourceRequirements = new V1ResourceRequirements(); - v1ResourceRequirements.setRequests(limitMap); - v1ResourceRequirements.setLimits(limitMap); + V1ResourceRequirements v1ResourceRequirements = setPodResource(devEnvironment.getStandard()); V1Pod pod = new V1PodBuilder() .withNewMetadata() @@ -674,6 +659,98 @@ public class K8sClientUtil { return pod; } + + public Integer createDeployment(String dpName, String namespace, Integer replicas, String model, String image, Integer port, String resource, String mountPath + , String envVariables, String codeConfig) { + AppsV1Api api = new AppsV1Api(apiClient); + + //配置标签选择 + HashMap selector = new HashMap<>(); + selector.put("app", dpName); + + //配置资源 + V1ResourceRequirements v1ResourceRequirements = setPodResource(resource); + + //配置环境变量 + List env = new ArrayList<>(); + if (StringUtils.isNotEmpty(envVariables)) { + HashMap envMap = JSON.parseObject(envVariables, HashMap.class); + for (String key : envMap.keySet()) { + V1EnvVar envVar = new V1EnvVar().name(key).value(envMap.get(key)); + env.add(envVar); + } + } + + // 配置卷和卷挂载 +// List volumeMounts = new ArrayList<>(); +// volumeMounts.add(new V1VolumeMount().name("workspace").mountPath(mountPath)); +// volumeMounts.add(new V1VolumeMount().name("minio-pvc").mountPath("/opt/code").subPath(codeConfig).readOnly(true)); +// volumeMounts.add(new V1VolumeMount().name("minio-pvc").mountPath("/opt/model").subPath(model).readOnly(true)); +// +// List volumes = new ArrayList<>(); +// volumes.add(new V1Volume().name("workspace").persistentVolumeClaim(new V1PersistentVolumeClaimVolumeSource().claimName(pvc.getMetadata().getName()))); +// volumes.add(new V1Volume().name("minio-pvc").persistentVolumeClaim(new V1PersistentVolumeClaimVolumeSource().claimName(dataPvcName))); + + + //创建deployment + V1Deployment deployment = new V1DeploymentBuilder().withNewMetadata() + .withName(dpName) + .endMetadata() + .withNewSpec() + .withReplicas(replicas) + .withSelector(new V1LabelSelector().matchLabels(selector)) + .withNewTemplate() + .withNewMetadata() + .addToLabels("app", dpName) + .endMetadata() + .withNewSpec() + .addNewContainer() + .withName(dpName) + .withImage(image) + .withEnv(env) + .withPorts(new V1ContainerPort().containerPort(port).protocol("TCP")) + .withResources(v1ResourceRequirements) + .endContainer() + .endSpec() + .endTemplate() + .endSpec() + .build(); + + try { + api.createNamespacedDeployment(namespace, deployment, null, null, null); + } catch (ApiException e) { + throw new RuntimeException("创建deployment异常:" + e.getResponseBody()); + } + + V1Service service = createService(namespace, dpName + "-svc", port, selector); + return service.getSpec().getPorts().get(0).getNodePort(); + } + + + V1ResourceRequirements setPodResource(String resource) { + //配置pod资源 + JSONObject standardJson = new JSONObject(resource); + JSONObject valueJson = (JSONObject) standardJson.get("value"); + int cpu = (int) valueJson.get("cpu"); + String memory = (String) valueJson.get("memory"); + memory = memory.substring(0, memory.length() - 1).concat("i"); + Integer gpu = (Integer) valueJson.get("gpu"); + + HashMap limitMap = new HashMap<>(); + if (gpu != null && gpu != 0) { + limitMap.put("nvidia.com/gpu", new Quantity(String.valueOf(gpu))); + } + limitMap.put("cpu", new Quantity(String.valueOf(cpu))); + limitMap.put("memory", new Quantity(memory)); + limitMap.put("ephemeral-storage", new Quantity("100Gi")); + + V1ResourceRequirements v1ResourceRequirements = new V1ResourceRequirements(); + v1ResourceRequirements.setRequests(limitMap); + v1ResourceRequirements.setLimits(limitMap); + + return v1ResourceRequirements; + } + /** * 删除 Pod * diff --git a/ruoyi-modules/management-platform/src/main/resources/mapper/managementPlatform/ServiceDaoMapper.xml b/ruoyi-modules/management-platform/src/main/resources/mapper/managementPlatform/ServiceDaoMapper.xml new file mode 100644 index 00000000..656b3384 --- /dev/null +++ b/ruoyi-modules/management-platform/src/main/resources/mapper/managementPlatform/ServiceDaoMapper.xml @@ -0,0 +1,134 @@ + + + + + + + + + + + + + select * from service_version + + state = 1 + + and version like concat('%', #{serviceVersion.version}, '%') + + + and service_id = #{serviceVersion.serviceId} + + + order by update_time DESC + + + + + + + + insert into service(service_name, service_type, description, create_by, update_by) + values (#{serviceName}, #{serviceType}, #{description}, #{createBy}, #{updateBy}) + + + + insert into service_version(service_id, version, model, image, resouce, replicas, mount_path, env_variables, + code_config, command, create_by, update_by) + values (#{serviceId}, #{version}, #{model}, #{image}, #{replicas}, #{mountPath}, #{envVariables}, + #{codeConfig}, #{command}, #{createBy}, #{updateBy}) + + + + update service + + + service_name = #{service.serviceName} + + + service_type = #{service.serviceType} + + + description = #{service.description} + + + state = #{service.state} + + + where id = #{service.id} + + + + update service_version + + + model = #{serviceVersion.model}, + + + image = #{serviceVersion.image}, + + + resouce = #{serviceVersion.resouce}, + + + replicas = #{serviceVersion.replicas}, + + + mount_path = #{serviceVersion.mountPath}, + + + env_variables = #{serviceVersion.envVariables}, + + + code_config = #{serviceVersion.codeConfig}, + + + command = #{serviceVersion.command}, + + + url = #{serviceVersion.url}, + + + where id = #{serviceVersion.id} + + \ No newline at end of file