Browse Source

first

master
educoder 3 years ago
parent
commit
2e87fae9f8
100 changed files with 10192 additions and 0 deletions
  1. +2
    -0
      .gitignore
  2. +218
    -0
      common/common.iml
  3. +36
    -0
      common/pom.xml
  4. +73
    -0
      common/src/main/java/com/imitate/common/advisor/DefaultControllerAdvisor.java
  5. +19
    -0
      common/src/main/java/com/imitate/common/annotation/PublicUrl.java
  6. +61
    -0
      common/src/main/java/com/imitate/common/bean/ApiResult.java
  7. +44
    -0
      common/src/main/java/com/imitate/common/bean/BeanFactory.java
  8. +53
    -0
      common/src/main/java/com/imitate/common/bean/BridgePage.java
  9. +48
    -0
      common/src/main/java/com/imitate/common/bean/ShellResult.java
  10. +141
    -0
      common/src/main/java/com/imitate/common/config/DateConfig.java
  11. +36
    -0
      common/src/main/java/com/imitate/common/config/InitListener.java
  12. +35
    -0
      common/src/main/java/com/imitate/common/config/JdbcConfig.java
  13. +9
    -0
      common/src/main/java/com/imitate/common/config/MybatisConfig.java
  14. +21
    -0
      common/src/main/java/com/imitate/common/config/RedisListenerConfig.java
  15. +23
    -0
      common/src/main/java/com/imitate/common/config/UncaughtBridgeExceptionHandler.java
  16. +63
    -0
      common/src/main/java/com/imitate/common/config/WebMvcConfig.java
  17. +7
    -0
      common/src/main/java/com/imitate/common/constant/ApiResultCsts.java
  18. +76
    -0
      common/src/main/java/com/imitate/common/constant/BuildResultCsts.java
  19. +217
    -0
      common/src/main/java/com/imitate/common/constant/TpCsts.java
  20. +53
    -0
      common/src/main/java/com/imitate/common/enums/CommonStateEnum.java
  21. +60
    -0
      common/src/main/java/com/imitate/common/enums/ErrorCodeEnum.java
  22. +36
    -0
      common/src/main/java/com/imitate/common/exception/BusinessException.java
  23. +117
    -0
      common/src/main/java/com/imitate/common/interceptor/HttpServletRequestFilter.java
  24. +142
    -0
      common/src/main/java/com/imitate/common/interceptor/SignInterceptor.java
  25. +73
    -0
      common/src/main/java/com/imitate/common/k8s/bean/BridgeContainer.java
  26. +47
    -0
      common/src/main/java/com/imitate/common/k8s/bean/BridgeNode.java
  27. +231
    -0
      common/src/main/java/com/imitate/common/k8s/bean/BuildResult.java
  28. +384
    -0
      common/src/main/java/com/imitate/common/k8s/bean/ClusterInfo.java
  29. +143
    -0
      common/src/main/java/com/imitate/common/k8s/bean/ContainerCreateParams.java
  30. +28
    -0
      common/src/main/java/com/imitate/common/k8s/bean/ContainerMountParams.java
  31. +66
    -0
      common/src/main/java/com/imitate/common/k8s/bean/CreatePodResult.java
  32. +38
    -0
      common/src/main/java/com/imitate/common/k8s/bean/DeploymentCreateParams.java
  33. +122
    -0
      common/src/main/java/com/imitate/common/k8s/bean/ExecResultCase.java
  34. +46
    -0
      common/src/main/java/com/imitate/common/k8s/bean/HPACreateParams.java
  35. +77
    -0
      common/src/main/java/com/imitate/common/k8s/bean/NodeEvaErrorInfo.java
  36. +35
    -0
      common/src/main/java/com/imitate/common/k8s/bean/NodeQueryParam.java
  37. +58
    -0
      common/src/main/java/com/imitate/common/k8s/bean/NodeRes.java
  38. +76
    -0
      common/src/main/java/com/imitate/common/k8s/bean/NodeResStat.java
  39. +165
    -0
      common/src/main/java/com/imitate/common/k8s/bean/OjEvaResult.java
  40. +41
    -0
      common/src/main/java/com/imitate/common/k8s/bean/PodCreateParams.java
  41. +123
    -0
      common/src/main/java/com/imitate/common/k8s/bean/PodCreateStrategy.java
  42. +281
    -0
      common/src/main/java/com/imitate/common/k8s/bean/PodQueryParam.java
  43. +127
    -0
      common/src/main/java/com/imitate/common/k8s/bean/RunPodQueryParam.java
  44. +42
    -0
      common/src/main/java/com/imitate/common/k8s/bean/ServiceCreateParams.java
  45. +81
    -0
      common/src/main/java/com/imitate/common/k8s/bean/TimeCost.java
  46. +8
    -0
      common/src/main/java/com/imitate/common/k8s/constant/BridgeNodeCsts.java
  47. +8
    -0
      common/src/main/java/com/imitate/common/k8s/constant/BridgePodCsts.java
  48. +12
    -0
      common/src/main/java/com/imitate/common/k8s/constant/PlatformConfigCsts.java
  49. +46
    -0
      common/src/main/java/com/imitate/common/k8s/mapper/BridgePodMapper.java
  50. +14
    -0
      common/src/main/java/com/imitate/common/k8s/mapper/ErrorPodInfoMapper.java
  51. +21
    -0
      common/src/main/java/com/imitate/common/k8s/mapper/EvaDayStatMapper.java
  52. +16
    -0
      common/src/main/java/com/imitate/common/k8s/mapper/OjEvaDayStatMapper.java
  53. +22
    -0
      common/src/main/java/com/imitate/common/k8s/mapper/PlatformConfigMapper.java
  54. +55
    -0
      common/src/main/java/com/imitate/common/k8s/mapper/RunPodMapper.java
  55. +16
    -0
      common/src/main/java/com/imitate/common/k8s/mapper/SecurityContextConfigMapper.java
  56. +31
    -0
      common/src/main/java/com/imitate/common/k8s/mapper/WindowsInfoMapper.java
  57. +173
    -0
      common/src/main/java/com/imitate/common/k8s/mgr/ClusterManager.java
  58. +146
    -0
      common/src/main/java/com/imitate/common/k8s/mgr/NodeManager.java
  59. +89
    -0
      common/src/main/java/com/imitate/common/k8s/mgr/node/GpuNodeMgr.java
  60. +48
    -0
      common/src/main/java/com/imitate/common/k8s/mgr/node/NodeMgrIf.java
  61. +85
    -0
      common/src/main/java/com/imitate/common/k8s/mgr/node/NormalNodeMgr.java
  62. +107
    -0
      common/src/main/java/com/imitate/common/k8s/mgr/node/OjNodeMgr.java
  63. +89
    -0
      common/src/main/java/com/imitate/common/k8s/mgr/node/ShenlongNodeMgr.java
  64. +311
    -0
      common/src/main/java/com/imitate/common/k8s/mgr/node/cluster/ClusterGpuNodeMgr.java
  65. +61
    -0
      common/src/main/java/com/imitate/common/k8s/mgr/node/cluster/ClusterNodeMgrIf.java
  66. +114
    -0
      common/src/main/java/com/imitate/common/k8s/mgr/node/cluster/ClusterNormalNodeMgr.java
  67. +348
    -0
      common/src/main/java/com/imitate/common/k8s/mgr/node/cluster/ClusterOjNodeMgr.java
  68. +299
    -0
      common/src/main/java/com/imitate/common/k8s/mgr/node/cluster/ClusterShenlongNodeMgr.java
  69. +67
    -0
      common/src/main/java/com/imitate/common/k8s/pojo/BridgePod.java
  70. +40
    -0
      common/src/main/java/com/imitate/common/k8s/pojo/ErrorPodInfo.java
  71. +74
    -0
      common/src/main/java/com/imitate/common/k8s/pojo/EvaDayStat.java
  72. +56
    -0
      common/src/main/java/com/imitate/common/k8s/pojo/OjEvaDayStat.java
  73. +29
    -0
      common/src/main/java/com/imitate/common/k8s/pojo/PlatformConfig.java
  74. +78
    -0
      common/src/main/java/com/imitate/common/k8s/pojo/RunPod.java
  75. +30
    -0
      common/src/main/java/com/imitate/common/k8s/pojo/SecurityContextConfig.java
  76. +44
    -0
      common/src/main/java/com/imitate/common/k8s/pojo/WindowsInfo.java
  77. +71
    -0
      common/src/main/java/com/imitate/common/k8s/service/BridgeNodeService.java
  78. +119
    -0
      common/src/main/java/com/imitate/common/k8s/service/BridgePodService.java
  79. +157
    -0
      common/src/main/java/com/imitate/common/k8s/service/DiskService.java
  80. +19
    -0
      common/src/main/java/com/imitate/common/k8s/service/EvaDayStatService.java
  81. +1330
    -0
      common/src/main/java/com/imitate/common/k8s/service/K8sService.java
  82. +120
    -0
      common/src/main/java/com/imitate/common/k8s/service/NodeResUsageService.java
  83. +54
    -0
      common/src/main/java/com/imitate/common/k8s/service/OjEvaDayStatService.java
  84. +59
    -0
      common/src/main/java/com/imitate/common/k8s/service/PlatformConfigService.java
  85. +110
    -0
      common/src/main/java/com/imitate/common/k8s/service/PortService.java
  86. +511
    -0
      common/src/main/java/com/imitate/common/k8s/service/RunPodService.java
  87. +42
    -0
      common/src/main/java/com/imitate/common/k8s/service/SecurityContextService.java
  88. +227
    -0
      common/src/main/java/com/imitate/common/k8s/util/ContainerUtil.java
  89. +30
    -0
      common/src/main/java/com/imitate/common/k8s/util/GetPodErrorReasonUtil.java
  90. +93
    -0
      common/src/main/java/com/imitate/common/k8s/util/K8sClientUtil.java
  91. +119
    -0
      common/src/main/java/com/imitate/common/k8s/util/K8sPodCommandExecutor.java
  92. +371
    -0
      common/src/main/java/com/imitate/common/k8s/util/K8sUtils.java
  93. +22
    -0
      common/src/main/java/com/imitate/common/shiro/config/FilterConfig.java
  94. +108
    -0
      common/src/main/java/com/imitate/common/shiro/config/OAuth2Filter.java
  95. +106
    -0
      common/src/main/java/com/imitate/common/shiro/config/ShiroConfig.java
  96. +16
    -0
      common/src/main/java/com/imitate/common/shiro/mapper/SysMenuMapper.java
  97. +31
    -0
      common/src/main/java/com/imitate/common/shiro/mapper/SysRoleMapper.java
  98. +29
    -0
      common/src/main/java/com/imitate/common/shiro/mapper/SysRoleMenuMapper.java
  99. +14
    -0
      common/src/main/java/com/imitate/common/shiro/mapper/SysTokenMapper.java
  100. +23
    -0
      common/src/main/java/com/imitate/common/shiro/mapper/SysUserMapper.java

+ 2
- 0
.gitignore View File

@@ -1,6 +1,8 @@
# ---> Java
# Compiled class file
*.class
./.idea/
.idea/

# Log file
*.log


+ 218
- 0
common/common.iml View File

@@ -0,0 +1,218 @@
<?xml version="1.0" encoding="UTF-8"?>
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="web" name="Web">
<configuration>
<webroots />
<sourceRoots>
<root url="file://$MODULE_DIR$/src/main/java" />
<root url="file://$MODULE_DIR$/src/main/resources" />
</sourceRoots>
</configuration>
</facet>
<facet type="Spring" name="Spring">
<configuration />
</facet>
</component>
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8">
<output url="file://$MODULE_DIR$/target/classes" />
<output-test url="file://$MODULE_DIR$/target/test-classes" />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/target" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-configuration-processor:2.5.6" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-autoconfigure:2.5.6" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot:2.5.6" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-context:5.3.12" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter:2.5.6" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-logging:2.5.6" level="project" />
<orderEntry type="library" name="Maven: ch.qos.logback:logback-classic:1.2.6" level="project" />
<orderEntry type="library" name="Maven: ch.qos.logback:logback-core:1.2.6" level="project" />
<orderEntry type="library" name="Maven: org.apache.logging.log4j:log4j-to-slf4j:2.14.1" level="project" />
<orderEntry type="library" name="Maven: org.apache.logging.log4j:log4j-api:2.14.1" level="project" />
<orderEntry type="library" name="Maven: org.slf4j:jul-to-slf4j:1.7.32" level="project" />
<orderEntry type="library" name="Maven: jakarta.annotation:jakarta.annotation-api:1.3.5" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-core:5.3.12" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-jcl:5.3.12" level="project" />
<orderEntry type="library" name="Maven: org.yaml:snakeyaml:1.28" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.springframework.boot:spring-boot-starter-test:2.5.6" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.springframework.boot:spring-boot-test:2.5.6" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.springframework.boot:spring-boot-test-autoconfigure:2.5.6" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: com.jayway.jsonpath:json-path:2.5.0" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: net.minidev:json-smart:2.4.7" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: net.minidev:accessors-smart:2.4.7" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.ow2.asm:asm:9.1" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: jakarta.xml.bind:jakarta.xml.bind-api:2.3.3" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: jakarta.activation:jakarta.activation-api:1.2.2" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.assertj:assertj-core:3.19.0" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.hamcrest:hamcrest:2.2" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.junit.jupiter:junit-jupiter:5.7.2" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.junit.jupiter:junit-jupiter-api:5.7.2" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.apiguardian:apiguardian-api:1.1.0" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.opentest4j:opentest4j:1.2.0" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.junit.platform:junit-platform-commons:1.7.2" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.junit.jupiter:junit-jupiter-params:5.7.2" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.junit.jupiter:junit-jupiter-engine:5.7.2" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.junit.platform:junit-platform-engine:1.7.2" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.mockito:mockito-core:3.9.0" level="project" />
<orderEntry type="library" name="Maven: net.bytebuddy:byte-buddy:1.10.22" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: net.bytebuddy:byte-buddy-agent:1.10.22" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.objenesis:objenesis:3.2" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.mockito:mockito-junit-jupiter:3.9.0" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.skyscreamer:jsonassert:1.5.0" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: com.vaadin.external.google:android-json:0.0.20131108.vaadin1" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.springframework:spring-test:5.3.12" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.xmlunit:xmlunit-core:2.8.3" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-aop:2.5.6" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-aop:5.3.12" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-beans:5.3.12" level="project" />
<orderEntry type="library" name="Maven: org.aspectj:aspectjweaver:1.9.7" level="project" />
<orderEntry type="library" name="Maven: com.spring4all:swagger-spring-boot-starter:1.9.0.RELEASE" level="project" />
<orderEntry type="library" name="Maven: io.springfox:springfox-swagger-ui:2.9.2" level="project" />
<orderEntry type="library" name="Maven: io.springfox:springfox-spring-web:2.9.2" level="project" />
<orderEntry type="library" name="Maven: io.springfox:springfox-swagger2:2.9.2" level="project" />
<orderEntry type="library" name="Maven: io.swagger:swagger-annotations:1.5.20" level="project" />
<orderEntry type="library" name="Maven: io.swagger:swagger-models:1.5.20" level="project" />
<orderEntry type="library" name="Maven: io.springfox:springfox-spi:2.9.2" level="project" />
<orderEntry type="library" name="Maven: io.springfox:springfox-core:2.9.2" level="project" />
<orderEntry type="library" name="Maven: io.springfox:springfox-schema:2.9.2" level="project" />
<orderEntry type="library" name="Maven: io.springfox:springfox-swagger-common:2.9.2" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml:classmate:1.5.1" level="project" />
<orderEntry type="library" name="Maven: org.springframework.plugin:spring-plugin-core:1.2.0.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework.plugin:spring-plugin-metadata:1.2.0.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.mapstruct:mapstruct:1.2.0.Final" level="project" />
<orderEntry type="library" name="Maven: io.springfox:springfox-bean-validators:2.9.2" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-web:2.5.6" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-json:2.5.6" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.12.5" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.module:jackson-module-parameter-names:2.12.5" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-tomcat:2.5.6" level="project" />
<orderEntry type="library" name="Maven: org.apache.tomcat.embed:tomcat-embed-core:9.0.54" level="project" />
<orderEntry type="library" name="Maven: org.apache.tomcat.embed:tomcat-embed-websocket:9.0.54" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-web:5.3.12" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-webmvc:5.3.12" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-expression:5.3.12" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-data-redis:2.5.6" level="project" />
<orderEntry type="library" name="Maven: org.springframework.data:spring-data-redis:2.5.6" level="project" />
<orderEntry type="library" name="Maven: org.springframework.data:spring-data-keyvalue:2.5.6" level="project" />
<orderEntry type="library" name="Maven: org.springframework.data:spring-data-commons:2.5.6" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-tx:5.3.12" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-oxm:5.3.12" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-context-support:5.3.12" level="project" />
<orderEntry type="library" name="Maven: io.lettuce:lettuce-core:6.1.5.RELEASE" level="project" />
<orderEntry type="library" name="Maven: io.netty:netty-common:4.1.69.Final" level="project" />
<orderEntry type="library" name="Maven: io.netty:netty-handler:4.1.69.Final" level="project" />
<orderEntry type="library" name="Maven: io.netty:netty-resolver:4.1.69.Final" level="project" />
<orderEntry type="library" name="Maven: io.netty:netty-buffer:4.1.69.Final" level="project" />
<orderEntry type="library" name="Maven: io.netty:netty-codec:4.1.69.Final" level="project" />
<orderEntry type="library" name="Maven: io.netty:netty-transport:4.1.69.Final" level="project" />
<orderEntry type="library" name="Maven: io.projectreactor:reactor-core:3.4.11" level="project" />
<orderEntry type="library" name="Maven: org.reactivestreams:reactive-streams:1.0.3" level="project" />
<orderEntry type="library" name="Maven: org.projectlombok:lombok:1.18.22" level="project" />
<orderEntry type="library" name="Maven: com.alibaba:fastjson:1.2.83" level="project" />
<orderEntry type="library" name="Maven: org.apache.httpcomponents:httpcore:4.4.5" level="project" />
<orderEntry type="library" name="Maven: javax.validation:validation-api:2.0.1.Final" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-validation:2.5.6" level="project" />
<orderEntry type="library" name="Maven: org.apache.tomcat.embed:tomcat-embed-el:9.0.54" level="project" />
<orderEntry type="library" name="Maven: org.hibernate.validator:hibernate-validator:6.2.0.Final" level="project" />
<orderEntry type="library" name="Maven: jakarta.validation:jakarta.validation-api:2.0.2" level="project" />
<orderEntry type="library" name="Maven: org.jboss.logging:jboss-logging:3.4.2.Final" level="project" />
<orderEntry type="library" name="Maven: org.apache.commons:commons-lang3:3.12.0" level="project" />
<orderEntry type="library" name="Maven: cn.hutool:hutool-all:5.7.11" level="project" />
<orderEntry type="library" name="Maven: tk.mybatis:mapper-spring-boot-starter:2.1.0" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-jdbc:2.5.6" level="project" />
<orderEntry type="library" name="Maven: com.zaxxer:HikariCP:4.0.3" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-jdbc:5.3.12" level="project" />
<orderEntry type="library" name="Maven: org.mybatis:mybatis:3.4.6" level="project" />
<orderEntry type="library" name="Maven: org.mybatis:mybatis-spring:1.3.2" level="project" />
<orderEntry type="library" name="Maven: tk.mybatis:mapper-core:1.1.0" level="project" />
<orderEntry type="library" name="Maven: javax.persistence:persistence-api:1.0" level="project" />
<orderEntry type="library" name="Maven: tk.mybatis:mapper-base:1.1.0" level="project" />
<orderEntry type="library" name="Maven: tk.mybatis:mapper-weekend:1.1.4.2" level="project" />
<orderEntry type="library" name="Maven: tk.mybatis:mapper-spring:1.1.0" level="project" />
<orderEntry type="library" name="Maven: tk.mybatis:mapper-extra:1.1.0" level="project" />
<orderEntry type="library" name="Maven: tk.mybatis:mapper-spring-boot-autoconfigure:2.1.0" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Maven: mysql:mysql-connector-java:8.0.27" level="project" />
<orderEntry type="library" name="Maven: com.alibaba:druid-spring-boot-starter:1.1.10" level="project" />
<orderEntry type="library" name="Maven: com.alibaba:druid:1.1.10" level="project" />
<orderEntry type="library" name="Maven: org.slf4j:slf4j-api:1.7.32" level="project" />
<orderEntry type="library" name="Maven: com.github.pagehelper:pagehelper-spring-boot-starter:1.2.10" level="project" />
<orderEntry type="library" name="Maven: org.mybatis.spring.boot:mybatis-spring-boot-starter:1.3.2" level="project" />
<orderEntry type="library" name="Maven: org.mybatis.spring.boot:mybatis-spring-boot-autoconfigure:1.3.2" level="project" />
<orderEntry type="library" name="Maven: com.github.pagehelper:pagehelper-spring-boot-autoconfigure:1.2.10" level="project" />
<orderEntry type="library" name="Maven: com.github.pagehelper:pagehelper:5.1.8" level="project" />
<orderEntry type="library" name="Maven: com.github.jsqlparser:jsqlparser:1.2" level="project" />
<orderEntry type="library" name="Maven: org.apache.shiro:shiro-core:1.9.0" level="project" />
<orderEntry type="library" name="Maven: org.apache.shiro:shiro-lang:1.9.0" level="project" />
<orderEntry type="library" name="Maven: org.apache.shiro:shiro-cache:1.9.0" level="project" />
<orderEntry type="library" name="Maven: org.apache.shiro:shiro-crypto-hash:1.9.0" level="project" />
<orderEntry type="library" name="Maven: org.apache.shiro:shiro-crypto-core:1.9.0" level="project" />
<orderEntry type="library" name="Maven: org.apache.shiro:shiro-crypto-cipher:1.9.0" level="project" />
<orderEntry type="library" name="Maven: org.apache.shiro:shiro-config-core:1.9.0" level="project" />
<orderEntry type="library" name="Maven: org.apache.shiro:shiro-config-ogdl:1.9.0" level="project" />
<orderEntry type="library" name="Maven: org.apache.shiro:shiro-event:1.9.0" level="project" />
<orderEntry type="library" name="Maven: org.apache.shiro:shiro-spring:1.9.0" level="project" />
<orderEntry type="library" name="Maven: org.apache.shiro:shiro-web:1.9.0" level="project" />
<orderEntry type="library" name="Maven: org.owasp.encoder:encoder:1.2.2" level="project" />
<orderEntry type="library" name="Maven: com.google.code.gson:gson:2.9.0" level="project" />
<orderEntry type="library" name="Maven: commons-io:commons-io:2.7" level="project" />
<orderEntry type="library" name="Maven: commons-codec:commons-codec:1.15" level="project" />
<orderEntry type="library" name="Maven: commons-net:commons-net:3.6" level="project" />
<orderEntry type="library" name="Maven: org.apache.commons:commons-text:1.9" level="project" />
<orderEntry type="library" name="Maven: io.fabric8:kubernetes-client:5.11.2" level="project" />
<orderEntry type="library" name="Maven: io.fabric8:kubernetes-model-core:5.11.2" level="project" />
<orderEntry type="library" name="Maven: io.fabric8:kubernetes-model-common:5.11.2" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-annotations:2.12.5" level="project" />
<orderEntry type="library" name="Maven: io.fabric8:kubernetes-model-rbac:5.11.2" level="project" />
<orderEntry type="library" name="Maven: io.fabric8:kubernetes-model-admissionregistration:5.11.2" level="project" />
<orderEntry type="library" name="Maven: io.fabric8:kubernetes-model-apps:5.11.2" level="project" />
<orderEntry type="library" name="Maven: io.fabric8:kubernetes-model-autoscaling:5.11.2" level="project" />
<orderEntry type="library" name="Maven: io.fabric8:kubernetes-model-apiextensions:5.11.2" level="project" />
<orderEntry type="library" name="Maven: io.fabric8:kubernetes-model-batch:5.11.2" level="project" />
<orderEntry type="library" name="Maven: io.fabric8:kubernetes-model-certificates:5.11.2" level="project" />
<orderEntry type="library" name="Maven: io.fabric8:kubernetes-model-coordination:5.11.2" level="project" />
<orderEntry type="library" name="Maven: io.fabric8:kubernetes-model-discovery:5.11.2" level="project" />
<orderEntry type="library" name="Maven: io.fabric8:kubernetes-model-events:5.11.2" level="project" />
<orderEntry type="library" name="Maven: io.fabric8:kubernetes-model-extensions:5.11.2" level="project" />
<orderEntry type="library" name="Maven: io.fabric8:kubernetes-model-flowcontrol:5.11.2" level="project" />
<orderEntry type="library" name="Maven: io.fabric8:kubernetes-model-networking:5.11.2" level="project" />
<orderEntry type="library" name="Maven: io.fabric8:kubernetes-model-metrics:5.11.2" level="project" />
<orderEntry type="library" name="Maven: io.fabric8:kubernetes-model-policy:5.11.2" level="project" />
<orderEntry type="library" name="Maven: io.fabric8:kubernetes-model-scheduling:5.11.2" level="project" />
<orderEntry type="library" name="Maven: io.fabric8:kubernetes-model-storageclass:5.11.2" level="project" />
<orderEntry type="library" name="Maven: io.fabric8:kubernetes-model-node:5.11.2" level="project" />
<orderEntry type="library" name="Maven: com.squareup.okhttp3:okhttp:3.14.9" level="project" />
<orderEntry type="library" name="Maven: com.squareup.okio:okio:1.17.2" level="project" />
<orderEntry type="library" name="Maven: com.squareup.okhttp3:logging-interceptor:3.14.9" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.12.5" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.12.5" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-databind:2.12.5" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-core:2.12.5" level="project" />
<orderEntry type="library" name="Maven: io.fabric8:zjsonpatch:0.3.0" level="project" />
<orderEntry type="library" name="Maven: com.github.mifmif:generex:1.0.2" level="project" />
<orderEntry type="library" name="Maven: dk.brics.automaton:automaton:1.11-8" level="project" />
<orderEntry type="library" name="Maven: redis.clients:jedis:2.9.0" level="project" />
<orderEntry type="library" name="Maven: org.apache.commons:commons-pool2:2.9.0" level="project" />
<orderEntry type="library" name="Maven: com.google.guava:guava:22.0" level="project" />
<orderEntry type="library" name="Maven: com.google.code.findbugs:jsr305:1.3.9" level="project" />
<orderEntry type="library" name="Maven: com.google.errorprone:error_prone_annotations:2.0.18" level="project" />
<orderEntry type="library" name="Maven: com.google.j2objc:j2objc-annotations:1.1" level="project" />
<orderEntry type="library" name="Maven: org.codehaus.mojo:animal-sniffer-annotations:1.14" level="project" />
<orderEntry type="library" name="Maven: com.googlecode.aviator:aviator:5.1.2" level="project" />
<orderEntry type="library" name="Maven: commons-beanutils:commons-beanutils:1.9.3" level="project" />
<orderEntry type="library" name="Maven: commons-collections:commons-collections:3.2.2" level="project" />
<orderEntry type="library" name="Maven: com.aliyun:aliyun-java-sdk-core:4.4.6" level="project" />
<orderEntry type="library" name="Maven: org.apache.httpcomponents:httpclient:4.5.13" level="project" />
<orderEntry type="library" name="Maven: commons-logging:commons-logging:1.2" level="project" />
<orderEntry type="library" name="Maven: javax.xml.bind:jaxb-api:2.3.1" level="project" />
<orderEntry type="library" name="Maven: javax.activation:javax.activation-api:1.2.0" level="project" />
<orderEntry type="library" name="Maven: org.jacoco:org.jacoco.agent:runtime:0.8.3" level="project" />
<orderEntry type="library" name="Maven: org.ini4j:ini4j:0.5.4" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.1.0" level="project" />
</component>
</module>

+ 36
- 0
common/pom.xml View File

@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>parent</artifactId>
<groupId>com.imitate</groupId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../parent/pom.xml</relativePath>
</parent>

<artifactId>common</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>common</name>
<description>common</description>
<packaging>jar</packaging>


<dependencies>
<!-- 配置文件联想提示 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
</dependencies>





</project>

+ 73
- 0
common/src/main/java/com/imitate/common/advisor/DefaultControllerAdvisor.java View File

@@ -0,0 +1,73 @@
package com.imitate.common.advisor;

import com.imitate.common.enums.ErrorCodeEnum;
import com.imitate.common.exception.BusinessException;
import com.imitate.common.util.R;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.validation.ConstraintViolationException;


/**
* @author yanchao
*/
@RestControllerAdvice
public class DefaultControllerAdvisor {

private static final Logger logger = LoggerFactory.getLogger(DefaultControllerAdvisor.class);

@ExceptionHandler(Exception.class)
public R processException(Exception e) {
logger.error(e.getMessage(), e);
return R.error(ErrorCodeEnum.EXCEPTION.getValue(),ErrorCodeEnum.EXCEPTION.getDescription());
}

@ExceptionHandler(BusinessException.class)
public R processException(BusinessException e) {
logger.error(e.getMessage(), e);
return R.error(e.getErrCode(),e.getMessage());
}



@ExceptionHandler(MissingServletRequestParameterException.class)
public R processMissingServletRequestParameterException(MissingServletRequestParameterException e){
logger.error(e.getMessage(), e);
return R.error(ErrorCodeEnum.MVC_BIND_EXCEPTION.getValue(),ErrorCodeEnum.MVC_BIND_EXCEPTION.getDescription());
}



@ExceptionHandler(ConstraintViolationException.class)
public R processConstraintViolationException(ConstraintViolationException e) {
logger.error(e.getMessage(), e);
return R.error(ErrorCodeEnum.INVALID_ARG_EXCEPTION.getValue(),ErrorCodeEnum.INVALID_ARG_EXCEPTION.getDescription());
}



@ExceptionHandler(BindException.class)
public R processBindException(BindException e) {
logger.error(e.getMessage(), e);
return R.error(ErrorCodeEnum.BIND_EXCEPTION.getValue(),ErrorCodeEnum.BIND_EXCEPTION.getDescription());
}


@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
@ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED)
public R processHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e) {
logger.error(e.getMessage(), e);
return R.error(ErrorCodeEnum.METHOD_NOT_ALLOWED_EXCEPTION.getValue(),ErrorCodeEnum.METHOD_NOT_ALLOWED_EXCEPTION.getDescription());
}



}

+ 19
- 0
common/src/main/java/com/imitate/common/annotation/PublicUrl.java View File

@@ -0,0 +1,19 @@
package com.imitate.common.annotation;

import java.lang.annotation.*;

/**
* 公开性自定义注解
* @author yanchao
*/
@Inherited
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface PublicUrl {
/**
* 是否校验签名合法性
* @return
*/
boolean signValidate() default false;
}

+ 61
- 0
common/src/main/java/com/imitate/common/bean/ApiResult.java View File

@@ -0,0 +1,61 @@
package com.imitate.common.bean;


import com.imitate.common.constant.ApiResultCsts;

public class ApiResult<T> {

private int code = ApiResultCsts.CODE_SUCCESS;
private String msg;
private T data;

public int getCode() {
return code;
}

public void setCode(int code) {
this.code = code;
}

public String getMsg() {
return msg;
}

public void setMsg(String msg) {
this.msg = msg;
}

public T getData() {
return data;
}

public void setData(T data) {
this.data = data;
}

public ApiResult() {
}

public ApiResult(int code, String msg, T data) {
this.code = code;
this.msg = msg;
this.data = data;
}

public static <T> ApiResult<T> successResult(T data) {
return successResult("success", data);
}

public static <T> ApiResult<T> successResult(String msg, T data) {
return new ApiResult<>(0, msg, data);
}

public static <T> ApiResult<T> failResult(int code, String msg, T data) {
return new ApiResult<>(code, msg, data);
}

public static <T> ApiResult<T> failResult(int code, String msg) {
return new ApiResult<>(code, msg, null);
}
}

+ 44
- 0
common/src/main/java/com/imitate/common/bean/BeanFactory.java View File

@@ -0,0 +1,44 @@

/**
* 文件名 : BeanFactory.java
* 版权 : <版权/公司名>
* 描述 : <描述>
* @author liliy
* 版本 : <版本>
* 修改时间: 2017年6月13日
* 修改内容: <修改内容>
*/
package com.imitate.common.bean;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

/**
* <一句话功能简述> <功能详细描述>
*
* @author liliy
* @version [版本号,2017年6月13日]
* @see [相关类/方法]
* @since [产品/模块版本]
*/
@Component
public class BeanFactory implements ApplicationContextAware {
private static ApplicationContext ctx = null;

public static Object getObejct(String name) {
return ctx.getBean(name);
}
public static <T> T getObejct(Class<T> requiredType) {
return ctx.getBean(requiredType);
}

@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
BeanFactory.ctx = applicationContext;

}

}

+ 53
- 0
common/src/main/java/com/imitate/common/bean/BridgePage.java View File

@@ -0,0 +1,53 @@
package com.imitate.common.bean;

import com.github.pagehelper.Page;

import java.util.List;

public class BridgePage<T> {

private List<T> data;
private Integer pageNum;
private Integer pageSize;
private Long total;

public BridgePage(Page<T> page) {
this.data = page.getResult();
this.pageNum = page.getPageNum();
this.pageSize = page.getPageSize();
this.total = page.getTotal();
}

public List<T> getData() {
return data;
}

public void setData(List<T> data) {
this.data = data;
}

public Integer getPageNum() {
return pageNum;
}

public void setPageNum(Integer pageNum) {
this.pageNum = pageNum;
}

public Integer getPageSize() {
return pageSize;
}

public void setPageSize(Integer pageSize) {
this.pageSize = pageSize;
}

public Long getTotal() {
return total;
}

public void setTotal(Long total) {
this.total = total;
}

}

+ 48
- 0
common/src/main/java/com/imitate/common/bean/ShellResult.java View File

@@ -0,0 +1,48 @@
package com.imitate.common.bean;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
* shell执行结果
*
* @author 威少
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ShellResult {
/**
* 退出码
*/
private Integer exitStatus;
/**
* 实际输出
*/
private String out;

public enum ExitStatus {
/**
* 成功
*/
SUCCESS(0),
/**
* 超时
*/
TIMEOUT(124),
/**
* 默认失败
*/
FAIL(-1);

private int code;
ExitStatus(int code) {
this.code = code;
}

public int getCode() {
return code;
}
}
}

+ 141
- 0
common/src/main/java/com/imitate/common/config/DateConfig.java View File

@@ -0,0 +1,141 @@
package com.imitate.common.config;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.converter.Converter;

import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;

@Configuration
public class DateConfig {

/** 默认日期时间格式 */
public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
/** 默认日期格式 */
public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
/** 默认时间格式 */
public static final String DEFAULT_TIME_FORMAT = "HH:mm:ss";

/**
* LocalDate转换器,用于转换RequestParam和PathVariable参数
*/
@Bean
public Converter<String, LocalDate> localDateConverter() {
return new Converter<String, LocalDate>() {
@Override
public LocalDate convert(String source) {
return LocalDate.parse(source, DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT));
}
};
}

/**
* LocalDateTime转换器,用于转换RequestParam和PathVariable参数
*/
@Bean
public Converter<String, LocalDateTime> localDateTimeConverter() {
return new Converter<String, LocalDateTime>() {
@Override
public LocalDateTime convert(String source) {
return LocalDateTime.parse(source, DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT));
}
};
}

/**
* LocalTime转换器,用于转换RequestParam和PathVariable参数
*/
@Bean
public Converter<String, LocalTime> localTimeConverter() {
return new Converter<String, LocalTime>() {
@Override
public LocalTime convert(String source) {
return LocalTime.parse(source, DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT));
}
};
}

/**
* Date转换器,用于转换RequestParam和PathVariable参数
*/
@Bean
public Converter<String, Date> dateConverter() {
return new Converter<String, Date>() {
@Override
public Date convert(String source) {
SimpleDateFormat format = new SimpleDateFormat(DEFAULT_DATE_TIME_FORMAT);
try {
return format.parse(source);
} catch (ParseException e) {
throw new RuntimeException(e);
}
}
};
}


/**
* Json序列化和反序列化转换器,用于转换Post请求体中的json以及将我们的对象序列化为返回响应的json
*/
@Bean("objectMapper")
public ObjectMapper objectMapper(){
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
objectMapper.disable(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE);

//LocalDateTime系列序列化和反序列化模块,继承自jsr310,我们在这里修改了日期格式
JavaTimeModule javaTimeModule = new JavaTimeModule();
javaTimeModule.addSerializer(LocalDateTime.class,new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)));
javaTimeModule.addSerializer(LocalDate.class,new LocalDateSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)));
javaTimeModule.addSerializer(LocalTime.class,new LocalTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)));
javaTimeModule.addDeserializer(LocalDateTime.class,new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)));
javaTimeModule.addDeserializer(LocalDate.class,new LocalDateDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)));
javaTimeModule.addDeserializer(LocalTime.class,new LocalTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)));


//Date序列化和反序列化
javaTimeModule.addSerializer(Date.class, new JsonSerializer<Date>() {
@Override
public void serialize(Date date, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
SimpleDateFormat formatter = new SimpleDateFormat(DEFAULT_DATE_TIME_FORMAT);
String formattedDate = formatter.format(date);
jsonGenerator.writeString(formattedDate);
}
});
javaTimeModule.addDeserializer(Date.class, new JsonDeserializer<Date>() {
@Override
public Date deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
SimpleDateFormat format = new SimpleDateFormat(DEFAULT_DATE_TIME_FORMAT);
String date = jsonParser.getText();
try {
return format.parse(date);
} catch (ParseException e) {
throw new RuntimeException(e);
}
}
});

objectMapper.registerModule(javaTimeModule);
return objectMapper;
}


}

+ 36
- 0
common/src/main/java/com/imitate/common/config/InitListener.java View File

@@ -0,0 +1,36 @@
package com.imitate.common.config;

import com.imitate.common.util.RedisPool;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
import redis.clients.jedis.Jedis;

@Component
public class InitListener implements ApplicationListener<ApplicationReadyEvent> {
private static final Logger log = LoggerFactory.getLogger(InitListener.class);

@Override
public void onApplicationEvent(ApplicationReadyEvent event) {
String active = System.getProperty("spring.profiles.active");
// 本地不初始化这些信息
Jedis jedis = null;
try {
if (!StringUtils.equals(active, "local")) {
// 初始化redis
jedis = RedisPool.getJedis();
}
} catch (Exception e) {
log.error("项目启动失败", e);
if ("jedisPool初始化错误".equals(e.getMessage())) {
Runtime.getRuntime().exit(-1);
}
} finally {
RedisPool.returnResource(jedis);
}
}

}

+ 35
- 0
common/src/main/java/com/imitate/common/config/JdbcConfig.java View File

@@ -0,0 +1,35 @@
package com.imitate.common.config;


import com.zaxxer.hikari.HikariDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.core.env.Environment;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;

/**
* @author yanchao
*/
@Component
public class JdbcConfig {
@Autowired
private Environment environment;

private static final String HOST = "com.mysql.cj.jdbc.Driver";
private static final String URL = "jdbc:mysql://rm-bp1ht3504joktie83.mysql.rds.aliyuncs.com:3306/educoderweb?useUnicode=true&characterEncoding=utf8&autoReconnect=true&failOverReadOnly=false";
private static final String USERNAME = "readonly";
private static final String PASSWORD = "readonly_20210901";


@Bean
public JdbcTemplate jdbcTemplate(){
HikariDataSource dataSource = new HikariDataSource();
dataSource.setDriverClassName(HOST);
dataSource.setJdbcUrl(URL);
dataSource.setUsername(USERNAME);
dataSource.setPassword(PASSWORD);
return new JdbcTemplate(dataSource);
}

}

+ 9
- 0
common/src/main/java/com/imitate/common/config/MybatisConfig.java View File

@@ -0,0 +1,9 @@
package com.imitate.common.config;

import org.springframework.context.annotation.Configuration;
import tk.mybatis.spring.annotation.MapperScan;

@Configuration
public class MybatisConfig {

}

+ 21
- 0
common/src/main/java/com/imitate/common/config/RedisListenerConfig.java View File

@@ -0,0 +1,21 @@
package com.imitate.common.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;


@Order(1)
@Configuration
public class RedisListenerConfig {

@Bean
RedisMessageListenerContainer listenerContainer(RedisConnectionFactory connectionFactory) {
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
return container;
}

}

+ 23
- 0
common/src/main/java/com/imitate/common/config/UncaughtBridgeExceptionHandler.java View File

@@ -0,0 +1,23 @@
/*
* Copyright 2017-2018 Educoder Group.
*/
package com.imitate.common.config;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

/**
* 未经捕获的异常处理
* @author weishao
*/
@Service
public class UncaughtBridgeExceptionHandler implements Thread.UncaughtExceptionHandler {

private static Logger logger = LoggerFactory.getLogger(UncaughtBridgeExceptionHandler.class);

@Override
public void uncaughtException(Thread t, Throwable e) {
// 此处只处理善后异常,其它已经在善后处理中解决
}
}

+ 63
- 0
common/src/main/java/com/imitate/common/config/WebMvcConfig.java View File

@@ -0,0 +1,63 @@
package com.imitate.common.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.imitate.common.interceptor.SignInterceptor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;

import java.util.List;


/**
*
* @author yanchao
*/
@Configuration
@Order(1)
@Slf4j
public class WebMvcConfig extends WebMvcConfigurationSupport {

@Override
public void addInterceptors(InterceptorRegistry registry) {
//签名拦截器
registry.addInterceptor(getHandlerInterceptor());
}

@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
log.debug("【配置argumentResolver】ok");
}


@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedHeaders("Content-Type", "x-requested-with", "X-Custom-Header")
.allowedOriginPatterns("*")
.allowedMethods("GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS")
.allowCredentials(true)
.maxAge(3600);
}

@Bean
public HandlerInterceptor getHandlerInterceptor() {
return new SignInterceptor();
}






}

+ 7
- 0
common/src/main/java/com/imitate/common/constant/ApiResultCsts.java View File

@@ -0,0 +1,7 @@
package com.imitate.common.constant;

public interface ApiResultCsts {
int CODE_SUCCESS = 0;
int CODE_FAIL = -1;

}

+ 76
- 0
common/src/main/java/com/imitate/common/constant/BuildResultCsts.java View File

@@ -0,0 +1,76 @@
package com.imitate.common.constant;

public interface BuildResultCsts {

/**
* 完整结果正则。
*
*/
// \{ 匹配 { , [\s]* 匹配0-多个空白字符, "compileResult"[\s]*:匹配"compileResult":
// [\s\S]*匹配0-多个任意字符, [\s\S]*"out"[\s]*:匹配"out": , [^}]*匹配除}之外的所有字符
String FULL_RESULT_REG = "\\{[\\s]*\"compileResult\"[\\s]*:[\\s\\S]*\"out\"[\\s]*:[^}]*}";

String TIMEOUT_RES_USAGE = "\\{[\\s]*\"exitStatus\"[\\s]*:[\\s\\S]*\"evaCpuUsage\"[\\s]*:[\\s\\S]*\"nodeLoadAvg\"[\\s]*:[^}]*}";

String SYS_BUSY_TIP = "系统繁忙,请稍后重试";
String SYS_BUSY_BASE64 = "57O757uf57mB5b-Z77yM6K-356iN5ZCO6YeN6K-V";

String EVA_UNDEFINED_ERROR_TIP = "程序执行失败导致评测提前终止,请稍后重试或联系系统管理员。";
String EVA_UNDEFINED_ERROR_BASE64 = "56iL5bqP5omn6KGM5aSx6LSl5a-86Ie06K-E5rWL5o-Q5YmN57uI5q2i77yM6K-356iN5ZCO6YeN6K-V5oiW6IGU57O757O757uf566h55CG5ZGY44CC";

String EVA_UNPUBLISHED_SCRIPT_ERROR_TIP = "评测脚本设置异常,建议您在实训的配置页面重新选择或修改评测脚本。";
String EVA_UNPUBLISHED_SCRIPT_ERROR_BASE64 = "6K-E5rWL6ISa5pys6K6-572u5byC5bi477yM5bu66K6u5oKo5Zyo5a6e6K6t55qE6YWN572u6aG16Z2i6YeN5paw6YCJ5oup5oiW5L-u5pS56K-E5rWL6ISa5pys44CC";

String EVA_PUBLISHED_SCRIPT_ERROR_TIP = "评测脚本设置异常,请联系老师在实训的配置页面重新选择或修改评测脚本。";
String EVA_PUBLISHED_SCRIPT_ERROR_BASE64 = "6K-E5rWL6ISa5pys6K6-572u5byC5bi477yM6K-36IGU57O76ICB5biI5Zyo5a6e6K6t55qE6YWN572u6aG16Z2i6YeN5paw6YCJ5oup5oiW5L-u5pS56K-E5rWL6ISa5pys44CC";

// String EVA_RETRY_ERROR_TIP = "本实训有严格的资源限制,当前账号对资源占有级别较低,请10秒后重试。";
// String EVA_RETRY_ERROR_BASE64 = "5pys5a6e6K6t5pyJ5Lil5qC855qE6LWE5rqQ6ZmQ5Yi277yM5b2T5YmN6LSm5Y-35a-56LWE5rqQ5Y2g5pyJ57qn5Yir6L6D5L2O77yM6K-3MTDnp5LlkI7ph43or5XjgII";

String EVA_RETRY_ERROR_TIP = "本次评测网络延迟较高,资源无法正常加载,请10s后重试。";
String EVA_RETRY_ERROR_BASE64 = "5pys5qyh6K-E5rWL572R57uc5bu26L-f6L6D6auY77yM6LWE5rqQ5peg5rOV5q2j5bi45Yqg6L2977yM6K-3MTBz5ZCO6YeN6K-V44CC";

String EVA_WINDOWS_ERROR_TIP = "实验环境存在问题或已被回收,请保存数据再重置实训重新评测。";

String EVA_VIRTUAL_NOT_READY_TIP = "环境尚未初始化完成,请稍后重试。";

String POD_HAVE_BEEN_CLEANED_TIP = "当前资源因未持续使用正在回收中,稍后重试即可。";
String POD_HAVE_BEEN_CLEANED_BASE64 = "5b2T5YmN6LWE5rqQ5Zug5pyq5oyB57ut5L2_55So5q2j5Zyo5Zue5pS25Lit77yM56iN5ZCO6YeN6K-V5Y2z5Y-v44CC";

String REDO_EVALUATING_FAIL_TIP = "当前账号两次评测间歇时间较短,请稍后重试!";
String REDO_EVALUATING_FAIL_BASE64 = "5b2T5YmN6LSm5Y-35Lik5qyh6K-E5rWL6Ze05q2H5pe26Ze06L6D55-t77yM6K-356iN5ZCO6YeN6K-V77yB";

String EVA_OVER_MEMORY_LIMIT_TIP = "当前运行程序超过系统最大空间限制,请检查程序是否存在死循环或内存泄漏等问题!";
String EVA_OVER_MEMORY_LIMIT_BASE64 = "5b2T5YmN6L+Q6KGM56iL5bqP6LaF6L+H57O757uf5pyA5aSn5YaF5a2Y6ZmQ5Yi277yM6K+35qOA5p+l56iL5bqP5piv5ZCm5a2Y5Zyo5q275b6q546v5oiW5YaF5a2Y5rOE5ryP562J6Zeu6aKY77yB";
String EVA_OVER_MEMORY_LIMIT_BASE64_REENCODE = "5b2T5YmN6L-Q6KGM56iL5bqP6LaF6L-H57O757uf5pyA5aSn5YaF5a2Y6ZmQ5Yi277yM56iL5bqP5Y-v6IO95a2Y5Zyo5q275b6q546v5oiW6ICF5YaF5a2Y5rOE5ryP562J6Zeu6aKY77yBDQo";

String PULL_IMAGE_FAIL = "当前实验环境正在更新中,请稍后重试或联系系统管理员!";
String CLONE_CODE_FAIL = "当前网络较差,代码下载超时,请稍后重试!";
String CLONE_CODE_FAIL_BASE64_REENCODE = "5b2T5YmN572R57uc6L6D5beu77yM5Luj56CB5LiL6L296LaF5pe277yM6K-356iN5ZCO6YeN6K-V77yB";

String RES_SCALE_TIP = "当前实验使用的用户较多,系统正在智能化为您调度更优质的资源,预计一分钟内完成,请稍后重试!";
String RES_SCALE_BASE64 = "5b2T5YmN5a6e6aqM5L2_55So55qE55So5oi36L6D5aSa77yM57O757uf5q2j5Zyo5pm66IO95YyW5Li65oKo6LCD5bqm5pu05LyY6LSo55qE6LWE5rqQ77yM6aKE6K6h5LiA5YiG6ZKf5YaF5a6M5oiQ77yM6K-356iN5ZCO6YeN6K-V77yB";

String OUTPUT_TOO_LONG_ERROR = "cannot allocate";
String INPUT_TOO_LONG_ERROR = "argument list too long";
String OUTPUT_TOO_LONG_TIP = "评测输出结果过长,请检查代码逻辑";
String INPUT_TOO_LONG_TIP = "评测测试用例过长,请采用文件测试用例形式";

String COMPILE_SUCCESS_TIP = "compile successfully";
String COMPILE_SUCCESS_BASE64 = "Y29tcGlsZSBzdWNjZXNzZnVsbHk";

String DOWNLOAD_STATUS = "downloadStatus";
String DOWNLOAD_STATUS_SUCCESS = "1";
String DOWNLOAD_STATUS_FAIL = "0";

String CREATE_POD_STATUS = "createPodStatus";
String CREATE_POD_STATUS_SUCCESS = "1";
String CREATE_POD_STATUS_FAIL = "0";

String COMPILE_SUCCESS_YES = "1";
String COMPILE_SUCCESS_NO = "0";

String TEXT_MSG_SERVICE_START = "服务启动中...";
String TEXT_MSG_SERVICE_SUCCESS = "服务启动完成";
String TEXT_MSG_REDO_EVA = "重复评测中...";
}

+ 217
- 0
common/src/main/java/com/imitate/common/constant/TpCsts.java View File

@@ -0,0 +1,217 @@
package com.imitate.common.constant;

public interface TpCsts {
String TPI_ID = "tpiID";
/**
* 类型
*/
String TYPE_EVALUATE = "evaluate";
String TYPE_EVASSH = "evassh";
String TYPE_WEBSSH = "webssh";
String TYPE_VNC = "vnc";
String TYPE_JUPYTER = "jupyter";
String TYPE_VSCODE = "vscode";
String TYPE_WEB = "web";

int POD_TYPE_EVALUATE = 0;
int POD_TYPE_WEBSSH = 1;
int POD_TYPE_EVASSH = 2;
int POD_TYPE_VNC = 3;
int POD_TYPE_JUPYTER = 4;
int POD_TYPE_VSCODE = 5;
int POD_TYPE_WEB = 6;

/**
* 全部可评测实训clone到tpiWorkspace, 都命名为此
*/
String TP_UNIFY_REPO_NAME = "myshixun";


String TP_RASPBERRY_REPO_SCRIPT = "raspberry";

String TP_USERFILES_NAME = "userfiles";

/**
* pod 分配对node的要求
*/
String NODE_REQUIRE = "nodeRequire";

String NODE_TYPE = "type";
String NODE_TYPE_OTHERS = "others";
String NODE_TYPE_GPU = "Python-GPU";

/**
* shenlong节点
*/
String SHENLONG_NODE_LABEL_KEY = "shenlong";
String SHENLONG_NODE_LABEL_VALUE = "true";

/**
* GPU节点
*/
String GPU_NODE_LABEL_KEY = "GPU";
String GPU_NODE_LABEL_VALUE = "true";

/**
* oj pod 和 node
*/
String OJ_LABEL_KEY = "oj";
String OJ_LABEL_VALUE = "true";

String OJ_CAPACITY_NODE_LABEL_KEY = "capacity";

/**
* OJ 平台类型
*/
String PLATFORM = "platform";

/**
* tpi评测需要用到的平台资源,在pod中的挂载路径
*/
String TPI_PLATFORM_MOUNT_PATH = "/data/platform/eva";


String VNC_POD_DEV_SHM_PATH = "/dev/shm";

/**
* tpi保护空间的挂载路径,存放评测执行脚本等
*/
String TPI_PROTECT_SPACE_MOUNT_PATH = "/data/protectspace";
/**
* tpi工作空间的挂载路径
*/
String TPI_WORKSPACE_MOUNT_PATH = "/data/workspace";

/**
* 评测分步输出消息匹配格式
*/
String EVA_STEP_OUT_MSG_PREFIX = "{\"step\":";
String EVA_STEP_OUT_MSG_SUFFIX = "}";


/**
* 超时编码:不确定
*/
int TIMEOUT_CODE_UNSURE = 1;
/**
* 超时编码:死循环
*/
int TIMEOUT_CODE_DEAD_LOOP = 2;
/**
* 超时编码:阻塞。(1)读取输入阻塞,(2)网络编程端口阻塞,(3)多线程阻塞。
*/
int TIMEOUT_CODE_BLOCKING = 3;
/**
* 超时编码:节点繁忙
*/
int TIMEOUT_CODE_NODE_BUSY = 4;

/**
* 主题:pod 调度
*/
String TOPIC_POD_SCHEDULE = "pod_schedule";
/**
* 主题:评测
*/
String TOPIC_EVALUATING = "evaluating";

String POD_SCHEDULE_CLUSTER_REDIS_KEY = "pod_schedule_cluster_";

long POD_SCHEDULE_CLUSTER_REDIS_EXPIRE_TIME = 5000;

String STATEFUL_POD_CLUSTER_RECORD_REDIS_KEY = "stateful_pod_schedule_";

long STATEFUL_POD_CLUSTER_RECORD_EXPIRE_TIME = 2 * 24 * 60 * 60 * 1000; // 2天

/**
* 评测开始存入redis,评测结束则删除。存在key,表明评测正在进行,value为true表示为重复评测。
*/
String REDO_EVALUATING_REDIS_KEY = "redo_evaluating_";

String REDO_EVALUATING_REDIS_VALUE_TRUE = "true";

String REDO_EVALUATING_REDIS_VALUE_FALSE = "false";

String RESET_LOCAL_REDIS_KEY = "reset_local_";

String CREATE_IMAGE_MAP = "create_image";

String CREATE_IMAGE_NAME_REDIS_KEY = "create_image_name_";

Long CREATE_IMAGE_NAME_REDIS_EXPIRE_TIME = 30 * 24 * 60 * 60 * 1000L; // 30天

String CREATE_IMAGE_TPI_ID_REDIS_KEY = "create_image_tpi_id_";

long CREATE_IMAGE_TPI_ID_REDIS_EXPIRE_TIME = 60 * 1000L; // 1分钟

long NODE_IMAGE_STATUS_EXPIRE_TIME = 30 * 60 * 1000L; // 30分钟

String K8S_NODE_STATUS_READY = "Ready";

String K8S_NODE_STATUS_NOT_READY = "NotReady";

String K8S_NODE_STATUS_LABEL_VALUE = "status";

String K8S_ELASTIC_NODE_LABEL_KEY = "tx";

String K8S_ELASTIC_NODE_LABEL_VALUE = "normal";

String K8S_NEW_CAPACITY_NODE_LABEL_KEY = "newCapacity";

String K8S_NEW_CAPACITY_NODE_LABEL_VALUE = "true";

String K8S_NEW_CAPACITY_NODE_REDIS_KEY = "k8s_new_capacity_node_key";

String K8S_NODE_PRE_REDUCE_LABEL_KEY = "pre_reduce";

String K8S_NODE_PRE_REDUCE_LABEL_VALUE = "true";

String K8S_PRE_REDUCE_NODE_REDIS_KEY = "k8s_pre_reduce_node_key";

String CLOUD_HOST_TYPE_WINDOWS = "windows";

String PROXMOX_HOST_TYPE_VIRTUAL = "virtual";

String CLOUD_HOST_TYPE_LINUX = "linux";

Integer NODE_CPU_USAGE_UNKNOWN = -1;

String JUPYTER_TYPE_LAB = "lab";
String JUPYTER_TYPE_NOTEBOOK = "notebook";

String IGNORED = "ignored";

/**
* 用户实时运行输出位置
*/
String USER_OUTPUT_FILE = "user.out";

/**
* 用户case输出分隔符
*/
String CASE_OUTPUT_SEPARATOR = "\\x1b\\x09\\x1d";

/**
* 本地集群
*/
String LOCAL_CLUSTER = "local";

/**
* 默认工作空间
*/
String DEFAULT_NAMESPACE = "default";

/**
* 挂载点名称
*/
String WORKSPACE = "workspace";
String TEST_CASE_DIR = "test-case-dir";
String TEST_CASE_ACTUAL_OUT_DIR = "test-case-actual-out-dir";
String PROTECT_DIR = "protect";

/**
* 仅运行结果前缀
*/
String RUN_ONLY_RESULT_KEY_PREFIX = "runOnlyResult";

}

+ 53
- 0
common/src/main/java/com/imitate/common/enums/CommonStateEnum.java View File

@@ -0,0 +1,53 @@
package com.imitate.common.enums;

/**
* 通用状态枚举 0为否定含义,1为肯定含义
* @author 威少
*/
public enum CommonStateEnum {
/**
* 否定含义
*/
FALSE(0, false),
/**
* 肯定含义
*/
TRUE(1, true);

int value;

boolean booleanValue;

CommonStateEnum(int value, boolean booleanValue) {
this.value = value;
this.booleanValue = booleanValue;
}


public int getValue() {
return value;
}

public boolean getBooleanValue() {
return booleanValue;
}

/**
* 从bool值转换
* @param value bool值
* @return 肯定为1,否定为0
*/
public static CommonStateEnum fromBoolean(Boolean value) {
return value == null ? FALSE : value ? TRUE : FALSE;
}

/**
* 从整型值转换
* @param value 整型值
* @return 肯定为1,否定为0
*/
public static CommonStateEnum fromInteger(Integer value) {
return value == null || value == FALSE.getValue() ? FALSE : TRUE;
}

}

+ 60
- 0
common/src/main/java/com/imitate/common/enums/ErrorCodeEnum.java View File

@@ -0,0 +1,60 @@
package com.imitate.common.enums;

import java.util.Arrays;


/**
* 全局错误枚举
* @author yanchao
*/
public enum ErrorCodeEnum {
SUCCESS("000000","成功"),
INVALID_ARG_EXCEPTION("000001","参数验证异常"),
BIND_EXCEPTION("000007","参数绑定异常"),
MVC_BIND_EXCEPTION("000014","请求参数绑定异常"),
METHOD_NOT_ALLOWED_EXCEPTION("000008","请求方式异常"),
EXCEPTION("999999","系统异常"),
DATAFLOW_EXCEPTION("000010","默认数据异常"),
BUSINESS_EXCEPTION("000011","默认业务异常"),
LOGIN_EXPIRE_TIME("000013","登录已过期,请重新登录"),
USER_LOGIN_DISABLE("000014","账号已经锁定,请联系管理员"),
NO_AUTH("000012","未认证登录状态"),
AFTERMATH_EXP("000013","评测线程出错,善后处理发生异常"),
GIT_FAIL("000014","获取git凭证失败: "),
GIT_CREDENTIAL_FAIL("000015","设置git凭证失败:"),


CLONE_FAIL("100001","克隆失败"),
EVALUATION_SHELL_FAIL("100002","生成评测脚本失败"),
WRITE_FILE_CODE_FAIL("100003","写代码文件失败"),
UPDATE_VERSION_REPOSITORY_FAIL("100004","更新版本库失败"),
SYNC_CLUSTER_VERSION_REPOSITORY_FAIL("100005","远程集群版本库同步失败"),
PUSH_FAIL("100006","push版本库失败"),
JUPYTER_ADD_OR_COMMIT_FAIL("100007","Jupyter添加提交失败"),
VERSION_REPOSITORY_NOT_EXIST("10000","主机名不存在");


String value;
String description;

ErrorCodeEnum(String value, String description) {
this.value = value;
this.description = description;
}

public String getValue() {
return value;
}

public String getDescription() {
return description;
}

public static ErrorCodeEnum getByDescription(String description) {
return Arrays.stream(values()).filter(errorCodeEnum -> errorCodeEnum.getDescription().equals(description)).findFirst().orElse(null);
}

}




+ 36
- 0
common/src/main/java/com/imitate/common/exception/BusinessException.java View File

@@ -0,0 +1,36 @@
package com.imitate.common.exception;

import com.imitate.common.enums.ErrorCodeEnum;

/**
* 业务异常
* @author yanchao
*/
public class BusinessException extends RuntimeException{
/**
* 错误码
*/
private String errCode = ErrorCodeEnum.DATAFLOW_EXCEPTION.getValue();

public BusinessException(ErrorCodeEnum errorCodeEnum){
super(errorCodeEnum.getDescription());
setErrCode(errorCodeEnum.getValue());
}


public BusinessException(String code,String msg){
super(msg);
setErrCode(code);
}



public void setErrCode(String errCode) {
this.errCode = errCode;
}

public String getErrCode() {
return errCode;
}
}


+ 117
- 0
common/src/main/java/com/imitate/common/interceptor/HttpServletRequestFilter.java View File

@@ -0,0 +1,117 @@
package com.imitate.common.interceptor;


import com.imitate.common.util.HttpContextUtil;
import org.apache.commons.io.IOUtils;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;
import java.nio.charset.StandardCharsets;

/***
* HttpServletRequest 过滤器
* 解决: request.getInputStream()只能读取一次的问题
* 目标: 流可重复读
* @author yanchao
*/
@Component
@WebFilter(filterName = "HttpServletRequestFilter", urlPatterns = "/")
@Order(10000)
public class HttpServletRequestFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
ServletRequest requestWrapper = null;
if(servletRequest instanceof HttpServletRequest) {
requestWrapper = new RequestWrapper((HttpServletRequest) servletRequest);
}
//获取请求中的流如何,将取出来的字符串,再次转换成流,然后把它放入到新request对象中
// 在chain.doFiler方法中传递新的request对象
if(null == requestWrapper) {
filterChain.doFilter(servletRequest, servletResponse);
} else {
filterChain.doFilter(requestWrapper, servletResponse);
}
}
@Override
public void destroy() {
}

/***
* HttpServletRequest 包装器
* 解决: request.getInputStream()只能读取一次的问题
* 目标: 流可重复读
*/
public static class RequestWrapper extends HttpServletRequestWrapper {
//参数字节数组
private byte[] requestBody;
//Http请求对象
private HttpServletRequest request;

public RequestWrapper(HttpServletRequest request) throws IOException {
super(request);
this.request = request;
}

/**
* @return
* @throws IOException
*/
@Override
public ServletInputStream getInputStream() throws IOException {
/**
* 每次调用此方法时将数据流中的数据读取出来,然后再回填到InputStream之中
* 解决通过@RequestBody和@RequestParam(POST方式)读取一次后控制器拿不到参数问题
*/
if (null == this.requestBody) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
IOUtils.copy(request.getInputStream(), baos);
this.requestBody = baos.toByteArray();
}

final ByteArrayInputStream bais = new ByteArrayInputStream(requestBody);
return new ServletInputStream() {

@Override
public boolean isFinished() {
return false;
}

@Override
public boolean isReady() {
return false;
}

@Override
public void setReadListener(ReadListener listener) {

}

@Override
public int read() {
return bais.read();
}
};
}

public byte[] getRequestBody() {
return requestBody;
}

@Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(this.getInputStream()));
}
}



}

+ 142
- 0
common/src/main/java/com/imitate/common/interceptor/SignInterceptor.java View File

@@ -0,0 +1,142 @@
package com.imitate.common.interceptor;

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

import com.imitate.common.annotation.PublicUrl;
import com.imitate.common.util.SignUtil;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.Map;


/**
* 签名认证拦截器
* @author 悟空
*/
public class SignInterceptor implements HandlerInterceptor {


@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
if(handler instanceof HandlerMethod){
HandlerMethod handlerMethod = (HandlerMethod) handler;

ValidateResponse validateResponse = new ValidateResponse(true);
PublicUrl publicUrl = handlerMethod.getMethodAnnotation(PublicUrl.class);
if (null != publicUrl) {
if (publicUrl.signValidate()) {

BufferedReader streamReader = new BufferedReader( new InputStreamReader(request.getInputStream(), "UTF-8"));
StringBuilder responseStrBuilder = new StringBuilder();
String inputStr;
while ((inputStr = streamReader.readLine()) != null) {
responseStrBuilder.append(inputStr);
}
Map<String,String> params = JSON.parseObject(responseStrBuilder.toString(), Map.class);

if(params != null){
validateResponse = paramSignValidate(params, response);
}else{
validateResponse = paramSignValidate(request, response);
}

}
}
/*if (!validateResponse.isValidate()) {
JSONObject result = new JSONObject();
result.put("code","-1");
result.put("msg","签名认证失败");
returnJson(response,result.toJSONString());
return false;
}*/
}
return true;
}


/**
* 签名校验
*
* @param request
* @param response
* @return
*/
private ValidateResponse paramSignValidate(HttpServletRequest request, HttpServletResponse response) {
String sign = request.getParameter("sign");
Map<String, String[]> map = request.getParameterMap();
// 将参数按照一定规则获取到sign和前端传过来的sign进行比较,规则自定义需要和前端一致
String sign1 = SignUtil.signMap(map);
if (ObjectUtil.isEmpty(sign) || !sign.equals(sign1)) {
return new ValidateResponse(false);
}
return new ValidateResponse(true);
}

/**
* 签名校验
*
* @param
* @param response
* @return
*/
private ValidateResponse paramSignValidate(Map<String,String> params, HttpServletResponse response) {
String sign = params.get("sign");
// 将参数按照一定规则获取到sign和前端传过来的sign进行比较,规则自定义需要和前端一致
String sign1 = SignUtil.signMap(null, params);
if (ObjectUtil.isEmpty(sign) || !sign.equals(sign1)) {
return new ValidateResponse(false);
}
return new ValidateResponse(true);
}


/**
* 校验返回对象
*/
private static class ValidateResponse {
private boolean validate;
public ValidateResponse(boolean validate) {
this.validate = validate;
}
public boolean isValidate() {
return validate;
}
}




/**
* 认证失败返回json数据
* @param response
* @param json
* @throws Exception
*/
@SuppressWarnings("unused")
private void returnJson(HttpServletResponse response, String json) throws Exception{
PrintWriter writer = null;
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json; charset=utf-8");
try {
writer = response.getWriter();
writer.print(json);
} catch (IOException e) {
} finally {
if (writer != null) {
writer.close();
}
}
}


}

+ 73
- 0
common/src/main/java/com/imitate/common/k8s/bean/BridgeContainer.java View File

@@ -0,0 +1,73 @@
package com.imitate.common.k8s.bean;



public class BridgeContainer {
private boolean mainContainer;

private String name;

private String image;

private Double cpuRequest;
private Double cpuLimit;
private Double memoryRequest;
private Double memoryLimit;

public boolean isMainContainer() {
return mainContainer;
}

public void setMainContainer(boolean mainContainer) {
this.mainContainer = mainContainer;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getImage() {
return image;
}

public void setImage(String image) {
this.image = image;
}

public Double getCpuRequest() {
return cpuRequest;
}

public void setCpuRequest(Double cpuRequest) {
this.cpuRequest = cpuRequest;
}

public Double getCpuLimit() {
return cpuLimit;
}

public void setCpuLimit(Double cpuLimit) {
this.cpuLimit = cpuLimit;
}

public Double getMemoryRequest() {
return memoryRequest;
}

public void setMemoryRequest(Double memoryRequest) {
this.memoryRequest = memoryRequest;
}

public Double getMemoryLimit() {
return memoryLimit;
}

public void setMemoryLimit(Double memoryLimit) {
this.memoryLimit = memoryLimit;
}

}

+ 47
- 0
common/src/main/java/com/imitate/common/k8s/bean/BridgeNode.java View File

@@ -0,0 +1,47 @@
package com.imitate.common.k8s.bean;


import java.time.LocalDateTime;

public class BridgeNode {

private String name;
private String ip;

private LocalDateTime createTime;

private Integer podNum;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getIp() {
return ip;
}

public void setIp(String ip) {
this.ip = ip;
}

public LocalDateTime getCreateTime() {
return createTime;
}

public void setCreateTime(LocalDateTime createTime) {
this.createTime = createTime;
}

public Integer getPodNum() {
return podNum;
}

public void setPodNum(Integer podNum) {
this.podNum = podNum;
}

}

+ 231
- 0
common/src/main/java/com/imitate/common/k8s/bean/BuildResult.java View File

@@ -0,0 +1,231 @@
package com.imitate.common.k8s.bean;

import java.util.List;

/**
* 评测结果
*
* @author liliy
*/

public class BuildResult {
private String buildID;
private String tpiID;
private String status;
private Integer timeoutCode;
private String outPut;
private List<ExecResultCase> msg;
private String resubmit;
private String compileSuccess;
private String executeSuccess;
private String createPodStatus;
private String downloadStatus;
private String sec_key;
private String showServer;
private String extras;

public boolean isSysBusy() {
return "57O757uf57mB5b-Z77yM6K-356iN5ZCO6YeN6K-V".equals(outPut);
}

public boolean isTimeOut() {
String timeOutMsg = "5Luj56CB6K-E5rWL6LaF5pe277yB";
for (ExecResultCase c : msg) {
if (c.getOutput().startsWith(timeOutMsg)) {
return Boolean.TRUE;
}
}
return Boolean.FALSE;
}

/**
* 步骤。输出分步输出时的步骤
*/
private String step;
/**
* 输出存文本
*/
private String textMsg;

public String getSec_key() {
return sec_key;
}

public void setSec_key(String sec_key) {
this.sec_key = sec_key;
}

public String getBuildID() {
return buildID;
}

public void setBuildID(String buildID) {
this.buildID = buildID;
}

public String getTpiID() {
return tpiID;
}

public void setTpiID(String tpiID) {
this.tpiID = tpiID;
}

public String getStatus() {
return status;
}

public void setStatus(String status) {
this.status = status;
}

public String getOutPut() {
return outPut;
}

public void setOutPut(String outPut) {
this.outPut = outPut;
}

public List<ExecResultCase> getMsg() {
return msg;
}

public void setMsg(List<ExecResultCase> msg) {
this.msg = msg;
}

public String getResubmit() {
return resubmit;
}

public void setResubmit(String resubmit) {
this.resubmit = resubmit;
}

public BuildResult(String buildID, String tpiID, String status, String outPut, List<ExecResultCase> msg, String resubmit,
String sec_key, String showServer, String extras) {
this.buildID = buildID;
this.tpiID = tpiID;
this.status = status;
this.outPut = outPut;
this.msg = msg;
this.resubmit = resubmit;
this.sec_key = sec_key;
this.showServer = showServer;
this.extras = extras;
}

public String getCompileSuccess() {
return compileSuccess;
}

public void setCompileSuccess(String compileSuccess) {
this.compileSuccess = compileSuccess;
}

public String getStep() {
return step;
}

public void setStep(String step) {
this.step = step;
}

public String getTextMsg() {
return textMsg;
}

public void setTextMsg(String textMsg) {
this.textMsg = textMsg;
}

public String getCreatePodStatus() {
return createPodStatus;
}

public void setCreatePodStatus(String createPodStatus) {
this.createPodStatus = createPodStatus;
}

public String getDownloadStatus() {
return downloadStatus;
}

public void setDownloadStatus(String downloadStatus) {
this.downloadStatus = downloadStatus;
}

public String getShowServer() {
return showServer;
}

public void setShowServer(String showServer) {
this.showServer = showServer;
}

public Integer getTimeoutCode() {
return timeoutCode;
}

public void setTimeoutCode(Integer timeoutCode) {
this.timeoutCode = timeoutCode;
}

public String getExtras() {
return extras;
}

public void setExtras(String extras) {
this.extras = extras;
}

public String getExecuteSuccess() {
return executeSuccess;
}

public void setExecuteSuccess(String executeSuccess) {
this.executeSuccess = executeSuccess;
}

public enum Status {
/**
* 评测通过
*/
PASS("0"),
/**
* 评测不通过
*/
FAIL("-1"),
/**
* oj 评测超时
*/
RUN_TIMEOUT("2"),
/**
* 创建pod 超时
*/
CREATE_POD_FAIL("3"),
/**
* 编译错误
*/
COMPILE_FAIL("4"),
/**
* 执行错误,执行用户程序,进程返回-1。如数组越界
*/
EXECUTE_ERROR("5");

private String value;

public String getValue() {
return value;
}

public void setValue(String value) {
this.value = value;
}

Status(String value) {
this.value = value;
}
}
}

+ 384
- 0
common/src/main/java/com/imitate/common/k8s/bean/ClusterInfo.java View File

@@ -0,0 +1,384 @@
package com.imitate.common.k8s.bean;


import com.google.common.util.concurrent.AtomicDouble;
import com.imitate.common.k8s.constant.BridgeNodeCsts;
import com.imitate.common.k8s.util.K8sUtils;
import com.imitate.common.sys.pojo.ClusterConfig;
import io.fabric8.kubernetes.api.model.Node;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ClusterInfo {
/**
* 集群配置
*/
private ClusterConfig clusterConfig;
/**
* 是否自动扩容
*/
private Boolean autoscale;
/**
* 比重
*/
private double weight;

/**
* 集群节点 Map<nodeName, Node>
*/
private Map<String, Node> nodeMap;

/**
* 集群pod总数
*/
private int podCount;

/**
* 集群可分配cpu 总量
*/
private double allocatableCpu;

/**
* 集群可分配memory 总量,以M为单位
*/
private double allocatableMemory;

/**
* 固定节点数量
*/
private int foreverNodeNum;

/**
* 扩容节点数量
*/
private int scaleNodeNum;

/**
* 集群已分配的request cpu 总量
*/
private double requestCpuSum;

/**
* 集群已分配的request memory 总量
*/
private double requestMemorySum;
/**
* 集群已被预订的request cpu 总量。pod已经被分配到此集群,但还没有创建。
*/
private AtomicDouble reserveRequestCpuSum = new AtomicDouble(0);

/**
* 集群已被预订的request memory 总量。pod已经被分配到此集群,但还没有创建。
*/
private AtomicDouble reserveRequestMemorySum = new AtomicDouble(0);

/**
* 集群剩余可分配的request cpu 总量
*/
private double surplusCpuSum;

/**
* 集群剩余可分配的request memory 总量
*/
private double surplusMemorySum;

/**
* 集群固定节点可分配cpu 总量
*/
private double foreverAllocatableCpuSum;

/**
* 集群固定节点可分配memory 总量
*/
private double foreverAllocatableMemorySum;

/**
* 折算固定节点 request cpu比例。把扩容节点上的request cpu折算到固定节点
*/
private double conversionForeverNodeRequestCpuRatio;

/**
* 折算固定节点 request memory比例。把扩容节点上的request memory折算到固定节点
*/
private double conversionForeverNodeRequestMemoryRatio;
private double requestCpuRatio;
private double requestMemoryRatio;
public void cal(String cluster, List<Node> nodes, List<NodeResStat> nodeResStats) {
Map<String, Node> nodeMap = new HashMap<>();
for (Node node : nodes) {
nodeMap.put(node.getMetadata().getName(), node);
}

double allocatableCpuCount = 0;
double allocatableMemoryCount = 0;
double foreverNodeAllocatableCpuCount = 0;
double foreverNodeAllocatableMemoryCount = 0;
int foreverNodeNum = 0;
int scaleNodeNum = 0;
for(Node node : nodes) {
String typeVal = K8sUtils.getLabel(node, BridgeNodeCsts.NODE_LABEL_TYPE);
boolean isEvaNode = BridgeNodeCsts.NODE_LABEL_TYPE_OTHERS.equals(typeVal)
|| BridgeNodeCsts.NODE_LABEL_TYPE_UNDER_PRESSURE.equals(typeVal);
if(!isEvaNode || K8sUtils.isOjNode(node)) { // 普通评测节点
continue;
}
double nodeAllocatableCpu = K8sUtils.getNodeAllocatableCpu(node);
allocatableCpuCount += nodeAllocatableCpu;

double allocatableMemory = K8sUtils.getNodeAllocatableMemory(node);
allocatableMemoryCount += allocatableMemory;
String txVal = K8sUtils.getLabel(node, "tx");
if("normal".equals(txVal)) { // 扩容节点
scaleNodeNum ++;
} else {
foreverNodeAllocatableCpuCount += nodeAllocatableCpu;
foreverNodeAllocatableMemoryCount += allocatableMemory;
foreverNodeNum ++;
}
}

double requestCpuSum = 0;
double requestMemorySum = 0;

int podCount = 0;
for (NodeResStat nodeResStat : nodeResStats) {
if (cluster.equals(nodeResStat.getCluster())) {
podCount += nodeResStat.getPodNum();
requestCpuSum += nodeResStat.getCpuRequest();
requestMemorySum += nodeResStat.getMemoryRequest();
}
}

double conversionForeverNodeRequestCpuRatio = requestCpuSum / foreverNodeAllocatableCpuCount * 100;
double conversionForeverNodeRequestMemoryRatio = requestMemorySum / foreverNodeAllocatableMemoryCount * 100;
double surplusCpuSum = allocatableCpuCount - requestCpuSum;
double surplusMemorySum = allocatableMemoryCount - requestMemorySum;
double requestCpuRatio = allocatableCpuCount == 0 ? 100 : (requestCpuSum / allocatableCpuCount * 100);
double requestMemoryRatio = allocatableMemoryCount == 0 ? 100
: (requestMemorySum / allocatableMemoryCount * 100);

setNodeMap(nodeMap);
setPodCount(podCount);
setAllocatableCpu(allocatableCpuCount);
setAllocatableMemory(allocatableMemoryCount);
setForeverNodeNum(foreverNodeNum);
setScaleNodeNum(scaleNodeNum);
setRequestCpuSum(requestCpuSum);
setRequestMemorySum(requestMemorySum);
setSurplusCpuSum(surplusCpuSum);
setSurplusMemorySum(surplusMemorySum);
setForeverAllocatableCpuSum(foreverNodeAllocatableCpuCount);
setForeverAllocatableMemorySum(foreverNodeAllocatableMemoryCount);
setConversionForeverNodeRequestCpuRatio(conversionForeverNodeRequestCpuRatio);
setConversionForeverNodeRequestMemoryRatio(conversionForeverNodeRequestMemoryRatio);
setRequestCpuRatio(requestCpuRatio);
setRequestMemoryRatio(requestMemoryRatio);
}
public ClusterConfig getClusterConfig() {
return clusterConfig;
}

public void setClusterConfig(ClusterConfig clusterConfig) {
this.clusterConfig = clusterConfig;
}

public Boolean getAutoscale() {
return autoscale;
}

public void setAutoscale(Boolean autoscale) {
this.autoscale = autoscale;
}

public double getWeight() {
return weight;
}

public void setWeight(double weight) {
this.weight = weight;
}

public Map<String, Node> getNodeMap() {
return nodeMap;
}

public void setNodeMap(Map<String, Node> nodeMap) {
this.nodeMap = nodeMap;
}

public double getAllocatableCpu() {
return allocatableCpu;
}

public void setAllocatableCpu(double allocatableCpu) {
this.allocatableCpu = allocatableCpu;
}

public double getAllocatableMemory() {
return allocatableMemory;
}

public void setAllocatableMemory(double allocatableMemory) {
this.allocatableMemory = allocatableMemory;
}

public int getForeverNodeNum() {
return foreverNodeNum;
}

public void setForeverNodeNum(int foreverNodeNum) {
this.foreverNodeNum = foreverNodeNum;
}

public int getScaleNodeNum() {
return scaleNodeNum;
}

public void setScaleNodeNum(int scaleNodeNum) {
this.scaleNodeNum = scaleNodeNum;
}

public double getRequestCpuSum() {
return requestCpuSum;
}

public void setRequestCpuSum(double requestCpuSum) {
this.requestCpuSum = requestCpuSum;
}

public double getRequestMemorySum() {
return requestMemorySum;
}

public void setRequestMemorySum(double requestMemorySum) {
this.requestMemorySum = requestMemorySum;
}

public double getReserveRequestCpuSum() {
return reserveRequestCpuSum.doubleValue();
}

public void addReserveRequestCpu(double reserveRequestCpu) {
this.reserveRequestCpuSum.addAndGet(reserveRequestCpu);
}

public double getReserveRequestMemorySum() {
return reserveRequestMemorySum.doubleValue();
}

public void addReserveRequestMemory(double reserveRequestMemory) {
this.reserveRequestMemorySum.addAndGet(reserveRequestMemory);
}

public double getSurplusCpuSum() {
return surplusCpuSum;
}

public void setSurplusCpuSum(double surplusCpuSum) {
this.surplusCpuSum = surplusCpuSum;
}

public double getSurplusMemorySum() {
return surplusMemorySum;
}

public void setSurplusMemorySum(double surplusMemorySum) {
this.surplusMemorySum = surplusMemorySum;
}

public double getConversionForeverNodeRequestCpuRatio() {
return conversionForeverNodeRequestCpuRatio;
}

public void setConversionForeverNodeRequestCpuRatio(double conversionForeverNodeRequestCpuRatio) {
this.conversionForeverNodeRequestCpuRatio = conversionForeverNodeRequestCpuRatio;
}

public double getConversionForeverNodeRequestMemoryRatio() {
return conversionForeverNodeRequestMemoryRatio;
}

public void setConversionForeverNodeRequestMemoryRatio(double conversionForeverNodeRequestMemoryRatio) {
this.conversionForeverNodeRequestMemoryRatio = conversionForeverNodeRequestMemoryRatio;
}

public double getForeverAllocatableCpuSum() {
return foreverAllocatableCpuSum;
}

public void setForeverAllocatableCpuSum(double foreverAllocatableCpuSum) {
this.foreverAllocatableCpuSum = foreverAllocatableCpuSum;
}

public double getForeverAllocatableMemorySum() {
return foreverAllocatableMemorySum;
}

public void setForeverAllocatableMemorySum(double foreverAllocatableMemorySum) {
this.foreverAllocatableMemorySum = foreverAllocatableMemorySum;
}

public double getRequestCpuRatio() {
return requestCpuRatio;
}


public void setRequestCpuRatio(double requestCpuRatio) {
this.requestCpuRatio = requestCpuRatio;
}


public double getRequestMemoryRatio() {
return requestMemoryRatio;
}


public void setRequestMemoryRatio(double requestMemoryRatio) {
this.requestMemoryRatio = requestMemoryRatio;
}

public int getPodCount() {
return podCount;
}

public void setPodCount(int podCount) {
this.podCount = podCount;
}

@Override
public String toString() {
return "ClusterInfo{" +
"clusterConfig=" + clusterConfig +
", autoscale=" + autoscale +
", weight=" + weight +
", nodeMap=" + nodeMap.size() +
", allocatableCpu=" + allocatableCpu +
", allocatableMemory=" + allocatableMemory +
", foreverNodeNum=" + foreverNodeNum +
", scaleNodeNum=" + scaleNodeNum +
", requestCpuSum=" + requestCpuSum +
", requestMemorySum=" + requestMemorySum +
", reserveRequestCpuSum=" + reserveRequestCpuSum +
", reserveRequestMemorySum=" + reserveRequestMemorySum +
", surplusCpuSum=" + surplusCpuSum +
", surplusMemorySum=" + surplusMemorySum +
", foreverAllocatableCpuSum=" + foreverAllocatableCpuSum +
", foreverAllocatableMemorySum=" + foreverAllocatableMemorySum +
", conversionForeverNodeRequestCpuRatio=" + conversionForeverNodeRequestCpuRatio +
", conversionForeverNodeRequestMemoryRatio=" + conversionForeverNodeRequestMemoryRatio +
'}';
}
}

+ 143
- 0
common/src/main/java/com/imitate/common/k8s/bean/ContainerCreateParams.java View File

@@ -0,0 +1,143 @@
package com.imitate.common.k8s.bean;

import com.alibaba.fastjson.JSONObject;
import com.google.common.base.Splitter;
import lombok.Builder;
import lombok.Data;
import lombok.ToString;
import org.apache.commons.lang3.StringUtils;

import java.util.List;

/**
* 创建容器的参数
*
* @author 威少
*/
@Data
@ToString
@Builder
public class ContainerCreateParams {
/**
* 超级权限
*/
private boolean privileged = false;

/**
* 镜像
*/
private String image;

/**
* 镜像名
*/
private String imageName;

/**
* 容器拉取策略
*/
private String imagePullPolicy = "IfNotPresent";

/**
* 内存限制
*/
private String memoryLimit;

/**
* CPU限制
*/
private String cpuLimit;

/**
* 内存request
*/
private String memoryRequest;

/**
* CPU request
*/
private String cpuRequest;

/**
* 磁盘限制
*/
private String diskLimit;

/**
* 容器类型
*/
private Type type;

/**
* 启动时间限制
*/
private Integer startTimeLimit;

/**
* 容器挂载点信息
*/
private List<ContainerMountParams> containerMountParams;

/**
* 启动命令
*/
private List<String> command;

/**
* prestop hook 执行的命令
*/
private List<String> prestopCommand;

/**
* poststart hook 执行的指令
*/
private List<String> postStartCommand;

/**
* 从json转换,格式形如
* {"image":"python3-ssh:v1.0","cpuLimit":2.0,"cpuRequest":0.1,"memoryLimit":"2048M",
* "memoryRequest":"10M","resourceLimit":"10000K","startTime":15,"type":"main"}
*/
public static ContainerCreateParams fromJSON(JSONObject containers) {
ContainerCreateParams containerCreateParams = ContainerCreateParams.builder()
.image(containers.getString("image"))
.cpuLimit(containers.getString("cpuLimit"))
.memoryLimit(containers.getString("memoryLimit"))
.memoryRequest(containers.getString("memoryRequest"))
.cpuRequest(containers.getString("cpuRequest"))
.diskLimit(containers.getString("resourceLimit"))
.startTimeLimit(containers.getInteger("startTime"))
.build();
if (StringUtils.isNotEmpty(containers.getString("type"))) {
containerCreateParams.setType(Type.valueOf(containers.getString("type")));
}
if (StringUtils.isNotEmpty(containers.getString("command"))) {
containerCreateParams.setCommand(Splitter.on(" ").splitToList(containers.getString("command")));
}
return containerCreateParams;
}

/**
* 容器类型
*/
public enum Type {
/**
* 主类别
*/
MAIN("main"),
/**
* 子类别
*/
SUB("sub");

private String value;

Type(String value) {
this.value = value;
}

public String getValue() {
return value;
}
}
}

+ 28
- 0
common/src/main/java/com/imitate/common/k8s/bean/ContainerMountParams.java View File

@@ -0,0 +1,28 @@
package com.imitate.common.k8s.bean;

import lombok.Builder;
import lombok.Data;
import lombok.ToString;

/**
* 容器挂载参数
*
* @author 威少
*/
@Data
@ToString
@Builder
public class ContainerMountParams {
/**
* 数据卷名称
*/
private String name;
/**
* 挂载目标位置
*/
private String path;
/**
* 是否只读
*/
private Boolean readonly;
}

+ 66
- 0
common/src/main/java/com/imitate/common/k8s/bean/CreatePodResult.java View File

@@ -0,0 +1,66 @@
package com.imitate.common.k8s.bean;

import io.fabric8.kubernetes.api.model.Pod;

public class CreatePodResult {
private Boolean success = Boolean.FALSE;

private Integer status = CREATE_POD_STATUS_DEF;

public static final int CREATE_POD_STATUS_DEF = 0;
public static final int CREATE_POD_STATUS_FAIL_PULL_IMAGE = 1;
public static final int CREATE_POD_STATUS_FAIL_DELETE_NOW = 2;

private Pod pod;

private String nodeName;

/**
* 创建开始时间
*/
private Long startTime;

public CreatePodResult() {
}

public CreatePodResult(Long startTime) {
this.startTime = startTime;
}

public Pod getPod() {
return pod;
}

public void setPod(Pod pod) {
this.pod = pod;
}

public long getMillisecondCost() {
return System.currentTimeMillis() - startTime;
}

public Boolean getSuccess() {
return success;
}

public void setSuccess(Boolean success) {
this.success = success;
}

public Integer getStatus() {
return status;
}

public void setStatus(Integer status) {
this.status = status;
}

public String getNodeName() {
return nodeName;
}

public void setNodeName(String nodeName) {
this.nodeName = nodeName;
}
}

+ 38
- 0
common/src/main/java/com/imitate/common/k8s/bean/DeploymentCreateParams.java View File

@@ -0,0 +1,38 @@
package com.imitate.common.k8s.bean;

import lombok.Builder;
import lombok.Data;
import lombok.ToString;

import java.util.Map;

/**
* 创建Deployment的参数
*
* @author 威少
*/
@Data
@ToString
@Builder
public class DeploymentCreateParams {
/**
* Deployment的名字
*/
private String name;

/**
* 标签
*/
private Map<String, String> labels;

/**
* pod副本数量
*/
private Integer replicas;

/**
* Pod Create Params
*/
private PodCreateParams podCreateParams;

}

+ 122
- 0
common/src/main/java/com/imitate/common/k8s/bean/ExecResultCase.java View File

@@ -0,0 +1,122 @@
package com.imitate.common.k8s.bean;

/**
* Created by weishao on 2017/4/12.
*/
public class ExecResultCase {
private String caseId;
private String input;
private String output;
private String expectedOutput;
private String passed;
private String type = "0"; // 默认为文本类型

private Long testSetTime;
private Long testSetMem;

public String getCaseId() {
return caseId;
}

public String getInput() {
return input;
}

public String getOutput() {
return output;
}

public String getExpectedOutput() {
return expectedOutput;
}

public String getPassed() {
return passed;
}

public void setCaseId(String caseId) {
this.caseId = caseId;
}

public void setInput(String input) {
this.input = input;
}

public void setOutput(String output) {
this.output = output;
}

public void setExpectedOutput(String expectedOutput) {
this.expectedOutput = expectedOutput;
}

public void setPassed(String passed) {
this.passed = passed;
}

public Long getTestSetTime() {
return testSetTime;
}

public void setTestSetTime(Long testSetTime) {
this.testSetTime = testSetTime;
}

public Long getTestSetMem() {
return testSetMem;
}

public void setTestSetMem(Long testSetMem) {
this.testSetMem = testSetMem;
}

public String getType() {
return type;
}

public void setType(String type) {
this.type = type;
}

public ExecResultCase() {
}

public ExecResultCase(String caseId, String output, String passed) {
this.caseId = caseId;
this.output = output;
this.passed = passed;
}

public ExecResultCase(String caseId, String output, String passed, String type) {
this.caseId = caseId;
this.output = output;
this.passed = passed;
this.type = type;
}

public enum Status {
/**
* 测试用例通过
*/
PASS("1"),
/**
* 测试用例不通过
*/
FAIL("0");

private String value;

public String getValue() {
return value;
}

public void setValue(String value) {
this.value = value;
}

Status(String value) {
this.value = value;
}
}

}

+ 46
- 0
common/src/main/java/com/imitate/common/k8s/bean/HPACreateParams.java View File

@@ -0,0 +1,46 @@
package com.imitate.common.k8s.bean;

import lombok.Builder;
import lombok.Data;
import lombok.ToString;

/**
* 创建HPA的参数
*
* @author 威少
*/
@Data
@ToString
@Builder
public class HPACreateParams {
/**
* hpa的名字
*/
private String name;

/**
* deployment的名字
*/
private String deploymentName;

/**
* 最小Pod数
*/
private Integer minReplicas;

/**
* 最大Pod数
*/
private Integer maxReplicas;

/**
* 期望的CPU利用率
*/
private Integer desireCpuPercent;

/**
* 期望的内存利用率
*/
private Integer desireMemoryPercent;

}

+ 77
- 0
common/src/main/java/com/imitate/common/k8s/bean/NodeEvaErrorInfo.java View File

@@ -0,0 +1,77 @@
package com.imitate.common.k8s.bean;

/**
* 节点评测错误信息
*/
public class NodeEvaErrorInfo {

private String nodeName;

private Integer downloadErrorNum;

private Integer createPodErrorNum;

private Integer runErrorNum;

private Integer evaCount;

public boolean isErrorNode(Integer errorNum, Double errorRatio) {
return (createPodErrorNum > errorNum && ((double) createPodErrorNum / evaCount) > errorRatio)
|| (runErrorNum > errorNum && ((double) runErrorNum / evaCount) > errorRatio);
}

public boolean isRunErrorNode(Integer errorNum, Double errorRatio) {
return runErrorNum > errorNum && ((double) runErrorNum / evaCount) > errorRatio;
}

public String getNodeName() {
return nodeName;
}

public void setNodeName(String nodeName) {
this.nodeName = nodeName;
}

public Integer getDownloadErrorNum() {
return downloadErrorNum;
}

public void setDownloadErrorNum(Integer downloadErrorNum) {
this.downloadErrorNum = downloadErrorNum;
}

public Integer getCreatePodErrorNum() {
return createPodErrorNum;
}

public void setCreatePodErrorNum(Integer createPodErrorNum) {
this.createPodErrorNum = createPodErrorNum;
}

public Integer getRunErrorNum() {
return runErrorNum;
}

public void setRunErrorNum(Integer runErrorNum) {
this.runErrorNum = runErrorNum;
}

public Integer getEvaCount() {
return evaCount;
}

public void setEvaCount(Integer evaCount) {
this.evaCount = evaCount;
}

@Override
public String toString() {
return "NodeEvaErrorInfo{" +
"nodeName='" + nodeName + '\'' +
", downloadErrorNum=" + downloadErrorNum +
", createPodErrorNum=" + createPodErrorNum +
", runErrorNum=" + runErrorNum +
", evaCount=" + evaCount +
'}';
}
}

+ 35
- 0
common/src/main/java/com/imitate/common/k8s/bean/NodeQueryParam.java View File

@@ -0,0 +1,35 @@
package com.imitate.common.k8s.bean;

import java.util.Map;

public class NodeQueryParam {

private String cluster;
private String name;
private Map<String, String> labels;

public String getCluster() {
return cluster;
}

public void setCluster(String cluster) {
this.cluster = cluster;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Map<String, String> getLabels() {
return labels;
}

public void setLabels(Map<String, String> labels) {
this.labels = labels;
}

}

+ 58
- 0
common/src/main/java/com/imitate/common/k8s/bean/NodeRes.java View File

@@ -0,0 +1,58 @@
package com.imitate.common.k8s.bean;

import com.google.common.util.concurrent.AtomicDouble;

public class NodeRes {

private String nodeName;
private Double requestCpu;
private Double allocatableCpu;

private Double requestCpuRate;

/**
* 调度时,使得pod尽量不调度到此节点的cpu量
*/
private AtomicDouble unAffinityCpu = new AtomicDouble(0.0);

public String getNodeName() {
return nodeName;
}

public void setNodeName(String nodeName) {
this.nodeName = nodeName;
}

public Double getRequestCpu() {
return requestCpu;
}

public void setRequestCpu(Double requestCpu) {
this.requestCpu = requestCpu;
}

public Double getAllocatableCpu() {
return allocatableCpu;
}

public void setAllocatableCpu(Double allocatableCpu) {
this.allocatableCpu = allocatableCpu;
}

public Double getRequestCpuRate() {
return requestCpuRate;
}

public void setRequestCpuRate(Double requestCpuRate) {
this.requestCpuRate = requestCpuRate;
}

public double getUnAffinityCpu() {
return unAffinityCpu.doubleValue();
}

public void addUnAffinityCpu(double unAffinityCpu) {
this.unAffinityCpu.addAndGet(unAffinityCpu);
}

}

+ 76
- 0
common/src/main/java/com/imitate/common/k8s/bean/NodeResStat.java View File

@@ -0,0 +1,76 @@
package com.imitate.common.k8s.bean;

/**
* 节点资源统计,数据来源于 run_pod 表。
*
* @author mumu
*
*/
public class NodeResStat {

private String cluster;
private String nodeIp;
private Integer podNum;

private Double cpuRequest;
private Double cpuLimit;

private Double memoryRequest;
private Double momoryLimit;

public String getCluster() {
return cluster;
}

public void setCluster(String cluster) {
this.cluster = cluster;
}

public String getNodeIp() {
return nodeIp;
}

public void setNodeIp(String nodeIp) {
this.nodeIp = nodeIp;
}

public Double getCpuRequest() {
return cpuRequest;
}

public void setCpuRequest(Double cpuRequest) {
this.cpuRequest = cpuRequest;
}

public Double getCpuLimit() {
return cpuLimit;
}

public void setCpuLimit(Double cpuLimit) {
this.cpuLimit = cpuLimit;
}

public Double getMemoryRequest() {
return memoryRequest;
}

public void setMemoryRequest(Double memoryRequest) {
this.memoryRequest = memoryRequest;
}

public Double getMomoryLimit() {
return momoryLimit;
}

public void setMomoryLimit(Double momoryLimit) {
this.momoryLimit = momoryLimit;
}

public Integer getPodNum() {
return podNum;
}

public void setPodNum(Integer podNum) {
this.podNum = podNum;
}
}

+ 165
- 0
common/src/main/java/com/imitate/common/k8s/bean/OjEvaResult.java View File

@@ -0,0 +1,165 @@
package com.imitate.common.k8s.bean;

import java.util.List;

/**
* oj评测结果
*/
public class OjEvaResult {

private String tpiID;

private String status;

private String execMode;
public final static String OJ_EVA_EXEC_MODE_DEBUG = "debug";
public final static String OJ_EVA_EXEC_MODE_ALL = "submit";

/**
* 代码,返回上层,避免查数据库
*/
private String codeFileContent;
private String executeMem;
private String executeTime;
private Integer failCaseNum;
private String outPut;
private ExecResultCase testCase;
private List<ExecResultCase> execResultCases;
private TimeCost timeCost;
private String sec_key;
private String extras;

// 新增编译和执行返回 0代表编译/运行失败 1 代表编译/运行成功
private String compileSuccess;
private String executeSuccess;

public OjEvaResult(String tpiID, String status, String outPut, ExecResultCase testCase, String sec_key, String extras) {
this.tpiID = tpiID;
this.status = status;
this.outPut = outPut;
this.testCase = testCase;
this.sec_key = sec_key;
this.extras = extras;
}

public String getSec_key() {
return sec_key;
}

public void setSec_key(String sec_key) {
this.sec_key = sec_key;
}

public String getTpiID() {
return tpiID;
}

public void setTpiID(String tpiID) {
this.tpiID = tpiID;
}

public String getStatus() {
return status;
}

public void setStatus(String status) {
this.status = status;
}

public String getOutPut() {
return outPut;
}

public void setOutPut(String outPut) {
this.outPut = outPut;
}


public ExecResultCase getTestCase() {
return testCase;
}

public void setTestCase(ExecResultCase testCase) {
this.testCase = testCase;
}

public String getExecMode() {
return execMode;
}

public void setExecMode(String execMode) {
this.execMode = execMode;
}

public Integer getFailCaseNum() {
return failCaseNum;
}

public void setFailCaseNum(Integer failCaseNum) {
this.failCaseNum = failCaseNum;
}

public TimeCost getTimeCost() {
return timeCost;
}

public void setTimeCost(TimeCost timeCost) {
this.timeCost = timeCost;
}

public String getExecuteMem() {
return executeMem;
}

public void setExecuteMem(String executeMem) {
this.executeMem = executeMem;
}

public String getExecuteTime() {
return executeTime;
}

public void setExecuteTime(String executeTime) {
this.executeTime = executeTime;
}

public String getCodeFileContent() {
return codeFileContent;
}

public void setCodeFileContent(String codeFileContent) {
this.codeFileContent = codeFileContent;
}

public List<ExecResultCase> getCases() {
return execResultCases;
}

public void setCases(List<ExecResultCase> execResultCases) {
this.execResultCases = execResultCases;
}

public String getExtras() {
return extras;
}

public void setExtras(String extras) {
this.extras = extras;
}

public String getCompileSuccess() {
return compileSuccess;
}

public void setCompileSuccess(String compileSuccess) {
this.compileSuccess = compileSuccess;
}

public String getExecuteSuccess() {
return executeSuccess;
}

public void setExecuteSuccess(String executeSuccess) {
this.executeSuccess = executeSuccess;
}
}

+ 41
- 0
common/src/main/java/com/imitate/common/k8s/bean/PodCreateParams.java View File

@@ -0,0 +1,41 @@
package com.imitate.common.k8s.bean;

import io.fabric8.kubernetes.api.model.Container;
import io.fabric8.kubernetes.api.model.Volume;
import lombok.Data;
import lombok.ToString;

import java.util.List;
import java.util.Map;

/**
* 创建Pod的参数
*
* @author 威少
*/
@Data
@ToString
public class PodCreateParams {
/**
* 标签
*/
private Map<String, String> labels;
/**
* 名称
*/
private String name;
/**
* 容器
*/
private List<Container> containerList;
/**
* 节点选择器
*/
private Map<String, String> nodeSelector;
/**
* mount
*/
private Volume[] volumes;


}

+ 123
- 0
common/src/main/java/com/imitate/common/k8s/bean/PodCreateStrategy.java View File

@@ -0,0 +1,123 @@
package com.imitate.common.k8s.bean;


import com.imitate.common.sys.constant.SysConfigCsts;

import java.util.List;

public class PodCreateStrategy {

private Integer timeLimit = MAX_CREATE_POD_TIME_LIMIT;

public static final int MAX_CREATE_POD_TIME_LIMIT = 15;
/**
* 普通pod能否分配到神龙节点
*/
private Boolean normalPodCanShenlong;
/**
* 普通pod能否分配到GPU节点
*/
private Boolean normalPodCanGpu;

/**
* 普通pod能否分配到oj节点
*/
private Boolean normalPodCanOj;

private List<String> noSchedulableNodes;

private List<String> noSchedulableShenlongNodes;
private List<String> noSchedulableGpuNodes;

/**
* pod不可调度的权重
*/
private Integer podNoSchedulableWeight;

private Integer autoscaleNodeWeight = SysConfigCsts.AUTOSCALE_NODE_WEIGHT_DEF;

public Integer getTimeLimit() {
return timeLimit;
}

public PodCreateStrategy setTimeLimit(Integer timeLimit) {
this.timeLimit = timeLimit;
return this;
}

public Boolean getNormalPodCanShenlong() {
return normalPodCanShenlong;
}

public PodCreateStrategy setNormalPodCanShenlong(Boolean normalPodCanShenlong) {
this.normalPodCanShenlong = normalPodCanShenlong;
return this;
}
public Boolean getNormalPodCanGpu() {
return normalPodCanGpu;
}

public PodCreateStrategy setNormalPodCanGpu(Boolean normalPodCanGpu) {
this.normalPodCanGpu = normalPodCanGpu;
return this;
}

public Boolean getNormalPodCanOj() {
return normalPodCanOj;
}

public PodCreateStrategy setNormalPodCanOj(Boolean normalPodCanOj) {
this.normalPodCanOj = normalPodCanOj;
return this;
}

public List<String> getNoSchedulableNodes() {
return noSchedulableNodes;
}

public PodCreateStrategy setNoSchedulableNodes(List<String> noSchedulableNodes) {
this.noSchedulableNodes = noSchedulableNodes;
return this;
}

public List<String> getNoSchedulableShenlongNodes() {
return noSchedulableShenlongNodes;
}

public PodCreateStrategy setNoSchedulableShenlongNodes(List<String> noSchedulableShenlongNodes) {
this.noSchedulableShenlongNodes = noSchedulableShenlongNodes;
return this;
}

public List<String> getNoSchedulableGpuNodes() {
return noSchedulableGpuNodes;
}

public PodCreateStrategy setNoSchedulableGpuNodes(List<String> noSchedulableGpuNodes) {
this.noSchedulableGpuNodes = noSchedulableGpuNodes;
return this;
}

public Integer getPodNoSchedulableWeight() {
return podNoSchedulableWeight;
}

public PodCreateStrategy setPodNoSchedulableWeight(Integer podNoSchedulableWeight) {
this.podNoSchedulableWeight = podNoSchedulableWeight;
return this;
}

public Integer getAutoscaleNodeWeight() {
return autoscaleNodeWeight;
}

public PodCreateStrategy setAutoscaleNodeWeight(Integer autoscaleNodeWeight) {
this.autoscaleNodeWeight = autoscaleNodeWeight;
return this;
}


}

+ 281
- 0
common/src/main/java/com/imitate/common/k8s/bean/PodQueryParam.java View File

@@ -0,0 +1,281 @@
package com.imitate.common.k8s.bean;


import java.time.LocalDateTime;

public class PodQueryParam {
private Long id;
private String cluster;
private String name;
private String tpiID;

private String uid;

private LocalDateTime requestTime;
private LocalDateTime minRequestTime;
private LocalDateTime maxRequestTime;
private String secKey;

private String nodeName;
private String nodeIp;

private String downloadStatus;
private String createPodStatus;
private String compileStatus;
private String runStatus;
private String status;

private String sortField;
private String sortDirection;

private Integer pageNum = 1;
private Integer pageSize = 10;

private String statDate;
private Double pull;
private Double createPod;

private String imageName;

private Double cpuLimit;

private Integer memoryLimit;

private Double cpuRequest;

private Integer memoryRequest;

private Double errorRatio;

public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public String getCluster() {
return cluster;
}

public void setCluster(String cluster) {
this.cluster = cluster;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getTpiID() {
return tpiID;
}

public void setTpiID(String tpiID) {
this.tpiID = tpiID;
}

public String getUid() {
return uid;
}

public void setUid(String uid) {
this.uid = uid;
}

public LocalDateTime getRequestTime() {
return requestTime;
}

public void setRequestTime(LocalDateTime requestTime) {
this.requestTime = requestTime;
}

public LocalDateTime getMinRequestTime() {
return minRequestTime;
}

public void setMinRequestTime(LocalDateTime minRequestTime) {
this.minRequestTime = minRequestTime;
}

public LocalDateTime getMaxRequestTime() {
return maxRequestTime;
}

public void setMaxRequestTime(LocalDateTime maxRequestTime) {
this.maxRequestTime = maxRequestTime;
}

public String getSecKey() {
return secKey;
}

public void setSecKey(String secKey) {
this.secKey = secKey;
}

public String getNodeName() {
return nodeName;
}

public void setNodeName(String nodeName) {
this.nodeName = nodeName;
}

public String getNodeIp() {
return nodeIp;
}

public void setNodeIp(String nodeIp) {
this.nodeIp = nodeIp;
}

public String getDownloadStatus() {
return downloadStatus;
}

public void setDownloadStatus(String downloadStatus) {
this.downloadStatus = downloadStatus;
}

public String getCreatePodStatus() {
return createPodStatus;
}

public void setCreatePodStatus(String createPodStatus) {
this.createPodStatus = createPodStatus;
}

public String getCompileStatus() {
return compileStatus;
}

public void setCompileStatus(String compileStatus) {
this.compileStatus = compileStatus;
}

public String getRunStatus() {
return runStatus;
}

public void setRunStatus(String runStatus) {
this.runStatus = runStatus;
}

public String getStatus() {
return status;
}

public void setStatus(String status) {
this.status = status;
}

public String getSortField() {
return sortField;
}

public void setSortField(String sortField) {
this.sortField = sortField;
}

public String getSortDirection() {
return sortDirection;
}

public void setSortDirection(String sortDirection) {
this.sortDirection = sortDirection;
}

public Integer getPageNum() {
return pageNum;
}

public void setPageNum(Integer pageNum) {
this.pageNum = pageNum;
}

public Integer getPageSize() {
return pageSize;
}

public void setPageSize(Integer pageSize) {
this.pageSize = pageSize;
}

public String getStatDate() {
return statDate;
}

public void setStatDate(String statDate) {
this.statDate = statDate;
}

public Double getPull() {
return pull;
}

public void setPull(Double pull) {
this.pull = pull;
}

public Double getCreatePod() {
return createPod;
}

public void setCreatePod(Double createPod) {
this.createPod = createPod;
}

public String getImageName() {
return imageName;
}

public void setImageName(String imageName) {
this.imageName = imageName;
}

public Double getCpuLimit() {
return cpuLimit;
}

public void setCpuLimit(Double cpuLimit) {
this.cpuLimit = cpuLimit;
}

public Integer getMemoryLimit() {
return memoryLimit;
}

public void setMemoryLimit(Integer memoryLimit) {
this.memoryLimit = memoryLimit;
}

public Double getCpuRequest() {
return cpuRequest;
}

public void setCpuRequest(Double cpuRequest) {
this.cpuRequest = cpuRequest;
}

public Integer getMemoryRequest() {
return memoryRequest;
}

public void setMemoryRequest(Integer memoryRequest) {
this.memoryRequest = memoryRequest;
}

public Double getErrorRatio() {
return errorRatio;
}

public void setErrorRatio(Double errorRatio) {
this.errorRatio = errorRatio;
}
}

+ 127
- 0
common/src/main/java/com/imitate/common/k8s/bean/RunPodQueryParam.java View File

@@ -0,0 +1,127 @@
package com.imitate.common.k8s.bean;

import java.time.LocalDateTime;
import java.util.List;

public class RunPodQueryParam {

private String cluster;

private String name;

private List<String> names;

private LocalDateTime expireTime;

private Long priority;

private LocalDateTime createTime;

private String createBy;

private String sshPort;

private String svcPort;

private Integer capacityThreshold;

private String nodeName;

private String nodeIp;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public LocalDateTime getExpireTime() {
return expireTime;
}

public void setExpireTime(LocalDateTime expireTime) {
this.expireTime = expireTime;
}

public LocalDateTime getCreateTime() {
return createTime;
}

public void setCreateTime(LocalDateTime createTime) {
this.createTime = createTime;
}

public Long getPriority() {
return priority;
}

public void setPriority(Long priority) {
this.priority = priority;
}

public String getCreateBy() {
return createBy;
}

public void setCreateBy(String createBy) {
this.createBy = createBy;
}

public Integer getCapacityThreshold() {
return capacityThreshold;
}

public void setCapacityThreshold(Integer capacityThreshold) {
this.capacityThreshold = capacityThreshold;
}

public List<String> getNames() {
return names;
}

public void setNames(List<String> names) {
this.names = names;
}

public String getSshPort() {
return sshPort;
}

public void setSshPort(String sshPort) {
this.sshPort = sshPort;
}

public String getSvcPort() {
return svcPort;
}

public void setSvcPort(String svcPort) {
this.svcPort = svcPort;
}

public String getNodeIp() {
return nodeIp;
}

public void setNodeIp(String nodeIp) {
this.nodeIp = nodeIp;
}

public String getCluster() {
return cluster;
}

public void setCluster(String cluster) {
this.cluster = cluster;
}

public String getNodeName() {
return nodeName;
}

public void setNodeName(String nodeName) {
this.nodeName = nodeName;
}
}

+ 42
- 0
common/src/main/java/com/imitate/common/k8s/bean/ServiceCreateParams.java View File

@@ -0,0 +1,42 @@
package com.imitate.common.k8s.bean;

import lombok.Data;
import lombok.ToString;

import java.util.Map;

/**
* kubernetes service创建参数
*
* @author 威少
*/
@Data
@ToString
public class ServiceCreateParams {
/**
* 标签
*/
private Map<String, String> labels;
/**
* 名称
*/
private String name;
/**
* 命名空间
*/
private String namespace;
/**
* 选择器
*/
private Map<String, String> selector;

/**
* service对外暴露端口
*/
private Integer nodePort;

/**
* 容器内部端口
*/
private Integer targetPort;
}

+ 81
- 0
common/src/main/java/com/imitate/common/k8s/bean/TimeCost.java View File

@@ -0,0 +1,81 @@
package com.imitate.common.k8s.bean;

import java.time.LocalDateTime;

/**
* 评测各阶段时间记录
*/
public class TimeCost {

private LocalDateTime evaluateStartTime;

private LocalDateTime evaluateEndTime;

private String pull;

private String createPod;

private String execute;

private String evaluateAllTime;

public LocalDateTime getEvaluateStartTime() {
return evaluateStartTime;
}

public void setEvaluateStartTime(LocalDateTime evaluateStartTime) {
this.evaluateStartTime = evaluateStartTime;
}

public LocalDateTime getEvaluateEndTime() {
return evaluateEndTime;
}

public void setEvaluateEndTime(LocalDateTime evaluateEndTime) {
this.evaluateEndTime = evaluateEndTime;
}

public String getPull() {
return pull;
}

public void setPull(String pull) {
this.pull = pull;
}

public String getCreatePod() {
return createPod;
}

public void setCreatePod(String createPod) {
this.createPod = createPod;
}

public String getExecute() {
return execute;
}

public void setExecute(String execute) {
this.execute = execute;
}

public String getEvaluateAllTime() {
return evaluateAllTime;
}

public void setEvaluateAllTime(String evaluateAllTime) {
this.evaluateAllTime = evaluateAllTime;
}

@Override
public String toString() {
return "TimeCost{" +
"evaluateStartTime=" + evaluateStartTime +
", evaluateEndTime=" + evaluateEndTime +
", pull='" + pull + '\'' +
", createPod='" + createPod + '\'' +
", execute='" + execute + '\'' +
", evaluateAllTime='" + evaluateAllTime + '\'' +
'}';
}
}

+ 8
- 0
common/src/main/java/com/imitate/common/k8s/constant/BridgeNodeCsts.java View File

@@ -0,0 +1,8 @@
package com.imitate.common.k8s.constant;

public interface BridgeNodeCsts {

String NODE_LABEL_TYPE = "type";
String NODE_LABEL_TYPE_OTHERS = "others";
String NODE_LABEL_TYPE_UNDER_PRESSURE = "under-pressure";
}

+ 8
- 0
common/src/main/java/com/imitate/common/k8s/constant/BridgePodCsts.java View File

@@ -0,0 +1,8 @@
package com.imitate.common.k8s.constant;

public interface BridgePodCsts {

String STATUS_BEGIN = "0";
String STATUS_END = "1";

}

+ 12
- 0
common/src/main/java/com/imitate/common/k8s/constant/PlatformConfigCsts.java View File

@@ -0,0 +1,12 @@
package com.imitate.common.k8s.constant;

public interface PlatformConfigCsts {

String PLATFORM_JAVA = "java";

String PLATFORM_C = "c";

String PLATFORM_CPP = "cpp";

String PLATFORM_PYTHON = "python";
}

+ 46
- 0
common/src/main/java/com/imitate/common/k8s/mapper/BridgePodMapper.java View File

@@ -0,0 +1,46 @@
package com.imitate.common.k8s.mapper;



import com.imitate.common.k8s.pojo.BridgePod;
import com.imitate.common.k8s.bean.NodeEvaErrorInfo;
import com.imitate.common.k8s.bean.PodQueryParam;
import com.imitate.common.k8s.pojo.EvaDayStat;
import com.imitate.common.util.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;

import java.time.LocalDateTime;
import java.util.List;

@Repository
@Mapper
public interface BridgePodMapper extends BaseMapper<BridgePod> {

@Override
int insert(BridgePod record);

@Override
int insertSelective(BridgePod record);

@Override
int updateByPrimaryKeySelective(BridgePod record);

@Override
int updateByPrimaryKey(BridgePod record);
List<BridgePod> selectBridgePod(PodQueryParam param);
void updateUpdateDeleteTime(BridgePod param);

void deleteByRequestTime(LocalDateTime deleteTime);

/**
*
* @param requestTime 整数,形式为yyyyMMdd
* @return
*/
EvaDayStat countEvaDayStat(Integer requestTime);

List<NodeEvaErrorInfo> selectNodeEvaErrorInfos(LocalDateTime requestTime);
}

+ 14
- 0
common/src/main/java/com/imitate/common/k8s/mapper/ErrorPodInfoMapper.java View File

@@ -0,0 +1,14 @@
package com.imitate.common.k8s.mapper;

import com.imitate.common.k8s.pojo.ErrorPodInfo;
import com.imitate.common.util.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;


@Repository
@Mapper
public interface ErrorPodInfoMapper extends BaseMapper<ErrorPodInfo> {
@Override
int insert(ErrorPodInfo errorPodInfo);
}

+ 21
- 0
common/src/main/java/com/imitate/common/k8s/mapper/EvaDayStatMapper.java View File

@@ -0,0 +1,21 @@
package com.imitate.common.k8s.mapper;


import com.imitate.common.k8s.pojo.EvaDayStat;
import com.imitate.common.util.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;

@Mapper
@Repository
public interface EvaDayStatMapper extends BaseMapper<EvaDayStat> {


@Override
int insert(EvaDayStat record);

@Override
int insertSelective(EvaDayStat record);


}

+ 16
- 0
common/src/main/java/com/imitate/common/k8s/mapper/OjEvaDayStatMapper.java View File

@@ -0,0 +1,16 @@
package com.imitate.common.k8s.mapper;


import com.imitate.common.k8s.pojo.OjEvaDayStat;
import com.imitate.common.util.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;


@Repository
@Mapper
public interface OjEvaDayStatMapper extends BaseMapper<OjEvaDayStat> {

@Override
int insertSelective(OjEvaDayStat record);
}

+ 22
- 0
common/src/main/java/com/imitate/common/k8s/mapper/PlatformConfigMapper.java View File

@@ -0,0 +1,22 @@
package com.imitate.common.k8s.mapper;


import com.imitate.common.k8s.pojo.PlatformConfig;
import com.imitate.common.util.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
@Mapper
public interface PlatformConfigMapper extends BaseMapper<PlatformConfig> {

@Override
int insertSelective(PlatformConfig record);

@Override
int updateByPrimaryKeySelective(PlatformConfig record);

List<PlatformConfig> selectAllConfig();
}

+ 55
- 0
common/src/main/java/com/imitate/common/k8s/mapper/RunPodMapper.java View File

@@ -0,0 +1,55 @@
package com.imitate.common.k8s.mapper;


import com.imitate.common.k8s.bean.NodeResStat;
import com.imitate.common.k8s.pojo.RunPod;
import com.imitate.common.k8s.bean.RunPodQueryParam;
import com.imitate.common.util.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;

import java.time.LocalDateTime;
import java.util.List;

@Repository
@Mapper
public interface RunPodMapper extends BaseMapper<RunPod> {

int deleteByName(String name);
int deleteByNameExpired(@Param("name") String name, @Param("expireTime") LocalDateTime expireTime);

@Override
int insert(RunPod record);

@Override
int insertSelective(RunPod record);


@Override
int updateByPrimaryKeySelective(RunPod record);

void updateByNameSelective(RunPod runPod);
int delayRunPodExpireTime(RunPod runPod);

@Override
int updateByPrimaryKey(RunPod record);

RunPod selectRunPodForUpdate(String podName);

List<RunPod> selectRunPods(RunPodQueryParam param);

int updatePortByName(RunPodQueryParam param);

RunPod selectByName(String podName);

RunPod selectSshRunPodByTpiID(String tpiID);

List<NodeResStat> statNodeRes(RunPodQueryParam param);

List<String> podNumStatGroupByNodeIp(String cluster);

void updateExpireTimeByNodeIp(RunPodQueryParam runPodQueryParam);
}

+ 16
- 0
common/src/main/java/com/imitate/common/k8s/mapper/SecurityContextConfigMapper.java View File

@@ -0,0 +1,16 @@
package com.imitate.common.k8s.mapper;


import com.imitate.common.k8s.pojo.SecurityContextConfig;
import com.imitate.common.util.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
@Mapper
public interface SecurityContextConfigMapper extends BaseMapper<SecurityContextConfig> {

List<SecurityContextConfig> selectAll();
}

+ 31
- 0
common/src/main/java/com/imitate/common/k8s/mapper/WindowsInfoMapper.java View File

@@ -0,0 +1,31 @@
package com.imitate.common.k8s.mapper;


import com.imitate.common.k8s.pojo.WindowsInfo;
import com.imitate.common.util.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
@Mapper
public interface WindowsInfoMapper extends BaseMapper<WindowsInfo> {

int deleteByUniqId(String uniqId);

@Override
int insertSelective(WindowsInfo record);

WindowsInfo selectByUniqId(String uniqId);

List<WindowsInfo> selectByTpiId(String tpiId);

List<WindowsInfo> selectByUserId(String userID);

int updateByUniqIdSelective(WindowsInfo windowsInfo);

List<String> selectUniqIdByAutoReleaseTime(WindowsInfo windowsInfo);

List<WindowsInfo> selectNotForwardEntryHost();
}

+ 173
- 0
common/src/main/java/com/imitate/common/k8s/mgr/ClusterManager.java View File

@@ -0,0 +1,173 @@
package com.imitate.common.k8s.mgr;


import com.imitate.common.k8s.bean.BridgeContainer;
import com.imitate.common.k8s.bean.ClusterInfo;
import com.imitate.common.k8s.bean.NodeQueryParam;
import com.imitate.common.k8s.bean.NodeResStat;
import com.imitate.common.k8s.service.K8sService;
import com.imitate.common.k8s.service.RunPodService;
import com.imitate.common.k8s.util.K8sUtils;
import com.imitate.common.sys.pojo.ClusterConfig;
import com.imitate.common.sys.service.ClusterConfigService;
import com.imitate.common.sys.service.SysConfigService;
import io.fabric8.kubernetes.api.model.Node;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
* 集群管理
*/
@Component
public class ClusterManager {

private Logger logger = LoggerFactory.getLogger(getClass());

// Map<cluster, ClusterInfo>
private volatile Map<String, ClusterInfo> clusterMap = new HashMap<>();

@Autowired
private K8sService k8sService;

@Autowired
private ClusterConfigService clusterConfigService;

@Autowired
private RunPodService runPodService;
@Autowired
private SysConfigService sysConfigService;

// ClusterInfo 相关 begin ...
// 刷新集群节点
public void refreshClusters() {
List<ClusterConfig> ccList = clusterConfigService.getAvailableClusterConfigs();
List<NodeResStat> nodeResStats = runPodService.statNodeRes();
Map<String, ClusterInfo> tmpMap = new HashMap<>();
for (ClusterConfig cc : ccList) {
try {
ClusterInfo cInfo = refreshCluster(cc, nodeResStats);
tmpMap.put(cc.getName(), cInfo);
} catch (Exception e) {
logger.error("刷新单个集群节点信息失败, cluster: " + cc.getName(), e);
}
}

clusterMap = tmpMap;
}

private ClusterInfo refreshCluster(ClusterConfig cc, List<NodeResStat> nodeResStats) {
String cluster = cc.getName();
NodeQueryParam param = new NodeQueryParam();
param.setCluster(cluster);
List<Node> nodesTemp = k8sService.getNodes(param);
List<Node> nodes = new ArrayList<>();
for (Node node : nodesTemp) {
if (K8sUtils.isReadyStatus(node)) {
nodes.add(node);
}
}

ClusterInfo cInfo = new ClusterInfo();
cInfo.setClusterConfig(cc);
cInfo.setWeight(cc.getWeight());
cInfo.setAutoscale(cc.getAutoScale());
cInfo.cal(cluster, nodes, nodeResStats);

logger.debug("refreshCluster cInfo: {}", cInfo);
return cInfo;
}

public Boolean canSupportedImageName(String cluster, String imageName) {
ClusterInfo cInfo = clusterMap.get(cluster);
if (cInfo != null) {
if (cInfo.getClusterConfig().supportImage(imageName)
&& !cInfo.getClusterConfig().notSupportImage(imageName)) {
return Boolean.TRUE;
}
}
return Boolean.FALSE;
}

/**
* 获取支持镜像的集群
*
* @param imageName
* @return
*/
public List<ClusterInfo> getSupportedClusterInfo(String imageName) {
List<ClusterInfo> list = new ArrayList<>();
for (Map.Entry<String, ClusterInfo> entry : clusterMap.entrySet()) {
ClusterInfo cInfo = entry.getValue();
// 检查白名单
if (!cInfo.getClusterConfig().supportImage(imageName)) {
continue;
}
// 过滤黑名单
if (cInfo.getClusterConfig().notSupportImage(imageName)) {
continue;
}
list.add(cInfo);
}

return list;
}

public Map<String, ClusterInfo> getClusterInfo() {
return clusterMap;
}

public void clusterReserveRequestRes(String cluster, BridgeContainer bc) {
ClusterInfo clusterInfo = clusterMap.get(cluster);
clusterInfo.addReserveRequestCpu(bc.getCpuRequest());
clusterInfo.addReserveRequestMemory(bc.getMemoryRequest());
}
// ClusterInfo 相关 end ...

// Node 相关 begin ...
public boolean isLocalNode(String cluster, String nodeName) {
Node node = getNode(cluster, nodeName);

Map<String, String> labelMap = node.getMetadata().getLabels();

return !labelMap.containsKey("remote");
}

public boolean isLocalCluster(String cluster) {
return clusterConfigService.getClusterConfig(cluster).getLocal();
}

public Node getNode(String cluster, String nodeName) {
ClusterInfo cInfo = clusterMap.get(cluster);
if (cInfo != null) {
Node node = cInfo.getNodeMap().get(nodeName);
if (node != null) {
return node;
}
}

// 直接查询
return k8sService.getNode(cluster, nodeName);
}
// Node 相关 end ...

public int getScaleNodeWeight(String cluster) {
return sysConfigService.getScaleNodeWeight();
}

public Map<String, Node> getClusterNodeMap(String cluster) {
Map<String, Node> nodeMap = new HashMap<>();
ClusterInfo clusterInfo = clusterMap.get(cluster);
if (clusterInfo != null) {
nodeMap = clusterInfo.getNodeMap();
}
return nodeMap;
}
}

+ 146
- 0
common/src/main/java/com/imitate/common/k8s/mgr/NodeManager.java View File

@@ -0,0 +1,146 @@
package com.imitate.common.k8s.mgr;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

import com.imitate.common.constant.TpCsts;
import com.imitate.common.k8s.mgr.node.NodeMgrIf;
import com.imitate.common.k8s.mgr.node.OjNodeMgr;
import com.imitate.common.k8s.bean.CreatePodResult;
import com.imitate.common.k8s.bean.PodCreateStrategy;
import com.imitate.common.sys.service.SysConfigService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;

/**
* node管理
*/
@Component
public class NodeManager {

@Autowired
private SysConfigService sysConfigService;

@Qualifier("normalNodeMgr")
@Autowired
private NodeMgrIf normalNodeMgr;

@Qualifier("shenlongNodeMgr")
@Autowired
private NodeMgrIf shenlongNodeMgr;

@Qualifier("gpuNodeMgr")
@Autowired
private NodeMgrIf gpuNodeMgr;

@Qualifier("ojNodeMgr")
@Autowired
private NodeMgrIf ojNodeMgr;

private AtomicBoolean checking = new AtomicBoolean(false);

public void check() {
boolean r = checking.compareAndSet(false, true);
if (!r) {// 启动时初始化线程和定时任务,可能并发执行。只允许一个执行
return;
}
try {
normalNodeMgr.check();
shenlongNodeMgr.check();
gpuNodeMgr.check();
ojNodeMgr.check();
} finally {
checking.set(false);
}
}

/**
* 是否公共pod
*
* @param podName
* @param buildParams
* @return
*/
public boolean isCommonPod(String podName, JSONObject buildParams) {
String containers = buildParams.getString("containers");
JSONArray jsonArray = JSONArray.parseArray(containers);
if (jsonArray.size() > 1) {
return false;
}
String imageName = jsonArray.getJSONObject(0).getString("image").split(":")[0];

List<String> commonImageNames = sysConfigService.getCommonImageNames();
return commonImageNames.contains(imageName) && podName.startsWith(TpCsts.TYPE_EVALUATE);
}

// 神龙------------start-------------
public boolean canScheduleNormalPodToShenlong(String cluster, int timeLimit) {
return this.shenlongNodeMgr.canScheduleNormalPod(cluster, timeLimit);
}

public void processShenlongPodStrategy(String cluster, PodCreateStrategy podCreateStrategy, String containers) {
this.shenlongNodeMgr.processPodCreateStrategy(cluster, podCreateStrategy, containers);
}

// 神龙------------end-------------
// GPU------------start-------------
public boolean canScheduleNormalPodToGpu(String cluster, int timeLimit) {
return this.gpuNodeMgr.canScheduleNormalPod(cluster, timeLimit);
}

public void processGpuPodStrategy(String cluster, PodCreateStrategy podCreateStrategy, String containers) {
this.gpuNodeMgr.processPodCreateStrategy(cluster, podCreateStrategy, containers);
}
// GPU------------end-------------

// oj------------start-------------
public boolean canScheduleNormalPodToOj(String cluster, int timeLimit) {
return this.ojNodeMgr.canScheduleNormalPod(cluster, timeLimit);
}

public void ojEvaStat(String cluster, String nodeName) {
((OjNodeMgr) this.ojNodeMgr).ojEvaStat(cluster, nodeName);
}

public void ojEvaTimeoutStat(String cluster, String nodeName) {
((OjNodeMgr) this.ojNodeMgr).ojEvaTimeoutStat(cluster, nodeName);
}

// oj------------end-------------

public List<String> getNoSchedulableNodes(String cluster) {
List<String> list = new ArrayList<>();
list.addAll(this.shenlongNodeMgr.getNoSchedulableNodes(cluster));
list.addAll(this.gpuNodeMgr.getNoSchedulableNodes(cluster));
list.addAll(this.ojNodeMgr.getNoSchedulableNodes(cluster));
list.addAll(this.normalNodeMgr.getNoSchedulableNodes(cluster));
return list;
}

public void processCreatePodResult(String cluster, CreatePodResult result) {
boolean processed = this.shenlongNodeMgr.processCreatePodResult(cluster, result);
if (processed) {
return;
}

processed = this.gpuNodeMgr.processCreatePodResult(cluster, result);
if (processed) {
return;
}

processed = this.ojNodeMgr.processCreatePodResult(cluster, result);
if (processed) {
return;
}

this.normalNodeMgr.processCreatePodResult(cluster, result);
}

}

+ 89
- 0
common/src/main/java/com/imitate/common/k8s/mgr/node/GpuNodeMgr.java View File

@@ -0,0 +1,89 @@
package com.imitate.common.k8s.mgr.node;


import com.imitate.common.k8s.mgr.ClusterManager;
import com.imitate.common.k8s.mgr.node.cluster.ClusterGpuNodeMgr;
import com.imitate.common.k8s.mgr.node.cluster.ClusterNodeMgrIf;
import com.imitate.common.k8s.bean.ClusterInfo;
import com.imitate.common.k8s.bean.CreatePodResult;
import com.imitate.common.k8s.bean.PodCreateStrategy;
import com.imitate.common.sys.settings.AppConfig;
import com.imitate.common.bean.BeanFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
* GPU节点管理
*/
@Component
public class GpuNodeMgr implements NodeMgrIf {

// Map<cluster, ClusterNodeMgrIf>
private final Map<String, ClusterNodeMgrIf> mgrMap = new HashMap<>();

@Autowired
private ClusterManager clusterManager;

@Autowired
private AppConfig appConfig;

@Override
public void check() {

// 没有Mgr的集群,初始化Mgr
Map<String, ClusterInfo> clusterMap = clusterManager.getClusterInfo();
for (ClusterInfo cInfo : clusterMap.values()) {
String cluster = cInfo.getClusterConfig().getName();
if (mgrMap.get(cluster) == null) {
if (cInfo.getClusterConfig().notSupportImage(appConfig.getGpuImage())) {
continue;
}

ClusterGpuNodeMgr mgr = BeanFactory.getObejct(ClusterGpuNodeMgr.class);
mgr.setCluster(cluster);
mgr.start();
mgrMap.put(cluster, mgr);
}
}

// 已经删除的集群,删除掉Mgr
for (String cluster : mgrMap.keySet()) {
if (!clusterMap.containsKey(cluster)) {
ClusterNodeMgrIf mgr = mgrMap.remove(cluster);
mgr.stop();
}
}
}

@Override
public boolean canScheduleNormalPod(String cluster, int timeLimit) {
ClusterNodeMgrIf mgr = mgrMap.get(cluster);
return mgr != null && mgr.canScheduleNormalPod(timeLimit);
}

@Override
public List<String> getNoSchedulableNodes(String cluster) {
ClusterNodeMgrIf mgr = mgrMap.get(cluster);
return mgr == null ? Collections.emptyList() : mgr.getNoSchedulableNodes();
}

@Override
public void processPodCreateStrategy(String cluster, PodCreateStrategy podCreateStrategy, String containers) {
ClusterNodeMgrIf mgr = mgrMap.get(cluster);
if (mgr != null) {
mgr.processPodCreateStrategy(podCreateStrategy, containers);
}
}

@Override
public boolean processCreatePodResult(String cluster, CreatePodResult result) {
ClusterNodeMgrIf mgr = mgrMap.get(cluster);
return mgr != null && mgr.processCreatePodResult(result);
}

}

+ 48
- 0
common/src/main/java/com/imitate/common/k8s/mgr/node/NodeMgrIf.java View File

@@ -0,0 +1,48 @@
package com.imitate.common.k8s.mgr.node;


import com.imitate.common.k8s.bean.CreatePodResult;
import com.imitate.common.k8s.bean.PodCreateStrategy;

import java.util.List;

/**
* node管理接口
*/
public interface NodeMgrIf {
/**
* 检测集群管理器等
*/
void check();

/**
* 节点能否调度普通pod
*
* @return
*/
boolean canScheduleNormalPod(String cluster, int timeLimit);

/**
* 获取不可调度的节点列表
*
* @return
*/
List<String> getNoSchedulableNodes(String cluster);

/**
* 处理pod创建策略
*
* @param podCreateStrategy
* @param containers
*/
void processPodCreateStrategy(String cluster, PodCreateStrategy podCreateStrategy, String containers);

/**
* 处理创建pod结果
*
* @param result
* @return 已经处理,返回true;不能处理,返回false。
*/
boolean processCreatePodResult(String cluster, CreatePodResult result);
}

+ 85
- 0
common/src/main/java/com/imitate/common/k8s/mgr/node/NormalNodeMgr.java View File

@@ -0,0 +1,85 @@
package com.imitate.common.k8s.mgr.node;


import com.imitate.common.k8s.mgr.ClusterManager;
import com.imitate.common.k8s.mgr.node.cluster.ClusterNodeMgrIf;
import com.imitate.common.k8s.mgr.node.cluster.ClusterNormalNodeMgr;
import com.imitate.common.k8s.bean.ClusterInfo;
import com.imitate.common.k8s.bean.CreatePodResult;
import com.imitate.common.k8s.bean.PodCreateStrategy;
import com.imitate.common.bean.BeanFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
* 普通 node 管理
*/
@Component
public class NormalNodeMgr implements NodeMgrIf {

// Map<cluster, ClusterNodeMgrIf>
private final Map<String, ClusterNodeMgrIf> mgrMap = new HashMap<>();

@Autowired
private ClusterManager clusterManager;

@Override
public void check() {
// 没有Mgr的集群,初始化Mgr
Map<String, ClusterInfo> clusterMap = clusterManager.getClusterInfo();
for (String cluster : clusterMap.keySet()) {
if (mgrMap.get(cluster) == null) {
ClusterNormalNodeMgr mgr = BeanFactory.getObejct(ClusterNormalNodeMgr.class);
mgr.setCluster(cluster);
mgr.start();
mgrMap.put(cluster, mgr);
}
}

// 已经删除的集群,删除掉Mgr
for (String cluster : mgrMap.keySet()) {
if (!clusterMap.containsKey(cluster)) {
ClusterNodeMgrIf mgr = mgrMap.remove(cluster);
mgr.stop();
}
}
}

@Override
public boolean canScheduleNormalPod(String cluster, int timeLimit) {
ClusterNodeMgrIf mgr = mgrMap.get(cluster);
return mgr != null && mgr.canScheduleNormalPod(timeLimit);
}

/**
* 暂时只有超时的情况,不可调度
*
* @return
*/
@Override
public List<String> getNoSchedulableNodes(String cluster) {
ClusterNodeMgrIf mgr = mgrMap.get(cluster);
return mgr == null ? Collections.emptyList() : mgr.getNoSchedulableNodes();
}

@Override
public void processPodCreateStrategy(String cluster, PodCreateStrategy podCreateStrategy, String containers) {
ClusterNodeMgrIf mgr = mgrMap.get(cluster);
if (mgr != null) {
mgr.processPodCreateStrategy(podCreateStrategy, containers);
}
}

@Override
public boolean processCreatePodResult(String cluster, CreatePodResult result) {

ClusterNodeMgrIf mgr = mgrMap.get(cluster);
return mgr != null && mgr.processCreatePodResult(result);
}

}

+ 107
- 0
common/src/main/java/com/imitate/common/k8s/mgr/node/OjNodeMgr.java View File

@@ -0,0 +1,107 @@
package com.imitate.common.k8s.mgr.node;


import com.imitate.common.k8s.mgr.ClusterManager;
import com.imitate.common.k8s.mgr.node.cluster.ClusterNodeMgrIf;
import com.imitate.common.k8s.mgr.node.cluster.ClusterOjNodeMgr;
import com.imitate.common.k8s.bean.ClusterInfo;
import com.imitate.common.k8s.bean.CreatePodResult;
import com.imitate.common.k8s.bean.PodCreateStrategy;
import com.imitate.common.bean.BeanFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
* oj 节点管理
*/
@Component
public class OjNodeMgr implements NodeMgrIf {
// Map<cluster, ClusterNodeMgrIf>
private final Map<String, ClusterNodeMgrIf> mgrMap = new HashMap<>();

@Autowired
private ClusterManager clusterManager;

@Override
public void check() {

// 没有Mgr的集群,初始化Mgr
Map<String, ClusterInfo> clusterMap = clusterManager.getClusterInfo();
for (ClusterInfo cInfo : clusterMap.values()) {
String cluster = cInfo.getClusterConfig().getName();
if (mgrMap.get(cluster) == null) {
if (!cInfo.getClusterConfig().getLocal()) {
continue;
}

ClusterOjNodeMgr mgr = BeanFactory.getObejct(ClusterOjNodeMgr.class);
mgr.setCluster(cluster);
mgr.start();
mgrMap.put(cluster, mgr);
}
}

// 已经删除的集群,删除掉Mgr
for (String cluster : mgrMap.keySet()) {
if (!clusterMap.containsKey(cluster)) {
ClusterNodeMgrIf mgr = mgrMap.remove(cluster);
mgr.stop();
}
}
}

public ClusterOjNodeMgr getClusterOjNodeMgr(String cluster) {
return (ClusterOjNodeMgr) mgrMap.get(cluster);
}

public void clearOjEvaStat() {
for (ClusterNodeMgrIf mgr : mgrMap.values()) {
((ClusterOjNodeMgr) mgr).clearOjEvaStat();
}
}

public void ojEvaStat(String cluster, String nodeName) {
ClusterNodeMgrIf mgr = mgrMap.get(cluster);
if (mgr != null) {
((ClusterOjNodeMgr) mgr).ojEvaStat(nodeName);
}
}

public void ojEvaTimeoutStat(String cluster, String nodeName) {
ClusterNodeMgrIf mgr = mgrMap.get(cluster);
if (mgr != null) {
((ClusterOjNodeMgr) mgr).ojEvaTimeoutStat(nodeName);
}
}

@Override
public boolean canScheduleNormalPod(String cluster, int timeLimit) {
ClusterNodeMgrIf mgr = mgrMap.get(cluster);
return mgr != null && mgr.canScheduleNormalPod(timeLimit);
}

@Override
public List<String> getNoSchedulableNodes(String cluster) {
ClusterNodeMgrIf mgr = mgrMap.get(cluster);
return mgr == null ? Collections.emptyList() : mgr.getNoSchedulableNodes();
}

@Override
public void processPodCreateStrategy(String cluster, PodCreateStrategy podCreateStrategy, String containers) {
ClusterNodeMgrIf mgr = mgrMap.get(cluster);
if (mgr != null) {
mgr.processPodCreateStrategy(podCreateStrategy, containers);
}
}

@Override
public boolean processCreatePodResult(String cluster, CreatePodResult result) {
ClusterNodeMgrIf mgr = mgrMap.get(cluster);
return mgr != null && mgr.processCreatePodResult(result);
}
}

+ 89
- 0
common/src/main/java/com/imitate/common/k8s/mgr/node/ShenlongNodeMgr.java View File

@@ -0,0 +1,89 @@
package com.imitate.common.k8s.mgr.node;


import com.imitate.common.k8s.mgr.ClusterManager;
import com.imitate.common.k8s.mgr.node.cluster.ClusterNodeMgrIf;
import com.imitate.common.k8s.mgr.node.cluster.ClusterShenlongNodeMgr;
import com.imitate.common.k8s.bean.ClusterInfo;
import com.imitate.common.k8s.bean.CreatePodResult;
import com.imitate.common.k8s.bean.PodCreateStrategy;
import com.imitate.common.sys.settings.AppConfig;
import com.imitate.common.bean.BeanFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
* 神龙节点管理
*/
@Component
public class ShenlongNodeMgr implements NodeMgrIf {

// Map<cluster, ClusterNodeMgrIf>
private final Map<String, ClusterNodeMgrIf> mgrMap = new HashMap<>();

@Autowired
private ClusterManager clusterManager;

@Autowired
private AppConfig appConfig;

@Override
public void check() {

// 没有Mgr的集群,初始化Mgr
Map<String, ClusterInfo> clusterMap = clusterManager.getClusterInfo();
for (ClusterInfo cInfo : clusterMap.values()) {
String cluster = cInfo.getClusterConfig().getName();
if (mgrMap.get(cluster) == null) {
if (cInfo.getClusterConfig().notSupportImage(appConfig.getShenlongImageCharacter())) {
continue;
}

ClusterShenlongNodeMgr mgr = BeanFactory.getObejct(ClusterShenlongNodeMgr.class);
mgr.setCluster(cluster);
mgr.start();
mgrMap.put(cluster, mgr);
}
}

// 已经删除的集群,删除掉Mgr
for (String cluster : mgrMap.keySet()) {
if (!clusterMap.containsKey(cluster)) {
ClusterNodeMgrIf mgr = mgrMap.remove(cluster);
mgr.stop();
}
}
}

@Override
public boolean canScheduleNormalPod(String cluster, int timeLimit) {
ClusterNodeMgrIf mgr = mgrMap.get(cluster);
return mgr != null && mgr.canScheduleNormalPod(timeLimit);
}

@Override
public List<String> getNoSchedulableNodes(String cluster) {
ClusterNodeMgrIf mgr = mgrMap.get(cluster);
return mgr == null ? Collections.emptyList() : mgr.getNoSchedulableNodes();
}

@Override
public void processPodCreateStrategy(String cluster, PodCreateStrategy podCreateStrategy, String containers) {
ClusterNodeMgrIf mgr = mgrMap.get(cluster);
if (mgr != null) {
mgr.processPodCreateStrategy(podCreateStrategy, containers);
}
}

@Override
public boolean processCreatePodResult(String cluster, CreatePodResult result) {
ClusterNodeMgrIf mgr = mgrMap.get(cluster);
return mgr != null && mgr.processCreatePodResult(result);
}

}

+ 311
- 0
common/src/main/java/com/imitate/common/k8s/mgr/node/cluster/ClusterGpuNodeMgr.java View File

@@ -0,0 +1,311 @@
package com.imitate.common.k8s.mgr.node.cluster;


import com.imitate.common.constant.TpCsts;
import com.imitate.common.k8s.constant.BridgeNodeCsts;
import com.imitate.common.k8s.bean.CreatePodResult;
import com.imitate.common.k8s.bean.NodeRes;
import com.imitate.common.k8s.bean.PodCreateStrategy;
import com.imitate.common.k8s.service.K8sService;
import com.imitate.common.k8s.util.ContainerUtil;
import com.imitate.common.k8s.util.K8sUtils;
import com.imitate.common.sys.competitor.LockCompetitor;
import com.imitate.common.sys.constant.SysConfigCsts;
import com.imitate.common.sys.service.SysConfigService;
import com.imitate.common.sys.settings.AppConfig;
import com.imitate.common.util.ThreadUtils;
import io.fabric8.kubernetes.api.model.Node;
import io.fabric8.kubernetes.api.model.Pod;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
* 集群GPU节点管理
*/
@Scope("prototype") // 每个集群一个实例
@Component
public class ClusterGpuNodeMgr implements ClusterNodeMgrIf {
private final Logger logger = LoggerFactory.getLogger(getClass());

// Map<nodeName, 恢复正常时间>, 过载节点记录在此,到了恢复时间,即可重新分配pod
private final Map<String, Long> overloadMap = new ConcurrentHashMap<>();

// 所有 pod request cpu之和阈值,达到阈值,不再分配普通pod到gpu节点
private volatile double requestCpuThreshold = 0;
// pod request cpu总量
private volatile double requestCpuTotal = 0;

// 节点资源,Map<nodeIp, NodeRes>
private volatile Map<String, NodeRes> nodeResMap = new HashMap<>();

private String cluster;
private volatile boolean terminated = false;

@Qualifier("podScheduleLockCompetitor")
@Autowired
private LockCompetitor lockCompetitor;

@Autowired
private K8sService k8sService;

@Autowired
private SysConfigService sysConfigService;

@Autowired
private AppConfig appConfig;

@Override
public void start() {
new Thread(() -> {
this.checkNodePressure();
}).start();

new Thread(() -> {
this.checkNodeRecovery();
}).start();

}

// 检测节点是否恢复
private void checkNodeRecovery() {
while (!terminated) {
try {
if (lockCompetitor.winLock()) {
checkNodeRecoveryInner();
}
} catch (Throwable t) {
logger.error("GPU节点超时到期后,尝试创建pod,以检测节点是否恢复正常出错, cluster:{}", cluster, t);
} finally {
ThreadUtils.sleep(60 * 1000);
}
}
}

private void checkNodeRecoveryInner() {
long now = System.currentTimeMillis();
Map<String, Long> tempMap = overloadMap;
Set<String> keySet = tempMap.keySet();
for (String nodeName : keySet) {
if (!nodeResMap.containsKey(nodeName)) {
continue;
}
if (tempMap.get(nodeName) > now) {
continue;
}

int timeLimit = (int) sysConfigService.getCreatePodCostMaxTime() / 1000 / 2;
String podName = "checkpod-" + appConfig.getBridgeInstanceName();
try {
Boolean success = k8sService.createCheckPod(cluster, podName, nodeName, timeLimit,
SysConfigCsts.CHECK_POD_CONTAINER_IMAGE);
if (success) {
k8sService.updateNodeLabel(cluster, nodeName, "type", "others");
overloadMap.remove(nodeName);
logger.info("GPU节点创建检测pod成功,超时状态结束, 节点:{}, cluster:{}", nodeName, cluster);
} else {
overloadMap.put(nodeName,
System.currentTimeMillis() + sysConfigService.getGpuNodeOverloadExpireTime());
logger.info("GPU节点创建检测pod失败,超时状态继续, 节点:{}, cluster:{}", nodeName, cluster);
}
} catch (Exception e) {
logger.error("检查GPU节点创建pod出错,image: {}, 节点:{}, cluster:{}", SysConfigCsts.CHECK_POD_CONTAINER_IMAGE,
nodeName, cluster, e);
} finally {
k8sService.deletePod(cluster, podName);
}
}
}

private void checkNodePressure() {
while (!terminated) {
try {
double totalCpu = 0; // 所有节点cpu总量
double requestCpuTotalTmp = 0; // 所有GPU pod request cpu总量
Map<String, NodeRes> nodeResMapTmp = new HashMap<>();

List<Node> nodes = k8sService.getNodeListWithLabel(cluster, TpCsts.GPU_NODE_LABEL_KEY,
TpCsts.GPU_NODE_LABEL_VALUE);
for (Node node : nodes) {
NodeRes nodeRes = new NodeRes();
String nodeName = node.getMetadata().getName();
nodeRes.setNodeName(nodeName);

String val = K8sUtils.getLabel(node, "type");
if (BridgeNodeCsts.NODE_LABEL_TYPE_UNDER_PRESSURE.equals(val)) {
if (overloadMap.get(nodeName) == null) {
overloadMap.put(nodeName,
System.currentTimeMillis() + sysConfigService.getGpuNodeOverloadExpireTime());
}
} else {
overloadMap.remove(nodeName);
}

// 节点已分配 cpu
double nodeRequestCpu = 0;
List<Pod> podList = k8sService.getPodListWithNodeName(cluster, nodeName);
for (Pod pod : podList) {
if (pod.getMetadata() != null && pod.getMetadata().getLabels() != null) {
String nodeRequire = pod.getMetadata().getLabels().get(TpCsts.NODE_REQUIRE);
if (appConfig.getGpuImage().equals(nodeRequire)) {// 神龙pod
double requestCpu = K8sUtils.getRequestCpu(pod);
nodeRequestCpu += requestCpu;
}
}
}
nodeRes.setRequestCpu(nodeRequestCpu);

// 节点可分配cpu
double nodeCpu = K8sUtils.getNodeAllocatableCpu(node);
nodeRes.setAllocatableCpu(nodeCpu);
// 此节点GPU pod request cpu总量占可用cpu的比例
double requestRate = nodeRequestCpu / nodeCpu;
nodeRes.setRequestCpuRate(requestRate);
nodeResMapTmp.put(nodeName, nodeRes);

totalCpu += nodeCpu; // 增加cpu总量
requestCpuTotalTmp += nodeRequestCpu; // 增加GPU pod request cpu总量
}

nodeResMap = nodeResMapTmp;
requestCpuTotal = requestCpuTotalTmp;
requestCpuThreshold = totalCpu * sysConfigService.getGpuOverloadPercent() / 100;

removeNoLongerExistNode(); // 删除不再存在的节点
} catch (Throwable t) {
logger.error("检查GPU节点压力出错, cluster:{}", cluster, t);
} finally {
ThreadUtils.sleep(5000);
}
}

}

/**
* 一些节点被回收,不再存在
*/
private void removeNoLongerExistNode() {
Map<String, Long> tempMap = overloadMap;
Set<String> keySet = tempMap.keySet();
for (String key : keySet) {
if (!nodeResMap.containsKey(key)) {
overloadMap.remove(key);
}
}
}

@Override
public void setCluster(String cluster) {
this.cluster = cluster;
}

@Override
public boolean canScheduleNormalPod(int timeLimit) {
boolean openReuse = sysConfigService.getGpuNodeOpenReuse();
if (!openReuse) {
return false;
}
logger.debug("canScheduleNormalPod requestCpuTotal: {}, requestCpuThreshold: {}", requestCpuTotal, requestCpuThreshold);
return requestCpuTotal < requestCpuThreshold;
}

/**
* 暂时只有超时的情况,不可调度。 此处针对把普通pod调度到神龙节点。
*
* @return
*/
@Override
public List<String> getNoSchedulableNodes() {
return new ArrayList<>(overloadMap.keySet());
}

/**
* 处理pod调度策略
*
* @param podCreateStrategy
*/
@Override
public void processPodCreateStrategy(PodCreateStrategy podCreateStrategy, String containers) {
boolean gpu = containers.contains(appConfig.getGpuImage());// 可在上一层处理
if (!gpu) {
return;
}

List<NodeRes> list = new ArrayList<>(nodeResMap.values());
if (list.size() <= 1) {
return;
}
Collections.sort(list, new Comparator<NodeRes>() {
@Override
public int compare(NodeRes o1, NodeRes o2) {
return o1.getRequestCpuRate().compareTo(o2.getRequestCpuRate());
}
});

// bridge规模扩大时,必要改为集中分配
double requestCpu = ContainerUtil.getRequestCpu(containers);
boolean existNoSchedulableNode = true; // 存在不可调度的节点
List<String> noList = new ArrayList<>();
for (int i = list.size() - 1; i > 0; i--) {
NodeRes higher = list.get(i);
NodeRes least = list.get(0);

double unAffinityCpu = requestCpu + higher.getUnAffinityCpu();
// k8s是整体调度的,可能把很多GPU pod调度到资源较小的节点,普通pod调度到资源较大的节点。这时候更加需要把GPU pod往资源较大节点分配。
// 例如把3个GPU pod分配到8c节点,32c节点一个GPU pod都没有。
double allocatableCpu = least.getAllocatableCpu();
// 当前是2台bridge节点,每台可以调节50%的量, 再乘0.8是因为pod本来倾向于分配到较小节点
if (allocatableCpu * (higher.getRequestCpuRate() - least.getRequestCpuRate()) * 0.5 * 0.8 > unAffinityCpu) {
noList.add(higher.getNodeName());
higher.addUnAffinityCpu(requestCpu);
} else {
existNoSchedulableNode = false;
}

// 3种情况检测结束:(1)没有更多不可调度的节点。(2)不可调度的节点数量超过9。(3)已经有超过一半的节点不可调度。
if (!existNoSchedulableNode || noList.size() > 9 || noList.size() >= list.size() / 2) {
break;
}
}

// 此处是针对GPU pod
podCreateStrategy.setNoSchedulableGpuNodes(noList);

}

@Override
public boolean processCreatePodResult(CreatePodResult result) {
String nodeName = K8sUtils.getNodeName(result.getPod());
if (StringUtils.isBlank(nodeName)) {
return false;// 调度失败,连节点都没有
}

if (!nodeResMap.containsKey(nodeName)) { // 不是GPU节点
return false;
}

if (Boolean.FALSE.equals(result.getSuccess())
&& result.getMillisecondCost() >= sysConfigService.getCreatePodCostMaxTime()) {
overloadMap.put(nodeName, System.currentTimeMillis() + sysConfigService.getGpuNodeOverloadExpireTime());
k8sService.updateNodeLabel(cluster, nodeName, BridgeNodeCsts.NODE_LABEL_TYPE,
BridgeNodeCsts.NODE_LABEL_TYPE_UNDER_PRESSURE);
logger.info("创建pod 超时 {}s,GPU节点超时状态开始,更改type label,pod:{}, node:{}, cluster:{}",
result.getMillisecondCost() / 1000, K8sUtils.getPodName(result.getPod()), nodeName, cluster);
}

return true;

}

@Override
public void stop() {
terminated = true;
}
}

+ 61
- 0
common/src/main/java/com/imitate/common/k8s/mgr/node/cluster/ClusterNodeMgrIf.java View File

@@ -0,0 +1,61 @@
package com.imitate.common.k8s.mgr.node.cluster;


import com.imitate.common.k8s.bean.CreatePodResult;
import com.imitate.common.k8s.bean.PodCreateStrategy;

import java.util.List;

/**
* 集群节点管理接口。
*/
public interface ClusterNodeMgrIf {
/**
* 启动管理器
*/
void start();
/**
* 集群
*
* @param cluster
* @return
*/
void setCluster(String cluster);

/**
* 节点能否调度普通pod
*
* @return
*/
boolean canScheduleNormalPod(int timeLimit);

/**
* 获取不可调度的节点列表
*
* @return
*/
List<String> getNoSchedulableNodes();

/**
* 处理pod创建策略
*
* @param podCreateStrategy
* @param containers
*/
void processPodCreateStrategy(PodCreateStrategy podCreateStrategy, String containers);

/**
* 处理创建pod结果
*
* @param result
* @return 已经处理,返回true;不能处理,返回false。
*/
boolean processCreatePodResult(CreatePodResult result);
/**
* 停止管理器
*/
void stop();
}


+ 114
- 0
common/src/main/java/com/imitate/common/k8s/mgr/node/cluster/ClusterNormalNodeMgr.java View File

@@ -0,0 +1,114 @@
package com.imitate.common.k8s.mgr.node.cluster;


import com.imitate.common.k8s.bean.CreatePodResult;
import com.imitate.common.k8s.bean.PodCreateStrategy;
import com.imitate.common.k8s.util.K8sUtils;
import com.imitate.common.sys.service.SysConfigService;
import com.imitate.common.util.ThreadUtils;
import io.fabric8.kubernetes.api.model.Pod;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
* 集群普通节点管理。
*/
@Scope("prototype") // 每个集群一个实例
@Component
public class ClusterNormalNodeMgr implements ClusterNodeMgrIf {
private final Logger logger = LoggerFactory.getLogger(getClass());

// Map<nodeName, 恢复正常时间>, 过载节点记录在此,到了恢复时间,即可重新分配pod
private final Map<String, Long> normalNodeOverloadMap = new ConcurrentHashMap<>();
// 集群
private String cluster;
private volatile boolean terminated = false;

@Autowired
private SysConfigService sysConfigService;

@Override
public void start() {
new Thread(() -> {
this.doWork();
}).start();
}
private void doWork() {
while (!terminated) {
try {
checkoutNormalRecovery();
} catch (Throwable e) {
logger.error("检查普通节点恢复正常出错, cluster:{}", cluster, e);
} finally {
ThreadUtils.sleep(5000);
}
}
}

private void checkoutNormalRecovery() {
long now = System.currentTimeMillis();
Map<String, Long> tempMap = normalNodeOverloadMap;
Set<String> keySet = tempMap.keySet();
for (String key : keySet) {
if (tempMap.get(key) <= now) {
normalNodeOverloadMap.remove(key);
}
}
}

@Override
public void setCluster(String cluster) {
this.cluster = cluster;
}

@Override
public boolean canScheduleNormalPod(int timeLimit) {
return true;
}

@Override
public List<String> getNoSchedulableNodes() {
return new ArrayList<>(normalNodeOverloadMap.keySet());
}

@Override
public void processPodCreateStrategy(PodCreateStrategy podCreateStrategy, String containers) {
throw new UnsupportedOperationException("ClusterNormalNodeMgr 不支持的操作");
}

@Override
public boolean processCreatePodResult(CreatePodResult result) {
Pod pod = result.getPod();
String nodeName = K8sUtils.getNodeName(pod);
if (StringUtils.isBlank(nodeName)) {
return false; // 调度失败,连节点都没有
}

if (Boolean.FALSE.equals(result.getSuccess())
&& result.getMillisecondCost() >= sysConfigService.getCreatePodCostMaxTime()) {
normalNodeOverloadMap.put(nodeName,
System.currentTimeMillis() + sysConfigService.getNodeOverloadExpireTime());
logger.info("创建 pod 超时, cluster:{}, pod:{}, 耗时:{}s,节点{}超时状态开始", cluster, K8sUtils.getPodName(pod),
result.getMillisecondCost() / 1000, nodeName);
}

return true;
}

@Override
public void stop() {
terminated = true;
}

}

+ 348
- 0
common/src/main/java/com/imitate/common/k8s/mgr/node/cluster/ClusterOjNodeMgr.java View File

@@ -0,0 +1,348 @@
package com.imitate.common.k8s.mgr.node.cluster;


import com.imitate.common.constant.TpCsts;
import com.imitate.common.k8s.constant.BridgeNodeCsts;
import com.imitate.common.k8s.bean.CreatePodResult;
import com.imitate.common.k8s.bean.PodCreateStrategy;
import com.imitate.common.k8s.service.K8sService;
import com.imitate.common.k8s.util.K8sUtils;
import com.imitate.common.sys.competitor.LockCompetitor;
import com.imitate.common.sys.service.SysConfigService;
import com.imitate.common.util.JedisUtil;
import com.imitate.common.util.ThreadUtils;
import io.fabric8.kubernetes.api.model.Node;
import io.fabric8.kubernetes.api.model.Pod;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
* 集群 oj 节点管理
*/
@Scope("prototype") // 每个集群一个实例
@Component
public class ClusterOjNodeMgr implements ClusterNodeMgrIf {
private final Logger logger = LoggerFactory.getLogger(getClass());

// Map<nodeName, 恢复正常时间>, 过载节点记录在此,到了恢复时间,即可重新分配pod
private final Map<String, Long> ojNodeOverloadMap = new ConcurrentHashMap<>();

private final int POD_CAN_TO_OJ_MAX_TIME_LIMIT = 10;

private final String OJ_EVA_STAT_REDIS_CACHE_KEY = "ojEvaStat_";

private final String OJ_EVA_TIMEOUT_STAT_REDIS_CACHE_KEY = "ojEvaTimeoutStat_";

// HashMap即可,当前只要检测单线程访问
private final Map<String, Integer> ojNodeEvaCountMap = new ConcurrentHashMap<>();

private final Map<String, Integer> ojNodeEvaTimeoutCountMap = new ConcurrentHashMap<>();

private volatile long updateEvaTimeoutCountTimestamp = System.currentTimeMillis();

private volatile Map<String, Node> ojNodeMap = new ConcurrentHashMap<>();

// 集群
private String cluster;
private volatile boolean terminated = false;

@Qualifier("podScheduleLockCompetitor")
@Autowired
private LockCompetitor lockCompetitor;

@Autowired
private K8sService k8sService;

@Autowired
private SysConfigService sysConfigService;

@Override
public void start() {
// new Thread(() -> {
// this.checkOjNodePressure();
// }).start();
}

private void checkOjNodePressure() {
while (!terminated) {
try {
long nowTime = System.currentTimeMillis();
boolean cycleOver = nowTime - updateEvaTimeoutCountTimestamp > 10 * 1000;// 周期结束
if (cycleOver) {
updateEvaTimeoutCountTimestamp = nowTime;
}
Map<String, Node> ojNodeMapTmp = new HashMap<>();

// 获取oj节点
List<Node> nodes = k8sService.getNodeListWithLabel(cluster, TpCsts.OJ_LABEL_KEY, TpCsts.OJ_LABEL_VALUE);
// 更新节点压力情况
for (Node node : nodes) {
String nodeName = node.getMetadata().getName();
ojNodeMapTmp.put(nodeName, node);
if (lockCompetitor.winLock()) {// bridge调度中心节点
if (ojNodeOverloadMap.get(nodeName) == null) {
checkOjNodePressure(node);
} else if (ojNodeOverloadMap.get(nodeName) < nowTime) {// 压力时间已过
checkOjNodePressure(node);
}
} else {// bridge普通节点
String val = K8sUtils.getLabel(node, "type");
if (BridgeNodeCsts.NODE_LABEL_TYPE_UNDER_PRESSURE.equals(val)) {
if (ojNodeOverloadMap.get(nodeName) == null) {
ojNodeOverloadMap.put(nodeName,
System.currentTimeMillis() + sysConfigService.getOjNodeOverloadExpireTime());
}
} else {
ojNodeOverloadMap.remove(nodeName);
}
}

changeCount(nodeName, cycleOver);
}
ojNodeMap = ojNodeMapTmp;

// 检查压力node是否仍然存在
for (String nodeName : ojNodeOverloadMap.keySet()) {
boolean found = false;
for (Node node : nodes) {
String name = node.getMetadata().getName();
if (nodeName.equals(name)) {
found = true;
break;
}
}
if (!found) {// 如果压力节点已经从k8s集群删除,则删除掉
ojNodeOverloadMap.remove(nodeName);
}
}

} catch (Throwable t) {
logger.error("检查oj节点压力出错, cluster:{}", cluster, t);
} finally {
ThreadUtils.sleep(5000);
}
}
}

private void checkOjNodePressure(Node node) {
boolean isOverload = isOjNodeOverload(cluster, node);
String nodeName = node.getMetadata().getName();
boolean isEvaTimeout = isOjNodeEvaTimeout(nodeName);

if (isOverload || isEvaTimeout) {
if (ojNodeOverloadMap.get(nodeName) == null) {
// k8sService.updateNodeLabel(cluster, nodeName, "type", BridgeNodeCsts.NODE_LABEL_TYPE_UNDER_PRESSURE);
logger.info("oj节点压力过大, cluster:{}, nodeName:{}, isOverload: {}, isEvaTimeout:{}", cluster,
nodeName, isOverload, isEvaTimeout);
} else {
logger.info("oj节点有压力,超时状态继续, cluster:{}, nodeName:{}, isOverload: {}, isEvaTimeout:{}", cluster,
nodeName, isOverload, isEvaTimeout);
}
ojNodeOverloadMap.put(nodeName,
System.currentTimeMillis() + sysConfigService.getOjNodeOverloadExpireTime());
} else {
if (ojNodeOverloadMap.get(nodeName) != null) {
// k8sService.updateNodeLabel(cluster, nodeName, "type", "others");
ojNodeOverloadMap.remove(nodeName);
logger.info("oj节点压力恢复正常, cluster:{}, nodeName:{}", cluster, nodeName);
}
}

}

/**
* 更改计数
*
* @param nodeName
* @param cycleOver
*/
private void changeCount(String nodeName, boolean cycleOver) {
// 超时计数
if (cycleOver) {
String newOjEvaTimeoutCountStr = JedisUtil.get(OJ_EVA_TIMEOUT_STAT_REDIS_CACHE_KEY + nodeName);
int newOjEvaTimeoutCount = StringUtils.isNotEmpty(newOjEvaTimeoutCountStr)
? Integer.parseInt(newOjEvaTimeoutCountStr)
: 0;
ojNodeEvaTimeoutCountMap.put(nodeName, newOjEvaTimeoutCount);
}

// 评测计数
String newOjEvaCountStr = JedisUtil.get(OJ_EVA_STAT_REDIS_CACHE_KEY + nodeName);
int newOjEvaCount = StringUtils.isNotEmpty(newOjEvaCountStr) ? Integer.parseInt(newOjEvaCountStr) : 0;
ojNodeEvaCountMap.put(nodeName, newOjEvaCount);

}

private boolean isOjNodeEvaTimeout(String nodeName) {
String newOjEvaTimeoutCountStr = JedisUtil.get(OJ_EVA_TIMEOUT_STAT_REDIS_CACHE_KEY + nodeName);
int newOjEvaTimeoutCount = StringUtils.isNotEmpty(newOjEvaTimeoutCountStr)
? Integer.parseInt(newOjEvaTimeoutCountStr)
: 0;

Integer ojEvaTimeoutCount = ojNodeEvaTimeoutCountMap.get(nodeName) != null
? ojNodeEvaTimeoutCountMap.get(nodeName)
: 0;

int maxEvaTimeoutNum = sysConfigService.getOjNodeMaxEvaTimeoutNum();
logger.debug(
"oj超时检测详情, cluster:{}, nodeName:{}, newOjEvaTimeoutCount: {}, ojEvaTimeoutCount:{}, maxEvaTimeoutNum:{}",
cluster, nodeName, newOjEvaTimeoutCount, ojEvaTimeoutCount, maxEvaTimeoutNum);

int timeoutNum = newOjEvaTimeoutCount - ojEvaTimeoutCount;
return timeoutNum > maxEvaTimeoutNum;
}

private boolean isOjNodeOverload(final String cluster, Node node) {
String nodeName = node.getMetadata().getName();
List<Pod> podList = k8sService.getPodListReversely(cluster, nodeName, TpCsts.OJ_LABEL_KEY, TpCsts.OJ_LABEL_VALUE);

double nodeCPU = K8sUtils.getNodeCapacityCpu(node);
// 根据节点cpu与最大可使用算力百分比计算最大可使用算力(8核节点算力为100)
double ojNodePowerThreshold = nodeCPU / 8 * sysConfigService.getOjNodeMaxPowPercent();

// 计算普通pod使用算力(普通pod评测使用算力为3)
int evaluatePodUsedPower = podList.size() * 8;

// 计算oj pod使用算力
int ojPodUsedPower = getOjPodUsedPower(nodeName);

// 当前node实际使用算力
int ojNodeUsedPower = evaluatePodUsedPower + ojPodUsedPower;
logger.debug(
"oj压力检测详情, cluster:{}, nodeName:{}, ojNodePowerThreshold: {}, evaluatePodUsedPower:{}, ojPodUsedPower:{}",
cluster, nodeName, ojNodePowerThreshold, evaluatePodUsedPower, ojPodUsedPower);

return ojNodeUsedPower > ojNodePowerThreshold;
}

private int getOjPodUsedPower(String nodeName) {
String newOjEvaCountStr = JedisUtil.get(OJ_EVA_STAT_REDIS_CACHE_KEY + nodeName);
int newOjEvaCount = StringUtils.isNotEmpty(newOjEvaCountStr) ? Integer.parseInt(newOjEvaCountStr) : 0;
Integer ojEvaCount = ojNodeEvaCountMap.get(nodeName) != null ? ojNodeEvaCountMap.get(nodeName) : 0;

return newOjEvaCount - ojEvaCount;
}

/**
* 清理评测统计
*/
public void clearOjEvaStat() {
// 获取oj节点
List<Node> nodes = k8sService.getNodeListWithLabel(cluster, TpCsts.OJ_LABEL_KEY, TpCsts.OJ_LABEL_VALUE);

for (Node node : nodes) {
String nodeName = node.getMetadata().getName();
JedisUtil.del(OJ_EVA_STAT_REDIS_CACHE_KEY + nodeName);
ojNodeEvaCountMap.put(nodeName, 0);

JedisUtil.del(OJ_EVA_TIMEOUT_STAT_REDIS_CACHE_KEY + nodeName);
ojNodeEvaTimeoutCountMap.put(nodeName, 0);
}
}

public void ojEvaStat(String nodeName) {
JedisUtil.incrBy(OJ_EVA_STAT_REDIS_CACHE_KEY + nodeName, 1);
}

public void ojEvaTimeoutStat(String nodeName) {
JedisUtil.incrBy(OJ_EVA_TIMEOUT_STAT_REDIS_CACHE_KEY + nodeName, 1);
}

@Override
public void setCluster(String cluster) {
this.cluster = cluster;
}

@Override
public boolean canScheduleNormalPod(int timeLimit) {
return (timeLimit <= POD_CAN_TO_OJ_MAX_TIME_LIMIT) && sysConfigService.getOjNodeOpenReuse()
&& ojNodeMap.size() > ojNodeOverloadMap.size();
}

/**
* 暂时只有超时的情况,不可调度
*
* @return
*/
@Override
public List<String> getNoSchedulableNodes() {
return new ArrayList<>(ojNodeOverloadMap.keySet());
}

/**
* 处理pod调度策略
*
* @param podCreateStrategy
*/
@Override
public void processPodCreateStrategy(PodCreateStrategy podCreateStrategy, String containers) {
throw new UnsupportedOperationException("oj 共享pod, 不支持processPodCreateStrategy");
}

@Override
public boolean processCreatePodResult(CreatePodResult result) {
String nodeName = K8sUtils.getNodeName(result.getPod());
if (StringUtils.isBlank(nodeName)) {
return false;// 调度失败,连节点都没有
}

if (!ojNodeMap.containsKey(nodeName)) { // 不是oj节点
return false;
}

if (Boolean.FALSE.equals(result.getSuccess())
&& result.getMillisecondCost() >= sysConfigService.getCreatePodCostMaxTime()) {

ojNodeOverloadMap.put(nodeName,
System.currentTimeMillis() + sysConfigService.getOjNodeOverloadExpireTime());
// k8sService.updateNodeLabel(cluster, nodeName, "type", BridgeNodeCsts.NODE_LABEL_TYPE_UNDER_PRESSURE);
logger.info("创建pod {} 超时 {}s,oj节点{}超时状态开始, cluster:{}", K8sUtils.getPodName(result.getPod()),
result.getMillisecondCost() / 1000, nodeName, cluster);
}

return true;

}

@Override
public void stop() {
terminated = true;
}

public Double ojNodeOverloadRatio() {
if (ojNodeMap.size() > 0) {
return ojNodeOverloadMap.size() / (double) ojNodeMap.size();
}
return null;
}

public String getNoOverloadOjNodeName() {
Map<String, Node> ojNodeMapTemp = ojNodeMap;
Set<String> keySet = ojNodeMapTemp.keySet();
for (String nodeName : keySet) {
if (!ojNodeOverloadMap.containsKey(nodeName)) {
Node node = ojNodeMapTemp.get(nodeName);
String capacityLabelValue = K8sUtils.getLabel(node, TpCsts.OJ_CAPACITY_NODE_LABEL_KEY);
if (StringUtils.isNotEmpty(capacityLabelValue)
&& LocalDateTime.now().isAfter(LocalDateTime.parse(capacityLabelValue, DateTimeFormatter.ofPattern("yyyyMMddHHmmss")))) {
return nodeName;
}
}
}
return null;
}

public int getOjNodeSize() {
return ojNodeMap.size();
}
}

+ 299
- 0
common/src/main/java/com/imitate/common/k8s/mgr/node/cluster/ClusterShenlongNodeMgr.java View File

@@ -0,0 +1,299 @@
package com.imitate.common.k8s.mgr.node.cluster;


import com.imitate.common.constant.TpCsts;
import com.imitate.common.k8s.bean.CreatePodResult;
import com.imitate.common.k8s.bean.PodCreateStrategy;
import com.imitate.common.k8s.constant.BridgeNodeCsts;
import com.imitate.common.k8s.bean.NodeRes;
import com.imitate.common.k8s.service.K8sService;
import com.imitate.common.k8s.util.ContainerUtil;
import com.imitate.common.k8s.util.K8sUtils;
import com.imitate.common.sys.competitor.LockCompetitor;
import com.imitate.common.sys.service.SysConfigService;
import com.imitate.common.sys.settings.AppConfig;
import com.imitate.common.util.ThreadUtils;
import io.fabric8.kubernetes.api.model.Node;
import io.fabric8.kubernetes.api.model.Pod;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
* 集群神龙节点管理
*/
@Scope("prototype") // 每个集群一个实例
@Component
public class ClusterShenlongNodeMgr implements ClusterNodeMgrIf {
private final Logger logger = LoggerFactory.getLogger(getClass());

// Map<nodeName, 恢复正常时间>, 过载节点记录在此,到了恢复时间,即可重新分配pod
private final Map<String, Long> shenlongNodeOverloadMap = new ConcurrentHashMap<>();

// 所有神龙节点request cpu之和阈值,达到阈值,不再分配普通pod到神龙节点
private volatile double shenlongNodeRequestCpuThreshold = 0;
// 神龙pod request cpu总量
private volatile double shenlongPodRequestCpuTotal = 0;

// 神龙节点资源,Map<nodeIp, NodeRes>
private volatile Map<String, NodeRes> shenlongNodeResMap = new HashMap<>();

private final String CHECK_POD_CONTAINER_IMAGE = "gcc-ssh:v1.0";

private String cluster;
private volatile boolean terminated = false;
@Qualifier("podScheduleLockCompetitor")
@Autowired
private LockCompetitor lockCompetitor;

@Autowired
private K8sService k8sService;

@Autowired
private SysConfigService sysConfigService;

@Autowired
private AppConfig appConfig;

@Override
public void start() {
new Thread(() -> {
this.checkShenlongNodePressure();
}).start();

new Thread(() -> {
this.checkShenlongNodeRecovery();
}).start();

}

// 检测神龙节点是否恢复
private void checkShenlongNodeRecovery() {
while (!terminated) {
try {
if (lockCompetitor.winLock()) {
checkShenlongNodeRecoveryInner();
}
} catch (Throwable t) {
logger.error("神龙节点超时到期后,尝试创建pod,以检测节点是否恢复正常出错, cluster:{}", cluster, t);
} finally {
ThreadUtils.sleep(60 * 1000);
}
}
}
private void checkShenlongNodeRecoveryInner() {
long now = System.currentTimeMillis();
Map<String, Long> tempMap = shenlongNodeOverloadMap;
Set<String> keySet = tempMap.keySet();
for (String nodeName : keySet) {
if (!shenlongNodeResMap.containsKey(nodeName)) {
continue;
}
if (tempMap.get(nodeName) > now) {
continue;
}

int timeLimit = (int) sysConfigService.getCreatePodCostMaxTime() / 1000 / 2;
String podName = "checkpod-" + appConfig.getBridgeInstanceName();
try {
Boolean shenlongNodeCreatePodFlag = k8sService.createCheckPod(cluster, podName, nodeName, timeLimit,
CHECK_POD_CONTAINER_IMAGE);
if (shenlongNodeCreatePodFlag) {
k8sService.updateNodeLabel(cluster, nodeName, "type", "others");
shenlongNodeOverloadMap.remove(nodeName);
logger.info("神龙节点{}创建检测pod成功,超时状态结束, cluster:{}", nodeName, cluster);
} else {
shenlongNodeOverloadMap.put(nodeName,
System.currentTimeMillis() + sysConfigService.getShenlongNodeOverloadExpireTime());
logger.info("神龙节点{}创建检测pod失败,超时状态继续, cluster:{}", nodeName, cluster);
}
} catch (Exception e) {
logger.error("检查神龙节点创建pod出错,image: {}, cluster:{}", CHECK_POD_CONTAINER_IMAGE, cluster, e);
} finally {
k8sService.deletePod(cluster, podName);
}
}
}

private void checkShenlongNodePressure() {
while (!terminated) {
try {
double totalCpu = 0; // 所有神龙节点,cpu总量
double shenlongPodRequestCpu = 0; // 所有神龙pod request cpu总量
Map<String, NodeRes> nodeResMapTmp = new HashMap<>();

List<Node> nodes = k8sService.getNodeListWithLabel(cluster, TpCsts.SHENLONG_NODE_LABEL_KEY,
TpCsts.SHENLONG_NODE_LABEL_VALUE);
for (Node node : nodes) {
NodeRes nodeRes = new NodeRes();
String nodeName = node.getMetadata().getName();
nodeRes.setNodeName(nodeName);
String val = K8sUtils.getLabel(node, "type");
if (BridgeNodeCsts.NODE_LABEL_TYPE_UNDER_PRESSURE.equals(val)) {
if (shenlongNodeOverloadMap.get(nodeName) == null) {
shenlongNodeOverloadMap.put(nodeName,
System.currentTimeMillis() + sysConfigService.getShenlongNodeOverloadExpireTime());
}
} else {
shenlongNodeOverloadMap.remove(nodeName);
}
// 节点已分配 cpu
double requestCpuTotal = 0;
List<Pod> podList = k8sService.getPodListWithNodeName(cluster, nodeName);
for (Pod pod : podList) {
if (pod.getMetadata() != null && pod.getMetadata().getLabels() != null) {
String nodeRequire = pod.getMetadata().getLabels().get(TpCsts.NODE_REQUIRE);
if (appConfig.getShenlongImageCharacter().equals(nodeRequire)) {// 神龙pod
double requestCpu = K8sUtils.getRequestCpu(pod);
requestCpuTotal += requestCpu;
}
}
}
nodeRes.setRequestCpu(requestCpuTotal);

// 节点可分配cpu
double nodeCpu = K8sUtils.getNodeAllocatableCpu(node);
nodeRes.setAllocatableCpu(nodeCpu);
// 此节点神龙pod request cpu总量占可用cpu的比例
double requestRate = requestCpuTotal / nodeCpu;
nodeRes.setRequestCpuRate(requestRate);
nodeResMapTmp.put(nodeName, nodeRes);

totalCpu += nodeCpu; // 增加cpu总量
shenlongPodRequestCpu += requestCpuTotal; // 增加神龙pod request cpu总量
}

shenlongNodeResMap = nodeResMapTmp;
shenlongPodRequestCpuTotal = shenlongPodRequestCpu;
shenlongNodeRequestCpuThreshold = totalCpu * sysConfigService.getShenlongOverloadPercent() / 100;

removeNoLongerExistNode(); // 删除不再存在的神龙节点
} catch (Throwable t) {
logger.error("检查节点压力出错, cluster:{}", cluster, t);
} finally {
ThreadUtils.sleep(5000);
}
}

}

/**
* 一些神龙节点被回收,不再存在
*/
private void removeNoLongerExistNode() {
Map<String, Long> tempMap = shenlongNodeOverloadMap;
Set<String> keySet = tempMap.keySet();
for (String key : keySet) {
if (!shenlongNodeResMap.containsKey(key)) {
shenlongNodeOverloadMap.remove(key);
}
}
}

@Override
public void setCluster(String cluster) {
this.cluster = cluster;
}

@Override
public boolean canScheduleNormalPod(int timeLimit) {
return shenlongPodRequestCpuTotal < shenlongNodeRequestCpuThreshold;
}

/**
* 暂时只有超时的情况,不可调度。 此处针对把普通pod调度到神龙节点。
*
* @return
*/
@Override
public List<String> getNoSchedulableNodes() {
return new ArrayList<>(shenlongNodeOverloadMap.keySet());
}

/**
* 处理神龙pod调度策略
*
* @param podCreateStrategy
*/
@Override
public void processPodCreateStrategy(PodCreateStrategy podCreateStrategy, String containers) {
boolean shenlong = containers.contains(appConfig.getShenlongImageCharacter());// 可在上一层处理
if (!shenlong) {
return;
}

List<NodeRes> list = new ArrayList<>(shenlongNodeResMap.values());
if (list.size() <= 1) {
return;
}
Collections.sort(list, new Comparator<NodeRes>() {
@Override
public int compare(NodeRes o1, NodeRes o2) {
return o1.getRequestCpuRate().compareTo(o2.getRequestCpuRate());
}
});

// bridge规模扩大时,必要改为集中分配
double requestCpu = ContainerUtil.getRequestCpu(containers);
List<String> noList = new ArrayList<>();
for (int i = list.size() - 1; i > 0; i--) {
NodeRes higher = list.get(i);
NodeRes least = list.get(0);

double unAffinityCpu = requestCpu + higher.getUnAffinityCpu();
// allocatableCpu 应该取较大值。
// k8s是整体调度的,可能把很多神龙pod调度到资源较小的节点,普通pod调度到资源较大的节点。这时候更加需要把神龙pod往资源较大节点分配。
// 例如把3个神龙pod分配到8c节点,32c节点一个神龙pod都没有。
double allocatableCpu = Math.max(higher.getAllocatableCpu(), least.getAllocatableCpu());
// 当前是2台bridge节点,每台可以调节50%的量, 再乘0.8是因为pod本来倾向于分配到较小节点
if (allocatableCpu * (higher.getRequestCpuRate() - least.getRequestCpuRate()) * 0.5 * 0.8 > unAffinityCpu) {
noList.add(higher.getNodeName());
higher.addUnAffinityCpu(requestCpu);
}
}

// 此处是针对神龙 pod
podCreateStrategy.setNoSchedulableShenlongNodes(noList);

}

@Override
public boolean processCreatePodResult(CreatePodResult result) {
String nodeName = K8sUtils.getNodeName(result.getPod());
if (StringUtils.isBlank(nodeName)) {
return false;// 调度失败,连节点都没有
}

if (!shenlongNodeResMap.containsKey(nodeName)) { // 不是神龙节点
return false;
}

if (Boolean.FALSE.equals(result.getSuccess())
&& result.getMillisecondCost() >= sysConfigService.getCreatePodCostMaxTime()) {
shenlongNodeOverloadMap.put(nodeName,
System.currentTimeMillis() + sysConfigService.getShenlongNodeOverloadExpireTime());
// k8sService.updateNodeLabel(cluster, nodeName, "type", BridgeNodeCsts.NODE_LABEL_TYPE_UNDER_PRESSURE);
logger.info("创建pod {} 超时 {}s,神龙节点{}超时状态开始, cluster:{}",
K8sUtils.getPodName(result.getPod()), result.getMillisecondCost() / 1000, nodeName, cluster);
}

return true;

}

@Override
public void stop() {
terminated = true;
}
}

+ 67
- 0
common/src/main/java/com/imitate/common/k8s/pojo/BridgePod.java View File

@@ -0,0 +1,67 @@
package com.imitate.common.k8s.pojo;


import com.imitate.common.util.AbstractDO;
import lombok.Data;
import lombok.EqualsAndHashCode;

import javax.persistence.Table;
import java.time.LocalDateTime;



@Data
@EqualsAndHashCode(callSuper = false)
@Table(name = "bridge_pod")
public class BridgePod extends AbstractDO {
private String name;
private String tpiID;
private String buildID;

private String uid;

private LocalDateTime k8sCreateTime;
private LocalDateTime deleteTime;

private String secKey;
private LocalDateTime requestTime;
private Double pull;
private Double createPod;
private Double execute;
private Double evaluateAllTime;

private String nodeName;
private String nodeIp;

private String downloadStatus;
private String createPodStatus;

public static final String CREATE_POD_STATUS_SUCCESS = "1";

public static final String CREATE_POD_STATUS_FAIL = "0";

private String compileStatus;
private String runStatus;

public static final String RUN_STATUS_FAIL = "-1";
public static final String RUN_STATUS_SUCCESS = "0";
public static final String RUN_STATUS_EXEC_FAIL = "1";
public static final String RUN_STATUS_TIMEOUT = "2";
public static final String RUN_STATUS_OTHERS_FAIL = "3";

private String status;

private String imageName;

private String imageVersion;

private Double cpuLimit;

private Integer memoryLimit;

private Double cpuRequest;

private Integer memoryRequest;


}

+ 40
- 0
common/src/main/java/com/imitate/common/k8s/pojo/ErrorPodInfo.java View File

@@ -0,0 +1,40 @@
package com.imitate.common.k8s.pojo;

import com.imitate.common.util.AbstractDO;
import lombok.Data;
import lombok.EqualsAndHashCode;

import javax.persistence.Table;
import java.time.LocalDateTime;

/**
* @author huqifeng
* @Time 2021-8-9
* @Description pod创建超时后保存的错误pod信息
*/
@Data
@EqualsAndHashCode(callSuper = false)
@Table(name = "error_pod_info")
public class ErrorPodInfo extends AbstractDO {
private LocalDateTime errorTime;
private String podName;
private String nodeIp;
private String tpiID;
private String buildID;
private String podPhase;
private String podStatusReason;
private String podStatusMessage;
private String podConditionType;
private String podConditionStatus;
private String podConditionReason;
private String podConditionMessage;
private String containerStatusReady;
private String containerStatusWaiting;
private String containerStatusWaitingReason;
private String containerStatusWaitingMessage;
private String containerStatusTerminated;
private String containerStatusTerminatedReason;
private String containerStatusTerminatedMessage;
private String imageExist;

}

+ 74
- 0
common/src/main/java/com/imitate/common/k8s/pojo/EvaDayStat.java View File

@@ -0,0 +1,74 @@
package com.imitate.common.k8s.pojo;

import com.imitate.common.util.AbstractDO;
import lombok.Data;
import lombok.EqualsAndHashCode;

import javax.persistence.Table;

/**
* 评测每日统计
*/
@Data
@EqualsAndHashCode(callSuper = false)
@Table(name = "eva_day_stat")
public class EvaDayStat extends AbstractDO {


/**
* 统计日期,如20200101
*/
private Integer statDate;

/**
* 评测总数
*/
private Integer evaTotal;

/**
* 代码下载大于5秒数
*/
private Integer pullSlow;

/**
* 代码下载失败数
*/
private Integer pullFail;

/**
* 创建pod大于5秒数
*/
private Integer createPodSlow;

/**
* 创建pod失败数
*/
private Integer createPodFail;

/**
* 评测执行错误
*/
private Integer execFail;

/**
* 其它错误
*/
private Integer othersFail;

/**
* 评测错误比率: (execFail+othersFail)/evaTotal
*/
private Double evaFailRatio;

/**
* 评测超时数
*/
private Integer evaTimeout;

/**
* 评测超时比例
*/
private Double evaTimeoutRatio;


}

+ 56
- 0
common/src/main/java/com/imitate/common/k8s/pojo/OjEvaDayStat.java View File

@@ -0,0 +1,56 @@
package com.imitate.common.k8s.pojo;

import com.imitate.common.util.AbstractDO;
import lombok.Data;
import lombok.EqualsAndHashCode;

import javax.persistence.Table;

/**
* oj评测每日统计
*/
@Data
@EqualsAndHashCode(callSuper = false)
@Table(name = "oj_eva_day_stat")
public class OjEvaDayStat extends AbstractDO {


/**
* 统计日期,如20200101
*/
private Integer statDate;

/**
* 评测总数
*/
private Integer evaTotal;

/**
* 评测错误
*/
private Integer evaFail;

/**
* 评测错误率
*/
private Double evaFailRatio;

/**
* 评测超时
*/
private Integer evaTimeout;

/**
* 评测超时率
*/
private Double evaTimeoutRatio;

public OjEvaDayStat(Integer statDate, Integer evaTotal, Integer evaFail, Double evaFailRatio, Integer evaTimeout, Double evaTimeoutRatio) {
this.statDate = statDate;
this.evaTotal = evaTotal;
this.evaFail = evaFail;
this.evaFailRatio = evaFailRatio;
this.evaTimeout = evaTimeout;
this.evaTimeoutRatio = evaTimeoutRatio;
}
}

+ 29
- 0
common/src/main/java/com/imitate/common/k8s/pojo/PlatformConfig.java View File

@@ -0,0 +1,29 @@
package com.imitate.common.k8s.pojo;

import com.imitate.common.util.AbstractDO;
import lombok.Data;
import lombok.EqualsAndHashCode;

import javax.persistence.Table;
import java.time.LocalDateTime;


@Data
@EqualsAndHashCode(callSuper = false)
@Table(name = "platform_config")
public class PlatformConfig extends AbstractDO {

private String platform;

private String containers;

private LocalDateTime createTime;

private LocalDateTime updateTime;

private String script;

private String fileNameSuffix;


}

+ 78
- 0
common/src/main/java/com/imitate/common/k8s/pojo/RunPod.java View File

@@ -0,0 +1,78 @@
package com.imitate.common.k8s.pojo;


import com.imitate.common.util.AbstractDO;
import lombok.Data;
import lombok.EqualsAndHashCode;

import javax.persistence.Table;
import java.time.LocalDateTime;


@Data
@Table(name = "run_pod")
public class RunPod extends AbstractDO {


private String name;

private String cluster;

private String imageName;

private Double cpuLimit;

private Integer memoryLimit;

private Double cpuRequest;

private Integer memoryRequest;

private Integer runPodType;

private String nodeIp;

private Long priority;

private String createBy;

private String svcPort;

private String sshPort;

public static final Long RUN_POD_PRIORITY_DEFAULT = 0L;

private LocalDateTime expireTime;




@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((super.getId() == null) ? 0 : super.getId().hashCode());
return result;
}

@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
RunPod other = (RunPod) obj;
if (super.getId() == null) {
if (other.getId() != null)
return false;
} else if (!super.getId().equals(other.getId()))
return false;
return true;
}

}

+ 30
- 0
common/src/main/java/com/imitate/common/k8s/pojo/SecurityContextConfig.java View File

@@ -0,0 +1,30 @@
package com.imitate.common.k8s.pojo;

import com.imitate.common.util.AbstractDO;
import lombok.Data;
import lombok.EqualsAndHashCode;

import javax.persistence.Table;
import java.time.LocalDateTime;

/**
* @author zmr
*/
@Data
@EqualsAndHashCode(callSuper = false)
@Table(name = "security_context_config")
public class SecurityContextConfig extends AbstractDO {

private String imageName;

private String cluster;

private Boolean privileged;

private String addCap;

private String dropCap;



}

+ 44
- 0
common/src/main/java/com/imitate/common/k8s/pojo/WindowsInfo.java View File

@@ -0,0 +1,44 @@
package com.imitate.common.k8s.pojo;

import com.imitate.common.util.AbstractDO;
import lombok.Data;
import lombok.EqualsAndHashCode;

import javax.persistence.Table;
import java.time.LocalDateTime;

/**
* windows实例信息
*/
@Data
@EqualsAndHashCode(callSuper = false)
@Table(name = "windows_info")
public class WindowsInfo extends AbstractDO {


private String uniqId;

private String instanceId;

private String userID;

private String templateName;

private String port;

private String vncPort;

private String forwardTableId;

private String forwardEntryId;

private String vncForwardEntryId;

private LocalDateTime autoReleaseTime;

private Integer status;


}



+ 71
- 0
common/src/main/java/com/imitate/common/k8s/service/BridgeNodeService.java View File

@@ -0,0 +1,71 @@
package com.imitate.common.k8s.service;


import com.imitate.common.k8s.bean.BridgeNode;
import com.imitate.common.k8s.bean.NodeQueryParam;
import io.fabric8.kubernetes.api.model.Node;
import io.fabric8.kubernetes.api.model.NodeAddress;
import io.fabric8.kubernetes.api.model.Pod;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class BridgeNodeService {

@Autowired
private K8sService k8sService;

public List<BridgeNode> getBridgePods(NodeQueryParam param) {
Map<String, List<Pod>> nodePodMap = this.getNodePods(param.getCluster());

List<Node> nodeList = k8sService.getNodes(param);

List<BridgeNode> list = new ArrayList<>(nodeList.size());
for (Node node : nodeList) {
BridgeNode bn = new BridgeNode();
bn.setName(node.getMetadata().getName());
// ip
List<NodeAddress> addrs = node.getStatus().getAddresses();
for (NodeAddress na : addrs) {
if ("InternalIP".equals(na.getType())) {
bn.setIp(na.getAddress());
break;
}
}
// 创建时间
String createTime = node.getMetadata().getCreationTimestamp();
if (createTime.endsWith("Z")) {
createTime = createTime.substring(0, createTime.length() - 1);
}
bn.setCreateTime(LocalDateTime.parse(createTime));
// pod数量
List<Pod> podList = nodePodMap.get(bn.getIp());
bn.setPodNum(podList == null ? 0 : podList.size());

list.add(bn);
}
return list;

}

private Map<String, List<Pod>> getNodePods(final String cluster) {
Map<String, List<Pod>> map = new HashMap<>();
List<Pod> list = k8sService.getPods(cluster);
for (Pod pod : list) {
String hostIp = pod.getStatus().getHostIP();
List<Pod> podList = map.get(hostIp);
if (podList == null) {
podList = new ArrayList<>();
map.put(hostIp, podList);
}
podList.add(pod);
}
return map;
}
}

+ 119
- 0
common/src/main/java/com/imitate/common/k8s/service/BridgePodService.java View File

@@ -0,0 +1,119 @@
package com.imitate.common.k8s.service;

import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageHelper;
import com.imitate.common.k8s.bean.*;
import com.imitate.common.k8s.constant.BridgePodCsts;
import com.imitate.common.k8s.mapper.BridgePodMapper;
import com.imitate.common.k8s.pojo.EvaDayStat;
import com.imitate.common.k8s.pojo.*;
import com.imitate.common.util.TpUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;

@Service
public class BridgePodService {
@Autowired
private BridgePodMapper bridgePodMapper;

public List<BridgePod> getBridgePods(PodQueryParam param) {

PageHelper.startPage(param.getPageNum(), param.getPageSize());
return bridgePodMapper.selectBridgePod(param);
}

public BridgePod createBridgePod(String name, String tpiID, String buildID, LocalDateTime requestTime, String secKey) {
BridgePod bridgePod = new BridgePod();
bridgePod.setName(name);
bridgePod.setTpiID(tpiID);
bridgePod.setBuildID(buildID);
bridgePod.setSecKey(secKey);
bridgePod.setRequestTime(requestTime);
bridgePod.setStatus(BridgePodCsts.STATUS_BEGIN);

bridgePodMapper.insert(bridgePod);
return bridgePod;
}

public void updateBridgeInfo(JSONObject buildParams, TimeCost timeCost, BuildResult result) {
BridgePod bridgePod = new BridgePod();
bridgePod.setId(buildParams.getLong("bridgePodId"));
String podName = buildParams.getString("podName");
bridgePod.setName(podName);
bridgePod.setNodeName(buildParams.getString("nodeName"));
bridgePod.setNodeIp(buildParams.getString("nodeIp"));

// image info
JSONObject mainContainer = buildParams.getJSONObject("mainContainer");
bridgePod.setImageName(mainContainer.getString("imageName"));
bridgePod.setImageVersion(mainContainer.getString("imageVersion"));
bridgePod.setCpuLimit(Double.parseDouble(mainContainer.getString("cpuLimit")));
Integer memoryLimit = Integer.parseInt(mainContainer.getString("memoryLimit").replace("M", ""));
bridgePod.setMemoryLimit(memoryLimit);
bridgePod.setCpuRequest(Double.parseDouble(mainContainer.getString("cpuRequest")));
Integer memoryRequest = Integer.parseInt(mainContainer.getString("memoryRequest").replace("M", ""));
bridgePod.setMemoryRequest(memoryRequest);

// 下载代码和创建pod
String pullTimeStr = timeCost.getPull();
Double pullTime = StringUtils.isNotEmpty(pullTimeStr) ? Double.parseDouble(pullTimeStr) : null;
bridgePod.setPull(pullTime);

String createPodStr = timeCost.getCreatePod();
Double createPod = StringUtils.isNotEmpty(createPodStr) ? Double.parseDouble(createPodStr) : null;
bridgePod.setCreatePod(createPod);

String createTime = buildParams.getString("k8sCreateTime");
if (StringUtils.isNotEmpty(createTime)) {
if (createTime.endsWith("Z")) {
createTime = createTime.substring(0, createTime.length() - 1);
}
LocalDateTime time = LocalDateTime.parse(createTime);
// 转化为东八区时间
if (time.isBefore(LocalDateTime.now().plusHours(1))) {
time.plusHours(8);
}
bridgePod.setK8sCreateTime(time);

String uid = time.format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")) + "-" + TpUtils.getTpiID(podName);
bridgePod.setUid(uid);
}

// 评测时间数据
String execute = timeCost.getExecute();
Double takeTime = execute == null ? null : Double.parseDouble(execute);
bridgePod.setExecute(takeTime);

bridgePod.setEvaluateAllTime(Double.parseDouble(timeCost.getEvaluateAllTime()));

bridgePod.setDownloadStatus(result.getDownloadStatus());
bridgePod.setCreatePodStatus(result.getCreatePodStatus());
bridgePod.setCompileStatus(result.getCompileSuccess());
String evaFailStatus = buildParams.getString("evaFailStatus");
if (StringUtils.isNotEmpty(evaFailStatus)) {
bridgePod.setRunStatus(evaFailStatus);
} else {
bridgePod.setRunStatus(result.getStatus());
}
bridgePod.setStatus(BridgePodCsts.STATUS_END);

bridgePodMapper.updateByPrimaryKeySelective(bridgePod);
}

public void deleteHisBridgePod(LocalDateTime deleteTime) {
bridgePodMapper.deleteByRequestTime(deleteTime);
}

public EvaDayStat doEvaDayStat(Integer date) {
return bridgePodMapper.countEvaDayStat(date);
}

public List<NodeEvaErrorInfo> getNodeEvaErrorInfos(LocalDateTime requestTime) {
return bridgePodMapper.selectNodeEvaErrorInfos(requestTime);
}
}

+ 157
- 0
common/src/main/java/com/imitate/common/k8s/service/DiskService.java View File

@@ -0,0 +1,157 @@
package com.imitate.common.k8s.service;


import com.imitate.common.constant.TpCsts;
import com.imitate.common.sys.settings.AppConfig;
import org.apache.commons.lang3.math.NumberUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.io.File;

/**
* 磁盘相关service
*
* @author 威少
*/
@Service
public class DiskService {

@Autowired
private AppConfig appConfig;

/**
* 文件类型实际输出所在文件夹名
*/
public static final String TEST_CASE_ACTUAL_OUT_FILE_FOLDER = "filecase";
/**
* 平台通用文件所在文件夹名
*/
public static final String PLATFORM_FILE_FOLDER = "platform";
/**
* 保护文件所在文件夹名
*/
public static final String PROTECT_FILE_FOLDER = "protect";
/**
* 私密版本库所在文件夹名
*/
public static final String SECRET_FILE_FOLDER = "secret";
/**
* TPI工作目录文件夹名前缀
*/
public static final String TPI_WORKSPACE_FOLDER_PREFIX = "myshixun_";

/**
* 获取工作目录在bridge节点挂载目录的名称
*/
public String getWorkspaceHostPath(String tpiID) {
// 分盘逻辑,对磁盘个数取余,使落到对应的盘
String[] workspaceNFSConfigs = getWorkspaceNFSConfigs();
int workspacesSize = workspaceNFSConfigs.length;
return workspaceNFSConfigs[(int)(NumberUtils.toLong(tpiID, 0) % workspacesSize)];
}

/**
* 对pod名字取hashcode取余决定盘
*/
public String getWorkspaceHostPathByPodName(String podName) {
String[] workspaceNFSConfigs = getWorkspaceNFSConfigs();
int index = (int)(podName.charAt(podName.length() - 1)) % workspaceNFSConfigs.length;
return workspaceNFSConfigs[index];
}

/**
* 获取TPI在bridge节点的工作目录
*/
public String getTpiWorkspaceHostPath(String tpiID) {
String workspace = getWorkspaceHostPath(tpiID);
return workspace + File.separator + TPI_WORKSPACE_FOLDER_PREFIX + tpiID;
}


/**
* 获取TPI 测试用例在bridge节点的host path
*/
public String getTpiTestCaseActualOutHostPath(String tpiID) {
String testCaseActualOutHostPath = getWorkspaceHostPath(tpiID) + File.separator + TEST_CASE_ACTUAL_OUT_FILE_FOLDER;
return StringUtils.isEmpty(tpiID) ? testCaseActualOutHostPath : testCaseActualOutHostPath + File.separator + tpiID;
}

/**
* 获取私密版本库工作目录
*/
public String getTpiSecretWorkspace(String tpiID) {
return getWorkspaceHostPath(tpiID) + File.separator + SECRET_FILE_FOLDER + File.separator + TPI_WORKSPACE_FOLDER_PREFIX + tpiID + File.separator + TpCsts.TP_UNIFY_REPO_NAME;
}

// ------------------------ 所有build的方法用给定的目录作为基础目录 ------------------------
/**
* 构建数据集存放路径
*/
public String buildTpDataHostPath(String basePath, String identifier) {
return basePath + File.separator + identifier;
}

/**
* 构建平台固定脚本等存放的路径
*/
public String buildTpiPlatformHostPath(String workspaceHostPath) {
return workspaceHostPath + File.separator + PLATFORM_FILE_FOLDER +
File.separator + "eva";
}

/**
* 构建工作目录
*/
public String buildTpiWorkspace(String workspace, String tpiID) {
return workspace + File.separator + TPI_WORKSPACE_FOLDER_PREFIX + tpiID;
}

/**
* 构建保护工作空间, 存放评测执行脚本等
*/
public String buildTpiProtectSpace(String workspace, String tpiID) {
return workspace + File.separator + PROTECT_FILE_FOLDER + File.separator + TPI_WORKSPACE_FOLDER_PREFIX + tpiID;
}

/**
* 构建TPI版本库路径
*/
public String buildTpiRepoPath(String tpiWorkspace, String tpiRepoName) {
return tpiWorkspace + File.separator + tpiRepoName;
}

/**
* 构建私密版本库路径
*/
public String buildSecretRepoSpace(String tpiRepoPath, String secretDir) {
return tpiRepoPath + File.separator + secretDir;
}

/**
* 构建TPM测试用例目录
*/
public String buildTpmTestCaseHostPath(String testCaseHostPath, String tpmIdentifier) {
if (StringUtils.isEmpty(tpmIdentifier)) {
return testCaseHostPath;
}
return testCaseHostPath + File.separator + tpmIdentifier;
}

/**
* 构建TPI测试用例的容器内挂载路径
*/
public String buildTpiTestCaseActualOutMountPath(String workspace) {
return workspace + File.separator + TEST_CASE_ACTUAL_OUT_FILE_FOLDER;
}

/**
* 取所有工作目录盘
*/
public String[] getWorkspaceNFSConfigs() {
String workspaceNFSConfig = appConfig.getWorkspaceNFSConfigs();
return workspaceNFSConfig.split(",");
}

}

+ 19
- 0
common/src/main/java/com/imitate/common/k8s/service/EvaDayStatService.java View File

@@ -0,0 +1,19 @@
package com.imitate.common.k8s.service;


import com.imitate.common.k8s.mapper.EvaDayStatMapper;
import com.imitate.common.k8s.pojo.EvaDayStat;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class EvaDayStatService {

@Autowired
private EvaDayStatMapper evaDayStatMapper;

public void insert(EvaDayStat evaDayStat) {
evaDayStatMapper.insertSelective(evaDayStat);
}

}

+ 1330
- 0
common/src/main/java/com/imitate/common/k8s/service/K8sService.java
File diff suppressed because it is too large
View File


+ 120
- 0
common/src/main/java/com/imitate/common/k8s/service/NodeResUsageService.java View File

@@ -0,0 +1,120 @@
package com.imitate.common.k8s.service;


import com.imitate.common.constant.TpCsts;
import com.imitate.common.k8s.mgr.ClusterManager;
import com.imitate.common.k8s.bean.ClusterInfo;
import com.imitate.common.bean.ShellResult;
import com.imitate.common.util.ShellUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;

/**
* k8s节点资源使用信息服务
*/
@Component
public class NodeResUsageService {

private final Logger logger = LoggerFactory.getLogger(getClass());

// Map<cluster, Map<nodeName, cpuPercent>>
private volatile Map<String, Map<String, Integer>> nodeCpuUsageRateMap = new HashMap<>();

@Autowired
private ClusterManager clusterManager;

public void refreshNodeResUsage() {
Map<String, Map<String, Integer>> tmpMap = new HashMap<>();
Map<String, ClusterInfo> clusterMap = clusterManager.getClusterInfo();
for (ClusterInfo cInfo : clusterMap.values()) {
String cluster = cInfo.getClusterConfig().getName();

// 加timeout避免某个集群网络缓慢等问题。可考虑集群各自管理
String cmd = "timeout 2 kubectl --kubeconfig=" + cInfo.getClusterConfig().getKubeconfig()
+ " top node | awk '{print $1,$2,$3,$4,$5}'";
ShellResult result = ShellUtil.executeAndGetExitStatus(cmd, 1);
if (result.getExitStatus() == 0) {
String resUsageOut = result.getOut();
Map<String, Integer> resUsageMap = getNewNodeResUsageMap(cluster, resUsageOut);
tmpMap.put(cluster, resUsageMap);
}
}

nodeCpuUsageRateMap = tmpMap;
}

public Integer getNodeCpuUsageRate(String cluster, String nodeName) {

Map<String, Integer> resUsageMap = nodeCpuUsageRateMap.get(cluster);
if (resUsageMap == null) {
logger.info("集群资源使用率尚未统计, cluster:{}, nodeName: {}", cluster, nodeName);
return TpCsts.NODE_CPU_USAGE_UNKNOWN;
} else {
Integer nodeCpuUsageRate = resUsageMap.get(nodeName);
if (nodeCpuUsageRate == null) {
logger.info("未获取到节点cpu使用率 , cluster:{}, nodeName: {}", cluster, nodeName);
return TpCsts.NODE_CPU_USAGE_UNKNOWN;
}
return nodeCpuUsageRate;
}

}

private Map<String, Integer> getNewNodeResUsageMap(String cluster, String resUsageOut) {
Map<String, Integer> newNodeResUsageMap = new HashMap<>();
String[] nodeResUsages = resUsageOut.split(System.getProperty("line.separator"));
for (int i = 1; i < nodeResUsages.length; i++) {
String nodeResUsage = nodeResUsages[i];
String[] infos = nodeResUsage.split(" ");
String nodeName = infos[0];
String nodeCpuUsageStr = infos[2];
String nodeMemoryUsageStr = infos[4];
int nodeCpuUsage=0;
int nodeMemoryUsage;
// kubectl top 会偶尔出现获取资源数据为 <unknown> 的情况
if (!"<unknown>".equals(nodeCpuUsageStr)) {
try{
nodeCpuUsage = Integer.parseInt(nodeCpuUsageStr.replace("%", ""));
//若k8s节点cpu使用率超过90%,钉钉报警
if( nodeCpuUsage>90 )
{
String message = "k8s节点:"+nodeName+",cpu使用率为:"+nodeCpuUsageStr+",服务器cpu繁忙";
}
newNodeResUsageMap.put(nodeName, nodeCpuUsage);
}
catch ( Exception e )
{
logger.error( "执行kubectl top node命令返回的结果中cpu数据不合法,nodeCpuUsage:{}",nodeCpuUsageStr,e);
}
if( !"<unknown>".equals(nodeMemoryUsageStr) )
{
try{
nodeMemoryUsage = Integer.parseInt(nodeMemoryUsageStr.replace("%", ""));
//若k8s节点内存使用率超过90%,钉钉报警
if( nodeMemoryUsage>90 )
{
String message = "k8s节点:"+nodeName+",内存使用率为:"+nodeMemoryUsageStr+",服务器内存即将耗尽";
}
}
catch ( Exception e )
{
logger.error( "执行kubectl top node命令返回的结果中memory数据不合法,nodeMemoryUsage:{}",nodeMemoryUsageStr,e);
}
}
} else {
// 使用该节点上次获取到的cpu使用信息
Map<String, Integer> resUsageMap = nodeCpuUsageRateMap.get(cluster);
if (resUsageMap != null && resUsageMap.get(nodeName) != null) {
nodeCpuUsage = resUsageMap.get(nodeName);
newNodeResUsageMap.put(nodeName, nodeCpuUsage);
}
}
}
return newNodeResUsageMap;
}
}

+ 54
- 0
common/src/main/java/com/imitate/common/k8s/service/OjEvaDayStatService.java View File

@@ -0,0 +1,54 @@
package com.imitate.common.k8s.service;


import com.imitate.common.k8s.mapper.OjEvaDayStatMapper;
import com.imitate.common.k8s.bean.BuildResult;
import com.imitate.common.k8s.pojo.OjEvaDayStat;
import com.imitate.common.util.JedisUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

@Service
public class OjEvaDayStatService {

@Autowired
private OjEvaDayStatMapper ojEvaDayStatMapper;

private static final String OJ_EVA_TOTAL_REDIS_KEY = "oj_total_";
private static final String OJ_EVA_FAIL_REDIS_KEY = "oj_fail_";
private static final String OJ_EVA_TIMEOUT_REDIS_KEY = "oj_timeout_";

public void ojEvaDayStat(Integer statDate) {
String totalStr = JedisUtil.get(OJ_EVA_TOTAL_REDIS_KEY + statDate);
Integer total = StringUtils.isEmpty(totalStr) ? 0 : Integer.parseInt(totalStr);

String failStr = JedisUtil.get(OJ_EVA_FAIL_REDIS_KEY + statDate);
Integer fail = StringUtils.isEmpty(failStr) ? 0 : Integer.parseInt(failStr);

String timeoutStr = JedisUtil.get(OJ_EVA_TIMEOUT_REDIS_KEY + statDate);
Integer timeout = StringUtils.isEmpty(timeoutStr) ? 0 : Integer.parseInt(timeoutStr);

double failRatio = total == 0 ? 0 : fail / (double) total;
double timeoutRatio = total == 0 ? 0 : timeout / (double) total;

OjEvaDayStat ojEvaDayStat = new OjEvaDayStat(statDate, total, fail, failRatio, timeout, timeoutRatio);

ojEvaDayStatMapper.insertSelective(ojEvaDayStat);
}

public void ojEvaStat(String status, boolean isCodeExecuteFail) {
Integer statDate = Integer.parseInt(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")));
JedisUtil.incrBy(OJ_EVA_TOTAL_REDIS_KEY + statDate, 1);
if (BuildResult.Status.RUN_TIMEOUT.getValue().equals(status)) {
JedisUtil.incrBy(OJ_EVA_TIMEOUT_REDIS_KEY + statDate, 1);
return;
}
if (BuildResult.Status.EXECUTE_ERROR.getValue().equals(status) && !isCodeExecuteFail) {
JedisUtil.incrBy(OJ_EVA_FAIL_REDIS_KEY + statDate, 1);
}
}
}

+ 59
- 0
common/src/main/java/com/imitate/common/k8s/service/PlatformConfigService.java View File

@@ -0,0 +1,59 @@
package com.imitate.common.k8s.service;


import com.imitate.common.k8s.mapper.PlatformConfigMapper;
import com.imitate.common.k8s.pojo.PlatformConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
* 平台配置表
*/
@Service
public class PlatformConfigService {

private volatile static Map<String, PlatformConfig> platformConfigMap = new HashMap<>();


@Autowired
private PlatformConfigMapper platformConfigMapper;

public void refreshPlatformConfig() {
Map<String, PlatformConfig> tmpMap = new HashMap<>();
List<PlatformConfig> pcs = platformConfigMapper.selectAllConfig();
for (PlatformConfig pc : pcs) {
String platform = pc.getPlatform();
tmpMap.put(platform, pc);
}

platformConfigMap = tmpMap;
}

public PlatformConfig getPlatformConfig(String platform) {
PlatformConfig pc = platformConfigMap.get(platform);
if (pc == null) {
throw new RuntimeException("不支持的平台:" + platform);
}
return pc;
}

public Set<String> getAllPlatforms() {
return platformConfigMap.keySet();
}

public void savePlatformConfig(PlatformConfig pc) {
platformConfigMapper.insertSelective(pc);
}

public void updatePlatformConfig(PlatformConfig pc) {
platformConfigMapper.updateByPrimaryKeySelective(pc);
}



}

+ 110
- 0
common/src/main/java/com/imitate/common/k8s/service/PortService.java View File

@@ -0,0 +1,110 @@
package com.imitate.common.k8s.service;


import com.imitate.common.k8s.util.K8sUtils;
import com.imitate.common.sys.constant.SysConfigCsts;
import com.imitate.common.sys.pojo.SysConfig;
import com.imitate.common.sys.service.SysConfigService;
import com.imitate.common.sys.settings.AppConfig;
import com.imitate.common.util.JedisUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class PortService {
private Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
private SysConfigService sysConfigService;

@Autowired
private K8sService k8sService;

@Autowired
private AppConfig appConfig;

@Transactional
public int allocatePort(String usablePortTypeKey,int k8sMinUsablePort,int k8sMaxUsablePort){
long port = JedisUtil.incrBy(usablePortTypeKey, 1);
if (port < k8sMinUsablePort) {
return this.initPort(port, usablePortTypeKey,k8sMinUsablePort);
}
if (port >= k8sMaxUsablePort) {
logger.info("分配的port {} 达到上限 {},等待端口重置后重新分配", port, k8sMaxUsablePort);

SysConfig configParam = new SysConfig();
configParam.setName(SysConfigCsts.CONFIG_PORT_RESET);
configParam.setVal(appConfig.getBridgeInstanceName());// 暂时写死
SysConfig sysConfig = null;
try {
sysConfig = sysConfigService.lockSysConfig(configParam);
if (sysConfig != null) {// 成功获得锁
port = JedisUtil.incrBy(usablePortTypeKey, 1);
if (port >= k8sMaxUsablePort) {
logger.info("分配的port {} 达到上限 {},已经锁定端口重置锁,将重置端口到最小可用值", port, k8sMaxUsablePort);
JedisUtil.set(usablePortTypeKey, k8sMinUsablePort + "");
port = JedisUtil.incrBy(usablePortTypeKey, 1);
}
} else {// 没有获得锁,那么是被其它任务锁定,并且重置了端口
port = JedisUtil.incrBy(usablePortTypeKey, 1);
}
} catch (Exception e) {
logger.error("重置端口错误", e);
} finally {
if (sysConfig != null) {
sysConfigService.releasSysConfigLock(configParam);
}
}

}
return (int) port;
}



@Transactional
public int allocatePort(String usablePortTypeKey) {
int k8sMinUsablePort = sysConfigService.getK8sMinUsablePort();
int k8sMaxUsablePort = sysConfigService.getK8sMaxUsablePort();
return allocatePort(usablePortTypeKey,k8sMinUsablePort,k8sMaxUsablePort);
}


private int initPort(long port, String usablePortTypeKey,int k8sMinUsablePort) {
SysConfig configParam = new SysConfig();
configParam.setName(SysConfigCsts.CONFIG_PORT_RESET);
configParam.setVal(appConfig.getBridgeInstanceName());// 暂时写死
SysConfig sysConfig = null;
try {
sysConfig = sysConfigService.lockSysConfig(configParam);
if (sysConfig != null) {// 成功获得锁
port = JedisUtil.incrBy(usablePortTypeKey, 1);
if (port < k8sMinUsablePort) {
logger.info("分配的port {} 小于最小值 {},已经锁定端口重置锁,将重置端口到最小可用值", port, k8sMinUsablePort);
JedisUtil.set(usablePortTypeKey, k8sMinUsablePort + "");
port = JedisUtil.incrBy(usablePortTypeKey, 1);
}
} else {// 没有获得锁,那么是被其它任务锁定,并且重置了端口
port = JedisUtil.incrBy(usablePortTypeKey, 1);
}
} catch (Exception e) {
logger.error("重置端口错误", e);
} finally {
if (sysConfig != null) {
sysConfigService.releasSysConfigLock(configParam);
}
}

return (int) port;
}

public Integer getServicePort(final String cluster, String podName) {
io.fabric8.kubernetes.api.model.Service service = k8sService.getService(cluster, podName);
if (service != null) {
return K8sUtils.getNodePort(service);
}
return null;
}
}

+ 511
- 0
common/src/main/java/com/imitate/common/k8s/service/RunPodService.java View File

@@ -0,0 +1,511 @@
package com.imitate.common.k8s.service;

import com.alibaba.fastjson.JSONObject;

import com.imitate.common.constant.TpCsts;
import com.imitate.common.k8s.bean.CreatePodResult;
import com.imitate.common.k8s.bean.NodeResStat;
import com.imitate.common.k8s.bean.PodCreateStrategy;
import com.imitate.common.k8s.bean.RunPodQueryParam;
import com.imitate.common.k8s.mapper.RunPodMapper;
import com.imitate.common.k8s.mgr.ClusterManager;
import com.imitate.common.k8s.mgr.NodeManager;
import com.imitate.common.k8s.pojo.*;
import com.imitate.common.k8s.util.ContainerUtil;
import com.imitate.common.k8s.util.K8sPodCommandExecutor;
import com.imitate.common.k8s.util.K8sUtils;
import com.imitate.common.sys.service.SysConfigService;
import com.imitate.common.sys.settings.AppConfig;
import com.imitate.common.util.JedisUtil;
import com.imitate.common.util.ThreadUtils;
import com.imitate.common.util.TpUtils;
import io.fabric8.kubernetes.api.model.Pod;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import static com.imitate.common.sys.constant.SysConfigCsts.*;

@Service
public class RunPodService {
private Logger logger = LoggerFactory.getLogger(getClass());

public static final String DELETE_POD_REDIS_KEY = "delete_pod_key_";

public static final String DELETE_POD_REDIS_LOCK_KEY = "delete_pod_lock_key_";

@Autowired
private RunPodMapper runPodMapper;

@Autowired
private K8sService k8sService;

@Autowired
private AppConfig appConfig;

@Autowired
private SysConfigService sysConfigService;
@Autowired
private NodeManager nodeManager;
@Autowired
private ClusterManager clusterManager;

public List<RunPod> getRunPods(RunPodQueryParam param) {
return runPodMapper.selectRunPods(param);
}

/**
* 仅仅删除 RunPod记录
*
* @param podName
* @return
*/
public void deleteRunPodRecordOnly(String podName) {
runPodMapper.deleteByName(podName);
}

/**
* 如果更新成功返回RunPod,否则返回null
*
* @param podName
* @param delayTime
* @return
*/
public void deleteRunPodAfterTime(String podName, long delayTime) {
RunPod runPod = new RunPod();
runPod.setName(podName);
LocalDateTime now = LocalDateTime.now();
runPod.setUpdateTime(now);
LocalDateTime expireTime = now.plusSeconds(delayTime);
runPod.setExpireTime(expireTime);
runPodMapper.updateByNameSelective(runPod);
}

/**
* 延长runPod过期时间,当新过期时间大于旧过期时间才更新
*
* @param podName
* @param delayTime
* @return
*/
public boolean delayRunPodExpireTime(String podName, long delayTime) {
RunPod runPod = new RunPod();
runPod.setName(podName);
LocalDateTime now = LocalDateTime.now();
runPod.setUpdateTime(now);
LocalDateTime expireTime = now.plusSeconds(delayTime);
runPod.setExpireTime(expireTime);
int rowNum = runPodMapper.delayRunPodExpireTime(runPod);
return rowNum > 0;
}

public boolean deteleRunPod(RunPod runPod) {
// 常驻镜像或pod不予删除
if (sysConfigService.getLongLiveImage().contains(runPod.getImageName()) || sysConfigService.getLongLivePod().contains(runPod.getName())) {
return false;
}

//加redis锁
JedisUtil.setnx(DELETE_POD_REDIS_LOCK_KEY + runPod.getName(),runPod.getName());
int r = runPodMapper.deleteByNameExpired(runPod.getName(), LocalDateTime.now());
if(r > 0) {
try {
delK8sPod(runPod);
logger.info("pod 过期被删除,podName:{}", runPod.getName());
} catch (Exception e) {
logger.error("k8s 删除pod异常,将继续删除run_pod, podName: {}, cluster: {}", runPod.getName(), runPod.getCluster(), e);
}
}
//删除redis锁,释放锁
JedisUtil.del(DELETE_POD_REDIS_LOCK_KEY + runPod.getName());
return r > 0;
}

private void delK8sPod(RunPod runPod) {
String podName = runPod.getName();
String tpiID = TpUtils.getTpiID(podName);
String cluster = runPod.getCluster();

JedisUtil.psetex(DELETE_POD_REDIS_KEY + podName, podName, sysConfigService.getDeletePodRedisExpireTime());



try {
// 根据podName来删除pod
Boolean r = k8sService.deletePod(cluster, podName);
logger.info("删除k8s pod {} 结果: {}", podName, r);
r = k8sService.deleteServiceByTpiId(cluster, tpiID);
logger.info("删除k8s service {} 结果: {}", tpiID, r);
} catch(Exception ignore) {
}


}

public void deteleRunPodSync(final String cluster, String tpiId, String podName, Integer podType) {
// 必须是先删除记录,再删除pod;否则可能删除掉其它线程刚刚创建的记录,导致pod永远不会删除掉。
// TODO 可以优化,先查询pod,后面按照时间删除,如果时间已经更新,则不再删除,否则删除。
deleteRunPodRecordOnly(podName);

// 查看pod是否已经存在
Pod pod = k8sService.getPod(cluster, podName);
if (pod != null) {
String phase = pod.getStatus().getPhase();
// 特殊状态的pod只能立即删除,否则无法删除掉。此时node可能已经宕机
if ("Terminating".equals(phase) || "Unknown".equals(phase)) {
k8sService.deletePod(cluster, podName);
// 检查pod是否已成功删除,10秒内应该足够删除
int times = 10;
while (times-- > 0) {
if (k8sService.getPod(cluster, podName) == null) {
break;
}
ThreadUtils.sleep(1000);
}
} else {
// 同步删除pod
k8sService.deletePodSync(cluster, podName);
}
}
k8sService.deleteServiceByTpiId(cluster, tpiId);
logger.info("同步删除run_pod {} 完成", podName);
}

public CreatePodResult createRunPod(final String cluster, JSONObject buildParams, String tpiID, String type,
int createPodTimeLimit, int timeLimit, Boolean localNode, String bigDataFile) {
CreatePodResult createPodResult = new CreatePodResult();
String podName = type + "-" + tpiID;
try {
Pod pod = null;
Integer podType = buildParams.getInteger("podType");
if(delayRunPodExpireTime(podName, timeLimit + 60)) {
pod = k8sService.getRunningPod(cluster, podName, createPodTimeLimit);
} else {
RunPod runPod = this.getRunPodByName(podName);
if (runPod == null) {
JSONObject mainContainer = buildParams.getJSONObject("mainContainer");
insertRunPod(cluster, podName, mainContainer, podType, RunPod.RUN_POD_PRIORITY_DEFAULT, timeLimit + 60);
} else {
pod = k8sService.getRunningPod(cluster, podName, createPodTimeLimit);
}
}
if (pod == null) {
boolean canToShenlong = Boolean.FALSE;
boolean canToGpu = Boolean.FALSE;
boolean canToOj = Boolean.FALSE;
if (nodeManager.isCommonPod(podName, buildParams)) {
canToShenlong = nodeManager.canScheduleNormalPodToShenlong(cluster, timeLimit);
canToGpu = nodeManager.canScheduleNormalPodToGpu(cluster, timeLimit);
canToOj = nodeManager.canScheduleNormalPodToOj(cluster, timeLimit);
}
List<String> noList = nodeManager.getNoSchedulableNodes(cluster);
PodCreateStrategy podCreateStrategy = new PodCreateStrategy().setTimeLimit(createPodTimeLimit)
.setNormalPodCanShenlong(canToShenlong).setNormalPodCanGpu(canToGpu).setNormalPodCanOj(canToOj).setNoSchedulableNodes(noList)
.setPodNoSchedulableWeight(sysConfigService.getPodNoSchedulableWeight())
.setAutoscaleNodeWeight(clusterManager.getScaleNodeWeight(cluster));

//读redis锁
boolean deleteRedisLock = StringUtils.isNotEmpty(JedisUtil.get(RunPodService.DELETE_POD_REDIS_LOCK_KEY + podName));
//递归读锁,阻塞当前线程线程,等待其他线程释放锁
while (deleteRedisLock) {
deleteRedisLock = StringUtils.isNotEmpty(JedisUtil.get(RunPodService.DELETE_POD_REDIS_LOCK_KEY + podName));
}
//没有锁,或已经释放锁,可以创pod
createPodResult = k8sService.createPod(cluster, podName, tpiID, type, buildParams.getString("containers"),
podCreateStrategy, null, bigDataFile, null, buildParams.getString("buildID"),
buildParams.getString("tpmIdentifier"), buildParams.getBooleanValue("mountTestCaseDir"));
pod = createPodResult.getPod();
if (Boolean.TRUE.equals(createPodResult.getSuccess())) {// pod创建成功时,记录pod所在节点ip
String nodeIp = K8sUtils.getNodeIp(pod);
if (StringUtils.isNotEmpty(nodeIp)) {
updateRunPodNodeIp(podName, K8sUtils.getNodeIp(pod));
}
} else {
pod = null;
}
nodeManager.processCreatePodResult(cluster, createPodResult);
}
if (pod != null) {
// 按需创建端口映射svc
Integer needPortMapping = buildParams.getInteger("needPortMapping");
if (needPortMapping != null && needPortMapping != -1 && needPortMapping != 0) {
if (!k8sService.svcExist(cluster, podName)) {
Integer nodePort = buildParams.getInteger("nodePort");
logger.info("create run pod service, tipID: {}, needPort: {}, nodePort: {}", tpiID, needPortMapping,
nodePort);
k8sService.createService(cluster, podName, tpiID, needPortMapping, nodePort);
updateRunPodSvcPort(podName, nodePort.toString());
}
}
}
createPodResult.setPod(pod);
} catch (Exception e) {
logger.error("创建pod失败 tpiID: {}", tpiID, e);
createPodResult.setStatus(CreatePodResult.CREATE_POD_STATUS_FAIL_DELETE_NOW);
}

// 异常情况下记录当前状态
if (createPodResult.getPod() == null) {
k8sService.describePod(cluster, podName);
}

return createPodResult;
}
@Transactional
public Pod createJupyterPod(final String cluster, String podName, String tpiID, String baseName, String containers, Integer podType, Integer delayDeleteTime, String identifier) {
RunPod runPod = this.getRunPodForUpdate(podName);
if (runPod == null) {
JSONObject mainContainer = ContainerUtil.getMainContainer(containers);
this.insertRunPod(cluster, podName, mainContainer, podType, RunPod.RUN_POD_PRIORITY_DEFAULT, delayDeleteTime);
} else {
updateRunPod(runPod, delayDeleteTime);
}
// jupyter创建pod暂没处理超时!!!
PodCreateStrategy podCreateStrategy = new PodCreateStrategy().setNormalPodCanShenlong(false).setNormalPodCanOj(false)
.setAutoscaleNodeWeight(clusterManager.getScaleNodeWeight(cluster)).setTimeLimit(120);// jupyter允许创建耗时120s
Map<String, String> envs = Collections.singletonMap(JUPYTER_PW_ENV, RandomStringUtils.randomAlphanumeric(16));
CreatePodResult createPodResult = k8sService.createPod(cluster, podName, tpiID, baseName, containers, podCreateStrategy, envs, identifier, null, null);
Pod pod = createPodResult.getPod();
if (Boolean.TRUE.equals(createPodResult.getSuccess())) {// pod创建成功时,记录pod所在节点ip
String nodeIp = K8sUtils.getNodeIp(pod);
if (StringUtils.isNotEmpty(nodeIp)) {
updateRunPodNodeIp(podName, K8sUtils.getNodeIp(pod));
}
} else {
pod = null;
}
return pod;
}

@Transactional
public Pod createWebsshPod(final String cluster, String podName, String tpiID, String type, String containers,
Integer podType, Integer delayDeleteTime, String bigDataFile, Boolean createImage) {
RunPod runPod = this.getRunPodForUpdate(podName);
if (runPod == null) {
JSONObject mainContainer = ContainerUtil.getMainContainer(containers);
this.insertRunPod(cluster, podName, mainContainer, podType, RunPod.RUN_POD_PRIORITY_DEFAULT, delayDeleteTime);
} else {
updateRunPod(runPod, delayDeleteTime);
}
//设置pod创建的最长时间限制等于pod所需所有容器启动时间限制之和
int createPodTimeLimit = Math.max(ContainerUtil.getContainersStartTime(containers), 15);
// webssh创建pod暂没处理超时!!!
PodCreateStrategy podCreateStrategy = new PodCreateStrategy().setNormalPodCanShenlong(false).setNormalPodCanOj(false)
.setAutoscaleNodeWeight(clusterManager.getScaleNodeWeight(cluster)).setTimeLimit(createPodTimeLimit);
// 随机生成自定义pwd
CreatePodResult createPodResult = k8sService.createPod(cluster, podName, tpiID, type, containers, podCreateStrategy, Collections.singletonMap(WEBSSH_PW_ENV ,RandomStringUtils.randomAlphanumeric(16)), bigDataFile, createImage, null);
Pod pod = createPodResult.getPod();
if (Boolean.TRUE.equals(createPodResult.getSuccess())) {// pod创建成功时,记录pod所在节点ip
String nodeIp = K8sUtils.getNodeIp(pod);
if (StringUtils.isNotEmpty(nodeIp)) {
updateRunPodNodeIp(podName, K8sUtils.getNodeIp(pod));
}
} else {
pod = null;
}
return pod;
}

@Transactional
public Pod createVncPod(final String cluster, String podName, String tpiID, String baseName, String containers, Integer podType, Integer delayDeleteTime, String bigDataFile, Boolean createImage) {
RunPod runPod = this.getRunPodForUpdate(podName);
if (runPod == null) {
JSONObject mainContainer = ContainerUtil.getMainContainer(containers);
this.insertRunPod(cluster, podName, mainContainer, podType, RunPod.RUN_POD_PRIORITY_DEFAULT, delayDeleteTime);
} else {
updateRunPod(runPod, delayDeleteTime);
}
//设置pod创建的最长时间限制等于pod所需所有容器启动时间限制之和
int createPodTimeLimit= ContainerUtil.getContainersStartTime( containers );
createPodTimeLimit = Math.max(createPodTimeLimit, 15);
// vnc创建pod暂没处理超时!!!
PodCreateStrategy podCreateStrategy = new PodCreateStrategy().setNormalPodCanShenlong(Boolean.FALSE)
.setNormalPodCanOj(Boolean.FALSE)
.setPodNoSchedulableWeight(sysConfigService.getPodNoSchedulableWeight())
.setAutoscaleNodeWeight(clusterManager.getScaleNodeWeight(cluster))
.setTimeLimit(createPodTimeLimit);
nodeManager.processShenlongPodStrategy(cluster, podCreateStrategy, containers);
CreatePodResult createPodResult = k8sService.createPod(cluster, podName, tpiID, baseName, containers,
podCreateStrategy, Collections.singletonMap(VNC_PW_ENV, RandomStringUtils.randomAlphanumeric(16)), bigDataFile, createImage, null);
Pod pod = createPodResult.getPod();
if (Boolean.TRUE.equals(createPodResult.getSuccess())) {// pod创建成功时,记录pod所在节点ip
String nodeIp = K8sUtils.getNodeIp(pod);
if (StringUtils.isNotEmpty(nodeIp)) {
updateRunPodNodeIp(podName, K8sUtils.getNodeIp(pod));
}
} else {
pod = null;
}
return pod;
}

public RunPod getRunPodForUpdate(String podName) {
return runPodMapper.selectRunPodForUpdate(podName);
}

public RunPod getRunPodByName(String podName) {
return runPodMapper.selectByName(podName);
}
public RunPod getSshRunPodByTpiID(String tpiID) {
return runPodMapper.selectSshRunPodByTpiID(tpiID);
}

public RunPod insertRunPod(final String cluster, String podName, JSONObject mainContainer, Integer runPodType, Long priority, int timeLimit) {
RunPod runPod = new RunPod();
runPod.setName(podName);
runPod.setCluster(cluster);
runPod.setRunPodType(runPodType);
runPod.setPriority(priority);
runPod.setCreateBy(appConfig.getBridgeInstanceName());
runPod.setImageName(mainContainer.getString("imageName"));
runPod.setCpuLimit(Double.parseDouble(mainContainer.getString("cpuLimit")));
Integer memoryLimit = Integer.parseInt(mainContainer.getString("memoryLimit").replace("M", ""));
runPod.setMemoryLimit(memoryLimit);
runPod.setCpuRequest(Double.parseDouble(mainContainer.getString("cpuRequest")));
Integer memoryRequest = Integer.parseInt(mainContainer.getString("memoryRequest").replace("M", ""));
runPod.setMemoryRequest(memoryRequest);
LocalDateTime now = LocalDateTime.now();

runPod.setCreateTime(now);
runPod.setUpdateTime(now);
LocalDateTime expireTime = now.plusSeconds(timeLimit);
runPod.setExpireTime(expireTime);

runPodMapper.insertSelective(runPod);
return runPod;
}

private void updateRunPod(RunPod runPod, int timeLimit) {

RunPod param = new RunPod();
param.setId(runPod.getId());
LocalDateTime now = LocalDateTime.now();
param.setUpdateTime(now);
now = now.plusSeconds(timeLimit);
param.setExpireTime(now);

runPodMapper.updateByPrimaryKeySelective(param);
}

public void updateRunPodSvcPort(String podName, String svcPort) {
RunPodQueryParam param = new RunPodQueryParam();
param.setName(podName);
param.setSvcPort(svcPort);
runPodMapper.updatePortByName(param);
}

public void updateRunPodSshPort(String podName, String sshPort) {
RunPodQueryParam param = new RunPodQueryParam();
param.setName(podName);
param.setSshPort(sshPort);
runPodMapper.updatePortByName(param);
}

public void updateRunPodNodeIp(String podName, String nodeIp) {
RunPodQueryParam param = new RunPodQueryParam();
param.setName(podName);
param.setNodeIp(nodeIp);
runPodMapper.updatePortByName(param);
}
/**
* 统计run_pod
* @return
*/
public List<NodeResStat> statNodeRes() {
return runPodMapper.statNodeRes(null);
}

public Integer getServicePort(String podName) {
RunPod runPod = getRunPodByName(podName);
if (runPod != null) {
String port = runPod.getSvcPort();
if (StringUtils.isNotEmpty(port)) {
return Integer.parseInt(port);
}
}
return null;
}

public String getRunPodCluster(String tpiID, Integer podType) {
String podName = TpUtils.buildEvaPodName(tpiID, podType);
RunPod runPod = this.getRunPodByName(podName);
if (runPod != null) {
return runPod.getCluster();
}
return null;
}

public List<String> podNumStatGroupByNodeIp(String cluster) {
return runPodMapper.podNumStatGroupByNodeIp(cluster);
}

public List<RunPod> getRunPodsByNodeIp(String cluster, String nodeIp) {
RunPodQueryParam runPodQueryParam = new RunPodQueryParam();
runPodQueryParam.setCluster(cluster);
runPodQueryParam.setNodeIp(nodeIp);
return runPodMapper.selectRunPods(runPodQueryParam);
}

public void deleteRunPodByNodeIp(String cluster, String nodeIp) {
RunPodQueryParam runPodQueryParam = new RunPodQueryParam();
runPodQueryParam.setCluster(cluster);
runPodQueryParam.setExpireTime(LocalDateTime.now());
runPodQueryParam.setNodeIp(nodeIp);
runPodMapper.updateExpireTimeByNodeIp(runPodQueryParam);
}

/**
* 杀死运行中的评测进程
*/
public void killEvaProcess(String tpiID) {
List<Pod> podList = k8sService.getPodList(TpCsts.LOCAL_CLUSTER, TpCsts.TPI_ID, tpiID);
podList.forEach( pod ->
K8sPodCommandExecutor.execCommandInPod(pod.getMetadata().getName(), new String[]{"bash", "/data/platform/eva/kill.sh"}, 3)
);
}

@Transactional
public Pod createVscodePod(String cluster, String podName, String tpiID, String type, String containers, Integer podType, int delayDeleteTime, String bigDataFile, Boolean createImage) {
RunPod runPod = this.getRunPodForUpdate(podName);
if (runPod == null) {
JSONObject mainContainer = ContainerUtil.getMainContainer(containers);
this.insertRunPod(cluster, podName, mainContainer, podType, RunPod.RUN_POD_PRIORITY_DEFAULT, delayDeleteTime);
} else {
updateRunPod(runPod, delayDeleteTime);
}
//设置pod创建的最长时间限制等于pod所需所有容器启动时间限制之和
int createPodTimeLimit = Math.max(ContainerUtil.getContainersStartTime(containers), 15);

// vscode创建pod暂没处理超时!!!
PodCreateStrategy podCreateStrategy = new PodCreateStrategy().setNormalPodCanShenlong(false).setNormalPodCanOj(false)
.setAutoscaleNodeWeight(clusterManager.getScaleNodeWeight(cluster)).setTimeLimit(createPodTimeLimit);

CreatePodResult createPodResult = k8sService.createPod(cluster, podName, tpiID, type, containers, podCreateStrategy, null, bigDataFile, createImage, null);
Pod pod = createPodResult.getPod();
// pod创建成功时,记录pod所在节点ip
if (Boolean.TRUE.equals(createPodResult.getSuccess())) {
String nodeIp = K8sUtils.getNodeIp(pod);
if (StringUtils.isNotEmpty(nodeIp)) {
updateRunPodNodeIp(podName, K8sUtils.getNodeIp(pod));
}
} else {
pod = null;
}
return pod;
}
}

+ 42
- 0
common/src/main/java/com/imitate/common/k8s/service/SecurityContextService.java View File

@@ -0,0 +1,42 @@
package com.imitate.common.k8s.service;


import com.imitate.common.k8s.mapper.SecurityContextConfigMapper;
import com.imitate.common.k8s.pojo.SecurityContextConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class SecurityContextService {

private static final Logger logger = LoggerFactory.getLogger(SecurityContextService.class);

private volatile Map<String, SecurityContextConfig> securityContextConfigMap = new HashMap<>();

@Autowired
private SecurityContextConfigMapper securityContextConfigMapper;

public SecurityContextConfig getSecurityContextConfig(String cluster, String imageName) {
SecurityContextConfig config = securityContextConfigMap.get(imageName);
if (config != null && cluster.equals(config.getCluster())) {
logger.info("getSecurityContextConfig success, config: {}", config);
return config;
}
return null;
}

public void refreshSecurityContextConfigs() {
List<SecurityContextConfig> configs = securityContextConfigMapper.selectAll();
Map<String, SecurityContextConfig> securityContextConfigMapTemp = new HashMap<>();
for (SecurityContextConfig config : configs) {
securityContextConfigMapTemp.put(config.getImageName(), config);
}
securityContextConfigMap = securityContextConfigMapTemp;
}
}

+ 227
- 0
common/src/main/java/com/imitate/common/k8s/util/ContainerUtil.java View File

@@ -0,0 +1,227 @@
package com.imitate.common.k8s.util;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.imitate.common.k8s.bean.BridgeContainer;
import io.fabric8.kubernetes.api.model.*;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;

public final class ContainerUtil {
private static final Logger log = LoggerFactory.getLogger(ContainerUtil.class);
public static JSONObject getMainContainer(String containers) {
JSONArray jsonArray = JSONArray.parseArray(containers);
JSONObject mainContainer = jsonArray.getJSONObject(0);
for (int i = 0; i < jsonArray.size(); i++) {
JSONObject container = jsonArray.getJSONObject(i);
if ("main".equals(container.getString("type"))) {
mainContainer = container;
}
}
String image = mainContainer.getString("image");
String[] imageInfo = image.split(":");
String imageName = imageInfo[0];
String imageVersion = imageInfo.length > 1 ? imageInfo[1] : "";
mainContainer.put("imageName", imageName);
mainContainer.put("imageVersion", imageVersion);
return mainContainer;
}
public static BridgeContainer parseBridgeContainer(String container) {
BridgeContainer bc = new BridgeContainer();

JSONObject obj = JSONObject.parseObject(container);
bc.setName(obj.getString("imageName"));
bc.setImage(obj.getString("image"));
bc.setCpuLimit(Double.parseDouble(obj.getString("cpuLimit")));
bc.setCpuRequest(Double.parseDouble(obj.getString("cpuRequest")));
Double memoryLimit = Double.parseDouble(obj.getString("memoryLimit").replace("M", ""));
bc.setMemoryLimit(memoryLimit);
Double memoryRequest = Double.parseDouble(obj.getString("memoryRequest").replace("M", ""));
bc.setMemoryRequest(memoryRequest);

return bc;
}

public static double getRequestCpu(String containers) {

double sum = 0;
List<Container> cs = parseContainers(containers);
for (Container c:cs) {
String cpu = c.getResources().getRequests().get("cpu").getAmount();
try{
if( cpu!=null )
sum += Double.parseDouble(cpu);
}catch ( Exception e )
{
log.error( "web层传递的containers参数中的cpuRequest不合法,cpuRequest:{}",cpu,e );
}

}

return sum;

}

public static double getLimitCpu(String containers) {

double sum = 0;
List<Container> cs = parseContainers(containers);
for (Container c:cs) {
String cpu = c.getResources().getLimits().get("cpu").getAmount();
try{
if( cpu!=null )
sum += Double.parseDouble(cpu);
}catch ( Exception e )
{
log.error( "web层传递的containers参数中的cpuLimit不合法,cpuLimit:{}",cpu,e );
}
}

return sum;

}

public static double getRequestMemory(String containers) {

double sum = 0L;
List<Container> cs = parseContainers(containers);
for (Container c:cs) {
String memory = c.getResources().getRequests().get("memory").getAmount();
memory=memory.replaceAll( "M","" );
try{
sum += Double.parseDouble(memory);
}catch ( Exception e )
{
log.error( "web层传递的containers参数中的memoryRequest不合法,memoryRequest:{}",memory,e );
}
}

return sum;

}

public static double getLimitMemory(String containers) {

double sum = 0;
List<Container> cs = parseContainers(containers);
for (Container c:cs) {
String memory = c.getResources().getLimits().get("memory").getAmount();
memory=memory.replaceAll( "M","" );
try{
sum += Double.parseDouble(memory);
}catch ( Exception e )
{
log.error( "web层传递的containers参数中的memoryLimit不合法,memoryLimit:{}",memory,e );
}
}

return sum;

}

public static List<Container> parseContainers(String containers) {

JSONArray jsonArray = JSONArray.parseArray(containers);
List<Container> containerList = new ArrayList<>();
for (int i = 0; i < jsonArray.size(); i++) {
Container container = new Container();
JSONObject props = jsonArray.getJSONObject(i);
container.setName(props.getString("image").split(":")[0]);
container.setImage(props.getString("image"));

container.setImagePullPolicy("IfNotPresent");

Map<String, Quantity> limits = new HashMap<>(2);
limits.put("cpu", new Quantity(props.getString("cpuLimit")));
limits.put("memory", new Quantity(props.getString("memoryLimit")));

// 最低资源限制
Map<String, Quantity> requests = new HashMap<>(2);
requests.put("cpu", new Quantity(props.getString("cpuRequest")));
requests.put("memory", new Quantity(props.getString("memoryRequest")));

ResourceRequirements resourceRequirements = new ResourceRequirements(limits, requests);
container.setResources(resourceRequirements);
// 次类别设置启动脚本为不包含ssh启动命令的脚本
String cmdParams = props.getString("cmd_params");
if ("sub".equals(props.getString("type"))) {
container.setCommand(StringUtils.isNotEmpty(cmdParams) ? Arrays.asList(cmdParams.split(",")) : Collections.singletonList("/start2.sh"));
containerList.add(container);
} else {
if(StringUtils.isNotEmpty(cmdParams)){
container.setCommand(Arrays.asList(cmdParams.split(",")));
}
containerList.add(0, container);
}
}

return containerList;

}

public static void setLifecycleStartCommand(Container container, List<String> command) {
Lifecycle lifecycle = new Lifecycle();
Handler postStart = new Handler();
ExecAction exec = new ExecAction();
exec.setCommand(command);
postStart.setExec(exec);
lifecycle.setPostStart(postStart);
container.setLifecycle(lifecycle);
}

public static boolean imagesMatch(String containers, List<Container> containersList) {
List<String> images = getContainersImages(containers);
boolean match = false;
for (String image : images) {
for (Container container : containersList) {
match = false;
if (image.equals(container.getImage())) {
match = true;
break;
}
}
if (!match) {
return false;
}
}
return true;
}

private static List<String> getContainersImages(String containers) {
JSONArray jsonArray = JSONArray.parseArray(containers);
List<String> images = new ArrayList<>(jsonArray.size());
for (int i = 0; i < jsonArray.size(); i++) {
images.add(jsonArray.getJSONObject(i).getString("image"));
}
return images;
}

/**
* 获取实训所需容器启动时间之和
* @param containers 实训所需容器
* @return 实训所需容器启动时间之和
*/
public static int getContainersStartTime(String containers) {
JSONArray jsonArray = JSONArray.parseArray(containers);
int containersStartTime = 0;
for (int i = 0; i < jsonArray.size(); i++) {
try {
String startTime = jsonArray.getJSONObject(i).getString("startTime");
if (startTime != null) {
containersStartTime += Integer.parseInt(startTime);
} else {
containersStartTime += 15;
}
} catch (Exception e) {
log.error("web层传递的startTime参数不合法,containers参数:{}", containers, e);
}
}
return containersStartTime;
}

}

+ 30
- 0
common/src/main/java/com/imitate/common/k8s/util/GetPodErrorReasonUtil.java View File

@@ -0,0 +1,30 @@
package com.imitate.common.k8s.util;


import com.imitate.common.bean.ShellResult;
import com.imitate.common.util.ShellUtil;

/**
* @author huqifeng
* @Time 2021-7-23
* @Description 当k8s pod出现问题时,执行shell语句返回错误的原因
*/
public final class GetPodErrorReasonUtil {

/**
* @Description 当k8s pod为Failed状态时,执行shell语句返回错误的原因
* @param podName
* @return errReasonOut,即pod为Failed状态的原因
*/
public static String getPodFailedReason( String podName )
{
String cmd = "timeout 2 kubectl " + "describe pod " + podName + " | awk '$2==\"Failed\"'";
ShellResult result = ShellUtil.executeAndGetExitStatus(cmd, 1);
String errReasonOut=null;
if (result.getExitStatus() == 0)
{
errReasonOut = result.getOut();
}
return errReasonOut;
}
}

+ 93
- 0
common/src/main/java/com/imitate/common/k8s/util/K8sClientUtil.java View File

@@ -0,0 +1,93 @@
package com.imitate.common.k8s.util;


import com.imitate.common.sys.pojo.ClusterConfig;
import com.imitate.common.sys.service.ClusterConfigService;
import com.imitate.common.sys.settings.AppConfig;
import com.imitate.common.bean.BeanFactory;
import io.fabric8.kubernetes.client.Config;
import io.fabric8.kubernetes.client.ConfigBuilder;
import io.fabric8.kubernetes.client.DefaultKubernetesClient;
import io.fabric8.kubernetes.client.KubernetesClient;
import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public final class K8sClientUtil {

private static volatile Map<String, KubernetesClient> clients = new HashMap<>();

public static KubernetesClient getClient(String cluster) {
KubernetesClient client = clients.get(cluster);
if (client == null) {
synchronized (K8sClientUtil.class) {
client = clients.get(cluster);
if (client == null) {
ClusterConfigService clusterConfigService = (ClusterConfigService) BeanFactory
.getObejct("clusterConfigService");
AppConfig appConfig = (AppConfig) BeanFactory.getObejct("appConfig");

ClusterConfig clusterConfig = clusterConfigService.getClusterConfig(cluster);
if (StringUtils.isNotEmpty(clusterConfig.getUsername())) {
Config config = new ConfigBuilder().withMasterUrl(clusterConfig.getMasterUrl())
.withNamespace("default").withTrustCerts(true).withUsername(clusterConfig.getUsername())
.withPassword(clusterConfig.getPassword())
.withMaxConcurrentRequests(appConfig.getK8sMaxConcurrentRequests())
.withMaxConcurrentRequestsPerHost(appConfig.getK8sMaxConcurrentRequestsPerHost())
.withWebsocketTimeout(150000)
.withWebsocketPingInterval(0)
.build();
client = new DefaultKubernetesClient(config);
} else if (StringUtils.isNotEmpty(clusterConfig.getCaCertData())) {
Config config = new ConfigBuilder().withMasterUrl(clusterConfig.getMasterUrl())
.withNamespace("default").withTrustCerts(true)
.withCaCertData(clusterConfig.getCaCertData())
.withClientCertData(clusterConfig.getClientCerData())
.withClientKeyData(clusterConfig.getClientKeyData())
.withMaxConcurrentRequests(appConfig.getK8sMaxConcurrentRequests())
.withMaxConcurrentRequestsPerHost(appConfig.getK8sMaxConcurrentRequestsPerHost())
.withWebsocketTimeout(150000)
.withWebsocketPingInterval(0)
.build();
client = new DefaultKubernetesClient(config);
}
Map<String, KubernetesClient> tmp = new HashMap<>(clients);
tmp.put(cluster, client);
clients = tmp;
}
}
}
return client;
}

public static void refreshK8sClients() {
ClusterConfigService clusterConfigService = (ClusterConfigService) BeanFactory
.getObejct("clusterConfigService");
List<String> availableClusters = clusterConfigService.getAvailableClusters();

List<String> list = new ArrayList<>(clients.keySet());
for (String cluster : list) {
boolean exist = false;
for (String availableCluster : availableClusters) {
if (cluster.equals(availableCluster)) {
exist = true;
break;
}
}

if (!exist) {
removeClient(cluster);
}
}

}

private static synchronized void removeClient(String cluster) {
Map<String, KubernetesClient> tmp = new HashMap<>(clients);
tmp.remove(cluster);
clients = tmp;
}
}

+ 119
- 0
common/src/main/java/com/imitate/common/k8s/util/K8sPodCommandExecutor.java View File

@@ -0,0 +1,119 @@
package com.imitate.common.k8s.util;

/**
* k8s 命令执行器
*
* @author 威少
*/

import com.imitate.common.bean.ShellResult;
import io.fabric8.kubernetes.api.model.Pod;
import io.fabric8.kubernetes.client.KubernetesClient;
import io.fabric8.kubernetes.client.dsl.ExecListener;
import io.fabric8.kubernetes.client.dsl.ExecWatch;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.io.ByteArrayOutputStream;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import static com.imitate.common.constant.TpCsts.*;


@Slf4j
public class K8sPodCommandExecutor {

/**
* Pod中执行命令
*
* @param podName pod名
* @param cmd 命令
* @param timeout 超时时间
* @return 执行结果
*/
public static ShellResult execCommandInPod(String podName, String[] cmd, long timeout) {
return execCommandInPod(LOCAL_CLUSTER, DEFAULT_NAMESPACE, podName, cmd, timeout);
}

/**
* Pod中执行命令
*
* @param cluster 集群
* @param namespace 命名空间
* @param podName pod名
* @param cmd 命令
* @param timeout 超时时间
* @return 执行结果
*/
public static ShellResult execCommandInPod(String cluster, String namespace, String podName, String[] cmd, long timeout) {
ShellResult result = new ShellResult(ShellResult.ExitStatus.FAIL.getCode(), StringUtils.EMPTY);
KubernetesClient client = K8sClientUtil.getClient(cluster);
Pod pod = client.pods().inNamespace(namespace).withName(podName).get();
CompletableFuture<ShellResult> data = new CompletableFuture<>();
try (ExecWatch ignored = execCmd(client, pod, data, cmd)) {
result = data.get(timeout, TimeUnit.SECONDS);
result.setExitStatus(ShellResult.ExitStatus.SUCCESS.getCode());
} catch (TimeoutException e) {
log.warn("exec command in pod timeout, cmd: {}, pod: {}", cmd, podName, e);
result.setExitStatus(ShellResult.ExitStatus.TIMEOUT.getCode());
} catch (Exception e) {
log.error("exec command in pod failure, cmd: {}, pod: {}", cmd, podName, e);
}

log.info("execute command: {} in pod: {} with timeout: {}, result: {}", cmd, podName, timeout, result);

return result;
}

/**
* 执行命令
*
* @param client 客户端
* @param pod pod
* @param data 返回数据future
* @param command 命令
*/
private static ExecWatch execCmd(KubernetesClient client, Pod pod, CompletableFuture<ShellResult> data, String... command) {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ByteArrayOutputStream errorChannelStream = new ByteArrayOutputStream();
String firstContainerName = pod.getSpec().getContainers().get(0).getName();
return client.pods()
.inNamespace(pod.getMetadata().getNamespace())
.withName(pod.getMetadata().getName())
.inContainer(firstContainerName)
.writingOutput(outputStream)
.writingError(outputStream)
.writingErrorChannel(errorChannelStream)
.usingListener(new PodBashExecListener(data, outputStream))
.exec(command);
}

static class PodBashExecListener implements ExecListener {

private CompletableFuture<ShellResult> data;
private ByteArrayOutputStream baos;

public PodBashExecListener(CompletableFuture<ShellResult> data, ByteArrayOutputStream baos) {
this.data = data;
this.baos = baos;
}

@SneakyThrows
@Override
public void onFailure(Throwable t, Response failureResponse) {
if (failureResponse == null) {
data.completeExceptionally(t);
} else {
data.complete(new ShellResult(failureResponse.code(), failureResponse.body()));
}
}

@Override
public void onClose(int code, String reason) {
data.complete(new ShellResult(code, baos.toString()));
}
}
}

+ 371
- 0
common/src/main/java/com/imitate/common/k8s/util/K8sUtils.java View File

@@ -0,0 +1,371 @@
package com.imitate.common.k8s.util;


import com.google.common.collect.Lists;
import com.imitate.common.constant.TpCsts;
import com.imitate.common.k8s.pojo.ErrorPodInfo;
import com.imitate.common.bean.ShellResult;
import com.imitate.common.sys.constant.SysConfigCsts;
import com.imitate.common.util.ShellUtil;
import io.fabric8.kubernetes.api.model.*;
import io.fabric8.kubernetes.client.utils.PodStatusUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;

import java.time.LocalDateTime;
import java.util.List;

public final class K8sUtils {

private static final Logger logger = LoggerFactory.getLogger(K8sUtils.class);

public static int getNodePort(Service svc) {
List<ServicePort> list = svc.getSpec().getPorts();
for (ServicePort sp : list) {
return sp.getNodePort();
}
throw new RuntimeException("svc: " + svc.getMetadata().getName() + " 中没有找到NodePort");
}

public static double getNodeAllocatableCpu(Node node) {
String amount = node.getStatus().getAllocatable().get("cpu").getAmount();
return parseCpuAmount(amount);
}
public static double getNodeCapacityCpu(Node node) {
String amount = node.getStatus().getCapacity().get("cpu").getAmount();
return parseCpuAmount(amount);
}

public static double getRequestCpu(Pod pod) {
String amount = pod.getSpec().getContainers().get(0).getResources().getRequests().get("cpu").getAmount();
return parseCpuAmount(amount);
}

public static double getNodeAllocatableMemory(Node node) {
String amount = node.getStatus().getAllocatable().get("memory").getAmount();
return parseMemoryAmount(amount);
}

public static double getNodeCapacityMemory(Node node) {
String amount = node.getStatus().getCapacity().get("memory").getAmount();
return parseCpuAmount(amount);
}

public static boolean isOjNode(Node node) {
String label = node.getMetadata().getLabels().get(TpCsts.OJ_LABEL_KEY);
return StringUtils.isNotEmpty(label) && TpCsts.OJ_LABEL_VALUE.equals(label);
}

public static boolean isOjPod(Pod pod) {
String label = pod.getMetadata().getLabels().get(TpCsts.OJ_LABEL_KEY);
return StringUtils.isNotEmpty(label) && TpCsts.OJ_LABEL_VALUE.equals(label);
}
private static double parseCpuAmount(String amount) {
// cpu可能 的形式 100m, "2", 1
amount = amount.trim().replaceAll("\"", ""); // \"有这种情况?
if (amount.endsWith("m")) {
amount = amount.substring(0, amount.length() - 1);
return Double.parseDouble(amount) / 1000;
} else {
return Double.parseDouble(amount);
}
}

private static double parseMemoryAmount(String amount) {
// memory返回的格式为:16267956Ki.需要去除最后两个字符
return Double.parseDouble(amount.substring(0, amount.length() - 2)) / 1024;
}

public static String getIp(Node node) {
return node.getStatus().getAddresses().get(0).getAddress();
}
public static String getLabel(Node node, String labelKey) {
return node.getMetadata().getLabels().get(labelKey);
}
public static String getNodeIp (Pod pod) {
return pod.getStatus().getHostIP();
}

public static String getNodeName (Node node) {
return node.getMetadata().getName();
}

public static String getNodeName(Pod pod) {
return pod == null ? null : pod.getSpec().getNodeName();
}
public static String getPodName(Pod pod) {
return pod == null ? null : pod.getMetadata().getName();
}
public static boolean isErrImagePull(Pod pod) {
List<ContainerStatus> list = pod.getStatus().getContainerStatuses();
for (ContainerStatus cs : list) {
ContainerState state = cs.getState();
if (state == null) {
continue;
}
ContainerStateWaiting wating = state.getWaiting();
if (wating == null) {
continue;
}
boolean r = "ErrImagePull".equals(wating.getReason());
if (r) {
return true;
}
}
return false;
}

/**
* @author huqifeng
* @Time 2021-7-19
* @Description 查询错误pod在节点上是否在服务器上不存在对应的镜像
* @param pod k8s pod
* @return 不存在的镜像列表
*/
public static List<String> podImagesNotExist(Pod pod) {
List<ContainerStatus> containerStatusList = pod.getStatus().getContainerStatuses();
List<PodCondition> podConditionList = pod.getStatus().getConditions();
String nodeIp = pod.getStatus().getHostIP();
//带版本号的镜像名
String imageNameWithVersion;
//镜像名imageName
String imageName;
//缺失的镜像
List<String> imageList = Lists.newArrayList();
//判断pod创建失败是否是由于镜像拉取失败而引起的
for (PodCondition podCondition : podConditionList) {
if ("False".equals(podCondition.getStatus()) && "ContainersNotReady".equals(podCondition.getReason())) {
String podConditionMessage = podCondition.getMessage();
if (podConditionMessage.startsWith("containers with unready status: [")) {
//获取镜像名
for (ContainerStatus containerStatus : containerStatusList) {
imageName=containerStatus.getName();
imageNameWithVersion = containerStatus.getImage();
if (imageNameWithVersion == null) {
continue;
}
//执行shell命令查询镜像是否存在
//镜像不存在,则保存缺失的镜像名
if (!K8sUtils.searchDockerImage(imageName, nodeIp)) {
imageList.add(imageNameWithVersion);
}
}
}
}
}
return imageList;
}

/**
* @author huqifeng
* @Time 2021-7-19
* @Description 判断k8s节点上是否有某一个镜像
* @param imageName 镜像名
* @param nodeIp k8s节点ip
* @return 若存在该镜像,返回true,否则返回false
*/
public static boolean searchDockerImage(String imageName, String nodeIp) {
String remoteConnection = String.format(SysConfigCsts.REMOTE_CONN_PREFIX_DEF, nodeIp);
//在shell中执行查询镜像语句
String getCommand = remoteConnection + " docker images | grep " + imageName + " | awk '{print $1}'";
ShellResult result = ShellUtil.executeAndGetExitStatus(getCommand);

return 0 == result.getExitStatus() && !"".equals(result.getOut());
}



public static boolean isReadyStatus(Node node) {
List<NodeCondition> conditions = node.getStatus().getConditions();
// 只统计Ready状态的节点
for (NodeCondition condition : conditions) {
if ("Ready".equalsIgnoreCase(condition.getType())
&& "True".equalsIgnoreCase(condition.getStatus())) {
return true;
}
}
return false;
}

/**
* 容器是否处于running的状态
*/
public static boolean isPodRunning(Pod pod) {
return PodStatusUtil.isRunning(pod) &&
pod.getStatus().getContainerStatuses().stream().allMatch(
status -> status.getReady() != null
&& status.getState() != null
&& status.getState().getRunning() != null);
}

public static boolean isNewCapacityNode(Node node, Integer time) {
String createTimestamp = node.getMetadata().getCreationTimestamp();
if (createTimestamp.endsWith("Z")) {
createTimestamp = createTimestamp.substring(0, createTimestamp.length() - 1);
}
// 转化为东八区时间
LocalDateTime createTime = LocalDateTime.parse(createTimestamp).plusHours(8);
return LocalDateTime.now().plusMinutes(-time).isBefore(createTime);
}

/**
* @author huqifeng
* @Time 2021-8-6
* @Description 当pod创建超时时,捕获pod的phase,以及处于该phase的原因
* @param podStatus pod状况
* @param podName pod名称
* @param nodeIp 节点ip
* @param errorPodInfo pod失败信息对象
*/
public static void catchPodPhaseReasonMessage(ErrorPodInfo errorPodInfo, PodStatus podStatus, String podName, String nodeIp )
{
String podPhase=podStatus.getPhase();
String podStatusReason=podStatus.getReason();
String podStatusMessage=podStatus.getMessage();
errorPodInfo.setPodPhase(podPhase);
errorPodInfo.setPodStatusReason(podStatusReason);
errorPodInfo.setPodConditionMessage(podStatusMessage);
logger.info( "创建pod {}失败,nodeIp: {},podPhase: {},podStatusReason: {},podStatusMessage: {}",podName,nodeIp,podPhase,podStatusReason,podStatusMessage );
}

/**
* @author huqifeng
* @Time 2021-8-6
* @Description 当pod创建超时时,捕获podCondition的状态,以及处于该状态的原因
* @param podStatus pod状况
* @param podName pod名称
* @param nodeIp 节点ip
* @param errorPodInfo pod失败信息对象
*/
public static void catchPodConditionReasonMessage(ErrorPodInfo errorPodInfo,PodStatus podStatus,String podName,String nodeIp)
{
List<PodCondition> conditions=podStatus.getConditions();
String podConditionType = null;
String podConditionStatus = null;
String podConditionReason = null;
String podConditionMessage = null;
for(PodCondition podCondition:conditions)
{
podConditionType = StringUtils.join(podConditionType,podCondition.getType(),"_");
podConditionStatus = StringUtils.join(podConditionStatus,podCondition.getType(),":",podCondition.getStatus(),"_");
podConditionReason = StringUtils.join(podConditionReason,podCondition.getType(),":",podCondition.getReason(),"_");
podConditionMessage = StringUtils.join(podConditionMessage,podCondition.getType(),":",podCondition.getMessage(),"_");
logger.info("创建pod {}失败,nodeIp: {},podConditionType: {},podConditionReason: {},podConditionMessage: {}",podName,nodeIp,podCondition.getType(),podCondition.getReason(),podCondition.getMessage());
}
errorPodInfo.setPodConditionType(podConditionType);
errorPodInfo.setPodConditionStatus(podConditionStatus);
errorPodInfo.setPodConditionReason(podConditionReason);
errorPodInfo.setPodConditionMessage(podConditionMessage);
}

/**
* @author huqifeng
* @Time 2021-8-6
* @Description 当pod创建超时时,捕获Container的状态,以及处于该状态的原因
* @param podStatus pod状况
* @param podName pod名称
* @param nodeIp 节点ip
* @param errorPodInfo pod失败信息对象
*/
public static void catchContainerStateReasonMessage(ErrorPodInfo errorPodInfo, PodStatus podStatus, String podName, String nodeIp )
{
List<ContainerStatus> containerStatuses=podStatus.getContainerStatuses();
String image;
String containerStatusReady = null;
String containerStatusWaiting = null;
String containerStatusWaitingReason = null;
String containerStatusWaitingMessage = null;
String containerStatusTerminated = null;
String containerStatusTerminatedReason = null;
String containerStatusTerminatedMessage = null;
for( ContainerStatus containerStatus:containerStatuses )
{
image = containerStatus.getImage();
if (containerStatus.getReady()) {
containerStatusReady=StringUtils.join(containerStatusReady,image,"_","true","_");
}
else {
containerStatusReady=StringUtils.join(containerStatusReady,image,"_","false","_");
}
ContainerState containerState=containerStatus.getState();
ContainerStateWaiting waiting = containerState.getWaiting();
//containerStatus为waiting状态
if (waiting!=null) {
containerStatusWaiting = StringUtils.join(containerStatusWaiting,image,"_","true","_");
containerStatusWaitingReason = StringUtils.join(containerStatusWaitingReason,image,"_",waiting.getReason(),"_");
containerStatusWaitingMessage = StringUtils.join(containerStatusWaitingMessage,image,"_",waiting.getMessage(),"_");
logger.info( "创建pod {}失败,nodeIp: {},image: {},ContainerState: waiting,ContainerStateReason: {},ContainerStateMessage: {}",podName,nodeIp,image,waiting.getReason(),waiting.getMessage() );
}
else {
containerStatusWaiting = StringUtils.join(containerStatusWaiting,image,"_","null","_");
containerStatusWaitingReason = StringUtils.join(containerStatusWaitingReason,image,"_","null","_");
containerStatusWaitingMessage = StringUtils.join(containerStatusWaitingMessage,image,"_","null","_");
}
ContainerStateTerminated terminated=containerState.getTerminated();
//containerStatus为terminated状态
if (terminated!=null) {
containerStatusTerminated = StringUtils.join(containerStatusTerminated,image,"_","true","_");
containerStatusTerminatedReason = StringUtils.join(containerStatusTerminatedReason,image,"_",terminated.getReason(),"_");
containerStatusTerminatedMessage = StringUtils.join(containerStatusTerminatedMessage,image,"_",terminated.getMessage(),"_");
logger.info( "创建pod {}失败,nodeIp: {},image: {},ContainerState: terminated,ContainerStateReason: {},ContainerStateMessage: {}",podName,nodeIp,image,terminated.getReason(),terminated.getMessage() );
}
else {
containerStatusTerminated = StringUtils.join(containerStatusTerminated,image,"_","null","_");
containerStatusTerminatedReason = StringUtils.join(containerStatusTerminatedReason,image,"_","null","_");
containerStatusTerminatedMessage = StringUtils.join(containerStatusTerminatedMessage,image,"_","null","_");
}
}
errorPodInfo.setContainerStatusReady(containerStatusReady);
errorPodInfo.setContainerStatusWaiting(containerStatusWaiting);
errorPodInfo.setContainerStatusWaitingReason(containerStatusWaitingReason);
errorPodInfo.setContainerStatusWaitingMessage(containerStatusWaitingMessage);
errorPodInfo.setContainerStatusTerminated(containerStatusTerminated);
errorPodInfo.setContainerStatusTerminatedReason(containerStatusTerminatedReason);
errorPodInfo.setContainerStatusTerminatedMessage(containerStatusTerminatedMessage);
}

/**
* @author huqifeng
* @Time 2021-8-9
* @Description 当pod创建超时时,捕获Container的状态,以及处于该状态的原因
* @param podStatus pod状况
* @param podName pod名称
* @param nodeIp 节点ip
*/
public static void createErrorPodInfo(ErrorPodInfo errorPodInfo, PodStatus podStatus, String podName, String nodeIp, String tpiID, String buildID, boolean imageExist)
{
errorPodInfo.setErrorTime(LocalDateTime.now());
errorPodInfo.setPodName(podName);
errorPodInfo.setNodeIp(nodeIp);
errorPodInfo.setTpiID(tpiID);
errorPodInfo.setBuildID(buildID);
if (imageExist) {
errorPodInfo.setImageExist("true");
}
else {
errorPodInfo.setImageExist("false");
}
K8sUtils.catchPodPhaseReasonMessage(errorPodInfo, podStatus, podName, nodeIp);
K8sUtils.catchPodConditionReasonMessage(errorPodInfo, podStatus, podName, nodeIp);
K8sUtils.catchContainerStateReasonMessage(errorPodInfo, podStatus, podName, nodeIp);
}

/**
* 获取环境变量
*/
public static String getEnv(Pod pod, String key){
String value = "";
if (!CollectionUtils.isEmpty(pod.getSpec().getContainers().get(0).getEnv())) {
value = pod.getSpec().getContainers().get(0).getEnv().stream().filter(envVar -> envVar.getName().equals(key)).findFirst().get().getValue();
}
return value;
}
}

+ 22
- 0
common/src/main/java/com/imitate/common/shiro/config/FilterConfig.java View File

@@ -0,0 +1,22 @@
package com.imitate.common.shiro.config;

import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.web.filter.DelegatingFilterProxy;

/**
* Filter配置
* @author yanchao
*/
public class FilterConfig {
@Bean
public FilterRegistrationBean shiroFilterRegistration(){
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
registrationBean.setFilter(new DelegatingFilterProxy("shiroFilter"));
registrationBean.addInitParameter("targetFilteerLifecycle","true");
registrationBean.setEnabled(true);
registrationBean.setOrder(Integer.MAX_VALUE - 1);
registrationBean.addUrlPatterns("/*");
return registrationBean;
}
}

+ 108
- 0
common/src/main/java/com/imitate/common/shiro/config/OAuth2Filter.java View File

@@ -0,0 +1,108 @@
package com.imitate.common.shiro.config;

import com.google.gson.Gson;
import com.imitate.common.enums.ErrorCodeEnum;
import com.imitate.common.shiro.realm.OAuth2Token;
import com.imitate.common.util.R;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.web.filter.authc.AuthenticatingFilter;
import org.springframework.web.bind.annotation.RequestMethod;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
* oauth2过滤器
* @author yanchao
*/
public class OAuth2Filter extends AuthenticatingFilter {

/**
* 取token
* @author yanchao
*/
@Override
protected AuthenticationToken createToken(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception {
//获取请求token
String token = getRequestToken((HttpServletRequest) servletRequest);
if(StringUtils.isBlank(token)){
return null;
}
return new OAuth2Token(token);
}


@Override
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
if(((HttpServletRequest) request).getMethod().equals(RequestMethod.OPTIONS.name())){
return true;
}
return false;
}


/**
* 认证之前调用的方法
* @author yanchao
* @return boolean
*/
@Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
//获取请求中的token,如果不存在,直接返回401
String token = getRequestToken((HttpServletRequest)request);
if(StringUtils.isBlank(token)){
HttpServletResponse httpResponse = (HttpServletResponse) response;
httpResponse.setHeader("Access-Control-Allow-Credentials","true");
httpResponse.setHeader("Access-Control-Allow-Origin", "*");
httpResponse.setContentType("application/json;charset=UTF-8");
R r = R.error(ErrorCodeEnum.NO_AUTH.getValue(),ErrorCodeEnum.NO_AUTH.getDescription());
String json = new Gson().toJson(r);
httpResponse.getWriter().print(json);
return false;
}
return executeLogin(request,response);
}

/**
* 登陆认证失败调用的方法
* @author yanchao
* @return boolean
*/
@Override
protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException e, ServletRequest request, ServletResponse response) {
HttpServletResponse httpResponse = (HttpServletResponse) response;
httpResponse.setContentType("application/json;charset=utf-8");
httpResponse.setHeader("Access-Control-Allow-Credentials","true");
httpResponse.setHeader("Access-Control-Allow-Origin", "*");
try {
//处理登录失败的异常
R r = R.error(ErrorCodeEnum.NO_AUTH.getValue(),ErrorCodeEnum.NO_AUTH.getDescription());
String json = new Gson().toJson(r);
httpResponse.getWriter().print(json);
}catch (IOException e1){
}
return false;
}

/**
* 获取请求的token
* @author yanchao
*/
private String getRequestToken(HttpServletRequest httpRequest){
//从header中获取token
String token = httpRequest.getHeader("token");
//如果header中不存在token,则从参数中获取
if(StringUtils.isBlank(token)){
token = httpRequest.getParameter("token");
}
return token;
}

}

+ 106
- 0
common/src/main/java/com/imitate/common/shiro/config/ShiroConfig.java View File

@@ -0,0 +1,106 @@
package com.imitate.common.shiro.config;


import com.imitate.common.shiro.realm.OAuth2Realm;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.servlet.Filter;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

/**
* Shiro配置类
* @author yanchao
*/
@Configuration
public class ShiroConfig {

/**
* 会话管理器
* @author yanchao
*/
@Bean("sessionManager")
public SessionManager sessionManager(){
DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
sessionManager.setSessionValidationSchedulerEnabled(true);
sessionManager.setSessionIdCookieEnabled(true);
return sessionManager;
}

/**
* 安全管理器
* @author yanchao
*/
@Bean("securityManager")
public SecurityManager securityManager(OAuth2Realm oAuth2Realm, SessionManager sessionManager){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(oAuth2Realm);
securityManager.setSessionManager(sessionManager);
return securityManager;
}

/**
* shiro过滤器工厂
* @author yanchao
*/
@Bean("shiroFilter")
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager){
ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
shiroFilter.setSecurityManager(securityManager);
//oauth
Map<String,Filter> filters = new HashMap<>();
filters.put("oauth2",new OAuth2Filter());
shiroFilter.setFilters(filters);

Map<String, String> filterMap = new LinkedHashMap<>();
//filterMap.put("/**","oauth2");
filterMap.put("/**","anon");
shiroFilter.setFilterChainDefinitionMap(filterMap);
return shiroFilter;
}




/**
* 启用Shiro注解,保证实现了shiro内部lifecycle函数的bean执行
* @author yanchao
*/
@Bean("lifecycleBeanPostProcessor")
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor(){
return new LifecycleBeanPostProcessor();
}



/**
* 启用shiro注解
* @author yanchao
*/
@Bean
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator(){
DefaultAdvisorAutoProxyCreator proxyCreator = new DefaultAdvisorAutoProxyCreator();
proxyCreator.setProxyTargetClass(true);
return proxyCreator;
}

@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){
AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
advisor.setSecurityManager(securityManager);
return advisor;
}




}

+ 16
- 0
common/src/main/java/com/imitate/common/shiro/mapper/SysMenuMapper.java View File

@@ -0,0 +1,16 @@
package com.imitate.common.shiro.mapper;


import com.imitate.common.shiro.pojo.SysMenu;
import com.imitate.common.util.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;

/**
* 权限菜单
* @author yanchao
*/
@Repository
@Mapper
public interface SysMenuMapper extends BaseMapper<SysMenu> {
}

+ 31
- 0
common/src/main/java/com/imitate/common/shiro/mapper/SysRoleMapper.java View File

@@ -0,0 +1,31 @@
package com.imitate.common.shiro.mapper;



import com.imitate.common.shiro.pojo.SysRole;
import com.imitate.common.util.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;
import java.util.List;

/**
* 角色管理
* @author yanchao
*/
@Mapper
@Repository
public interface SysRoleMapper extends BaseMapper<SysRole> {
/**
* 查询用户创建的角色ID列表
*/
List<Long> queryRoleIdList(Long createUserId);


/**
* 获取角色详情
*/
SysRole get(@Param(value = "id") Long id);

}

+ 29
- 0
common/src/main/java/com/imitate/common/shiro/mapper/SysRoleMenuMapper.java View File

@@ -0,0 +1,29 @@
package com.imitate.common.shiro.mapper;


import com.imitate.common.shiro.pojo.SysRoleMenu;
import com.imitate.common.util.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;

import java.util.List;

/**
* 角色与菜单对应关系
* @author yanchao
*/
@Mapper
@Repository
public interface SysRoleMenuMapper extends BaseMapper<SysRoleMenu> {
/**
* 根据角色ID,获取菜单ID列表
*/
List<Long> queryMenuIdList(Long roleId);

/**
* 根据角色ID数组,批量删除
*/
int deleteBatch(Long[] roleIds);

}

+ 14
- 0
common/src/main/java/com/imitate/common/shiro/mapper/SysTokenMapper.java View File

@@ -0,0 +1,14 @@
package com.imitate.common.shiro.mapper;


import com.imitate.common.shiro.pojo.SysToken;
import com.imitate.common.util.BaseMapper;
import org.springframework.stereotype.Repository;

/**
* 登录会话
* @author yanchao
*/
@Repository
public interface SysTokenMapper extends BaseMapper<SysToken> {
}

+ 23
- 0
common/src/main/java/com/imitate/common/shiro/mapper/SysUserMapper.java View File

@@ -0,0 +1,23 @@
package com.imitate.common.shiro.mapper;



import com.imitate.common.shiro.pojo.SysUser;
import com.imitate.common.util.BaseMapper;
import org.springframework.stereotype.Repository;

import java.util.List;

/**
* 后台用户mapper
* @author yanchao
*/
@Repository
public interface SysUserMapper extends BaseMapper<SysUser> {

/**
* 查询用户的所有权限
*/
List<String> queryAllPerms(Long id);

}

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

Loading…
Cancel
Save