LimitRequestServiceImpl.java 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. package cn.seecoder.devmanage.service.impl;
  2. import cn.seecoder.api.k8s.model.LimitRange;
  3. import cn.seecoder.devmanage.log.LocalLogger;
  4. import cn.seecoder.devmanage.model.po.LimitRequest;
  5. import cn.seecoder.devmanage.model.vo.LimitRequestVO;
  6. import cn.seecoder.devmanage.repository.LimitRequestRepository;
  7. import cn.seecoder.devmanage.service.LimitRangeService;
  8. import cn.seecoder.devmanage.service.LimitRequestService;
  9. import lombok.RequiredArgsConstructor;
  10. import org.springframework.data.domain.*;
  11. import org.springframework.security.core.context.SecurityContextHolder;
  12. import org.springframework.stereotype.Service;
  13. import org.springframework.transaction.annotation.Transactional;
  14. import java.util.ArrayList;
  15. import java.util.Arrays;
  16. import java.util.List;
  17. @Service
  18. @RequiredArgsConstructor
  19. public class LimitRequestServiceImpl implements LimitRequestService {
  20. private final LocalLogger localLogger;
  21. private final LimitRangeService limitRangeService;
  22. private final LimitRequestRepository limitRequestRepository;
  23. private final int[] validPageSizes = new int[]{5, 10, 20};
  24. private final String[] HANDLED_MATCHES = {"已处理", "handled", "handle", "已审阅", "已操作", "true"};
  25. private final String[] UNHANDLED_MATCHES = {"未处理", "unhandled", "unhandle", "未审阅", "未操作", "false"};
  26. private final String[] PERMITTED_MATCHES = {"已允许", "允许", "permitted", "permit", "已获准", "获准", "已准许", "准许", "true"};
  27. private final String[] DENIED_MATCHES = {"未允许", "未获准", "未准许", "deny", "denied", "unpermitted", "unpermit", "false"};
  28. private final int ALL_REQUEST = 0;
  29. private final int ONLY_HANDLED = 1;
  30. private final int ONLY_UNHANDLED = 2;
  31. @Transactional
  32. @Override
  33. public LimitRequestVO newLimitRequest(String namespace, String name, Integer maxCpu, Integer maxMem, String reason) {
  34. String username = (String) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
  35. LimitRequest limitRequest =
  36. new LimitRequest(username, namespace, name, maxMem, maxCpu, false, false, System.currentTimeMillis(), reason);
  37. LimitRequest save = limitRequestRepository.save(limitRequest);
  38. return new LimitRequestVO(save);
  39. }
  40. @Transactional(readOnly = true)
  41. @Override
  42. public List<LimitRequestVO> getPagedLimitRequests(Integer pageNo, Integer pageSize, Boolean descByTime, Integer handledSwitch) {
  43. if (isInvalidPageSize(pageSize)) {
  44. return new ArrayList<>();
  45. }
  46. Page<LimitRequest> results;
  47. Sort sort = descByTime ? Sort.by("timestamp").descending() : Sort.by("timestamp").ascending();
  48. if (handledSwitch == ALL_REQUEST) {
  49. results = limitRequestRepository.findAll(PageRequest.of(pageNo, pageSize, sort));
  50. } else if (handledSwitch == ONLY_HANDLED || handledSwitch == ONLY_UNHANDLED) {
  51. boolean handled = handledSwitch == ONLY_HANDLED;
  52. LimitRequest probe = new LimitRequest();
  53. probe.setHandled(handled);
  54. ExampleMatcher matcher = ExampleMatcher.matchingAll()
  55. .withMatcher("handled", ExampleMatcher.GenericPropertyMatchers.exact());
  56. Example<LimitRequest> example = Example.of(probe, matcher);
  57. results = limitRequestRepository.findAll(example, PageRequest.of(pageNo, pageSize, sort));
  58. } else {
  59. return new ArrayList<>();
  60. }
  61. List<LimitRequestVO> ans = new ArrayList<>(pageSize);
  62. for (LimitRequest po: results) {
  63. ans.add(new LimitRequestVO(po));
  64. }
  65. return ans;
  66. }
  67. @Transactional(readOnly = true)
  68. @Override
  69. public List<LimitRequestVO> searchPagedLimitRequests(Integer pageNo, Integer pageSize, String keyword, Boolean descByTime) {
  70. if (isInvalidPageSize(pageSize) || keyword == null) {
  71. return new ArrayList<>();
  72. }
  73. Sort sort = descByTime ? Sort.by("timestamp").descending() : Sort.by("timestamp").ascending();
  74. LimitRequest probe = new LimitRequest();
  75. probe.setRequester(keyword);
  76. probe.setNamespace(keyword);
  77. probe.setName(keyword);
  78. // String keywords
  79. ExampleMatcher matcher = ExampleMatcher.matchingAny()
  80. .withIgnoreCase()
  81. .withMatcher("requester", ExampleMatcher.GenericPropertyMatchers.contains())
  82. .withMatcher("namespace", ExampleMatcher.GenericPropertyMatchers.contains())
  83. .withMatcher("name", ExampleMatcher.GenericPropertyMatchers.contains());
  84. // Long keyword
  85. if (isParsableLong(keyword)) {
  86. probe.setId(Long.parseLong(keyword));
  87. matcher = matcher.withMatcher("id", ExampleMatcher.GenericPropertyMatchers.exact());
  88. }
  89. // Integer keywords
  90. if (isParsableInteger(keyword)) {
  91. int intKey = Integer.parseInt(keyword);
  92. probe.setMaxMem(intKey);
  93. probe.setMaxCpu(intKey);
  94. matcher = matcher
  95. .withMatcher("maxMem", ExampleMatcher.GenericPropertyMatchers.exact())
  96. .withMatcher("maxCpu", ExampleMatcher.GenericPropertyMatchers.exact());
  97. }
  98. // Handled
  99. if (Arrays.stream(HANDLED_MATCHES).anyMatch(keyword::equalsIgnoreCase)) {
  100. probe.setHandled(true);
  101. matcher = matcher.withMatcher("handled", ExampleMatcher.GenericPropertyMatchers.exact());
  102. } else if (Arrays.stream(UNHANDLED_MATCHES).anyMatch(keyword::equalsIgnoreCase)) {
  103. probe.setHandled(false);
  104. matcher = matcher.withMatcher("handled", ExampleMatcher.GenericPropertyMatchers.exact());
  105. }
  106. // Permitted
  107. if (Arrays.stream(PERMITTED_MATCHES).anyMatch(keyword::equalsIgnoreCase)) {
  108. probe.setPermitted(true);
  109. matcher = matcher.withMatcher("permitted", ExampleMatcher.GenericPropertyMatchers.exact());
  110. } else if (Arrays.stream(DENIED_MATCHES).anyMatch(keyword::equalsIgnoreCase)) {
  111. probe.setPermitted(false);
  112. matcher = matcher.withMatcher("permitted", ExampleMatcher.GenericPropertyMatchers.exact());
  113. }
  114. Example<LimitRequest> example = Example.of(probe, matcher);
  115. Page<LimitRequest> results = limitRequestRepository.findAll(example, PageRequest.of(pageNo, pageSize, sort));
  116. List<LimitRequestVO> ans = new ArrayList<>();
  117. for (LimitRequest po: results) {
  118. ans.add(new LimitRequestVO(po));
  119. }
  120. return ans;
  121. }
  122. @Transactional
  123. @Override
  124. public boolean permitRequest(Long limitRequestId) {
  125. LimitRequest limitRequest = limitRequestRepository.getById(limitRequestId);
  126. if (limitRequest.getHandled()) {
  127. // You can not handle an already handled request
  128. localLogger.recordFailure(
  129. String.format("Tried to illegally permit an already handled LimitRequest, which id is %s.",
  130. limitRequestId));
  131. return false;
  132. } else {
  133. limitRequest.setHandled(true);
  134. limitRequest.setPermitted(true);
  135. String namespace = limitRequest.getNamespace();
  136. String name = limitRequest.getName();
  137. List<LimitRange> limitRanges = limitRangeService.getLimitRanges(namespace, name);
  138. if (limitRanges == null || limitRanges.isEmpty()) {
  139. localLogger.recordFailure(String.format("Targeted LimitRange of id %s doest not exist, thus" +
  140. " did nothing.", limitRequestId));
  141. return false;
  142. } else {
  143. LimitRange limitRange = limitRanges.get(0);
  144. Integer maxCpu = limitRequest.getMaxCpu();
  145. Integer maxMem = limitRequest.getMaxMem();
  146. limitRange.setMaxCpu(maxCpu + "m");
  147. limitRange.setMaxMemory(maxMem + "Mi");
  148. limitRangeService.updateLimitRange(limitRange);
  149. localLogger.recordSuccess(String.format("Permitted a LimitRequest, which id is %s", limitRequestId));
  150. return true;
  151. }
  152. }
  153. }
  154. @Transactional
  155. @Override
  156. public boolean denyRequest(Long limitRequestId) {
  157. LimitRequest limitRequest = limitRequestRepository.getById(limitRequestId);
  158. if (limitRequest.getHandled()) {
  159. // You can not handle an already handled request
  160. localLogger.recordFailure(
  161. String.format("Tried to illegally deny an already handled LimitRequest, which id is %s.",
  162. limitRequestId));
  163. return false;
  164. } else {
  165. limitRequest.setHandled(true);
  166. limitRequest.setPermitted(false);
  167. localLogger.recordSuccess(String.format("Denied a LimitRequest, which id is %s", limitRequestId));
  168. return true;
  169. }
  170. }
  171. @Override
  172. public Integer getTotalPageCount(Integer pageSize) {
  173. if (isInvalidPageSize(pageSize)) {
  174. return 0;
  175. } else {
  176. long count = limitRequestRepository.count();
  177. if (count % pageSize == 0) {
  178. return Math.toIntExact(count / pageSize);
  179. } else {
  180. return Math.toIntExact(count / pageSize + 1);
  181. }
  182. }
  183. }
  184. private boolean isParsableLong(String keyword) {
  185. try {
  186. Long.parseLong(keyword);
  187. return true;
  188. } catch (NumberFormatException e) {
  189. return false;
  190. }
  191. }
  192. private boolean isParsableInteger(String keyword) {
  193. try {
  194. Integer.parseInt(keyword);
  195. return true;
  196. } catch (NumberFormatException e) {
  197. return false;
  198. }
  199. }
  200. private boolean isInvalidPageSize(Integer pageSize) {
  201. for (int validPageSize: validPageSizes) {
  202. if (validPageSize == pageSize) {
  203. return false;
  204. }
  205. }
  206. return true;
  207. }
  208. }