wanghongkai 5 anni fa
parent
commit
bd16d4a86a

+ 16 - 0
src/main/java/cn/seecoder/paas/data/dao/MetricsDAO.java

@@ -0,0 +1,16 @@
+package cn.seecoder.paas.data.dao;
+
+import cn.seecoder.paas.data.entity.Metrics;
+import cn.seecoder.paas.util.enums.MetricsSource;
+import cn.seecoder.paas.util.enums.MetricsType;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+@Repository
+public interface MetricsDAO extends JpaRepository<Metrics, Integer> {
+
+    List<Metrics> findByMetricsSourceAndAndMetricsSourceValueAndMetricsTypeAndMetricsTimeBetween(MetricsSource source, String metricsSourceValue, MetricsType metricsType, LocalDateTime startTime, LocalDateTime endTime);
+}

+ 62 - 0
src/main/java/cn/seecoder/paas/data/entity/Metrics.java

@@ -0,0 +1,62 @@
+package cn.seecoder.paas.data.entity;
+
+import cn.seecoder.paas.util.enums.ConfigBelongsToType;
+import cn.seecoder.paas.util.enums.MetricsSource;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+import javax.persistence.*;
+import java.time.LocalDateTime;
+
+@Entity
+@Table(name = "metrics")
+@ToString
+@EqualsAndHashCode
+@Data
+public class Metrics {
+
+    @Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    @Column(name = "id")
+    private Integer id;
+
+    /**
+     * 度量来源
+     */
+    @Basic
+    @Enumerated
+    @Column(name = "metrics_source")
+    private MetricsSource metricsSource;
+
+    /**
+     * 度量来源对象标识
+     */
+    @Basic
+    @Enumerated
+    @Column(name = "metrics_source_value")
+    private String metricsSourceValue;
+
+    /**
+     * 度量类型
+     */
+    @Basic
+    @Enumerated
+    @Column(name = "metrics_type")
+    private MetricsSource metricsType;
+
+    /**
+     * 度量类型值
+     */
+    @Basic
+    @Enumerated
+    @Column(name = "metrics_type_value")
+    private String metricsTypeValue;
+
+    /**
+     * 度量时间
+     */
+    @Basic
+    @Column(name = "metricsTime")
+    private LocalDateTime metricsTime;
+}

+ 15 - 0
src/main/java/cn/seecoder/paas/service/MetricsService.java

@@ -0,0 +1,15 @@
+package cn.seecoder.paas.service;
+
+import cn.seecoder.paas.service.model.vo.MetricsVO;
+import cn.seecoder.paas.util.enums.MetricsSource;
+import cn.seecoder.paas.util.enums.MetricsType;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+public interface MetricsService {
+
+    List<MetricsVO> getMetricsBySourceAndTypeBetween(MetricsSource metricsSource, String metricsSourceValue, MetricsType metricsType, LocalDateTime startTime, LocalDateTime endTime);
+
+    List<MetricsVO> getMetricsSourceCurrentStatus(MetricsSource metricsSource, String metricsSourceValue);
+}

+ 180 - 0
src/main/java/cn/seecoder/paas/service/impl/MetricsServiceImpl.java

@@ -0,0 +1,180 @@
+package cn.seecoder.paas.service.impl;
+
+import cn.seecoder.paas.data.dao.EnvironmentDAO;
+import cn.seecoder.paas.data.dao.MetricsDAO;
+import cn.seecoder.paas.data.entity.Environment;
+import cn.seecoder.paas.data.entity.Metrics;
+import cn.seecoder.paas.service.MetricsService;
+import cn.seecoder.paas.service.facade.k8s.PodApi;
+import cn.seecoder.paas.service.facade.k8s.model.K8sObjectRequest;
+import cn.seecoder.paas.service.facade.k8s.model.Pod;
+import cn.seecoder.paas.service.model.converter.MetricsConverter;
+import cn.seecoder.paas.service.model.vo.MetricsVO;
+import cn.seecoder.paas.util.ApplicationProperties;
+import cn.seecoder.paas.util.enums.MetricsSource;
+import cn.seecoder.paas.util.enums.MetricsType;
+import cn.seecoder.paas.util.enums.ResourceLabel;
+import io.fabric8.kubernetes.api.model.Quantity;
+import io.fabric8.kubernetes.api.model.metrics.v1beta1.NodeMetrics;
+import io.fabric8.kubernetes.api.model.metrics.v1beta1.NodeMetricsList;
+import io.fabric8.kubernetes.api.model.metrics.v1beta1.PodMetrics;
+import io.fabric8.kubernetes.client.DefaultKubernetesClient;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import java.time.LocalDateTime;
+import java.util.*;
+import java.util.stream.Collectors;
+
+@org.springframework.stereotype.Service
+public class MetricsServiceImpl implements MetricsService {
+
+    private final DefaultKubernetesClient fabricK8sClient;
+
+    private final ApplicationProperties applicationProperties;
+
+    private final EnvironmentDAO environmentDAO;
+
+    private final MetricsDAO metricsDAO;
+
+    private final PodApi podApi;
+
+    @Autowired
+    public MetricsServiceImpl(DefaultKubernetesClient fabricK8sClient, ApplicationProperties applicationProperties, EnvironmentDAO environmentDAO, PodApi podApi, MetricsDAO metricsDAO) {
+        this.fabricK8sClient = fabricK8sClient;
+        this.applicationProperties = applicationProperties;
+        this.environmentDAO = environmentDAO;
+        this.podApi = podApi;
+        this.metricsDAO = metricsDAO;
+    }
+
+    @Override
+    public List<MetricsVO> getMetricsBySourceAndTypeBetween(MetricsSource metricsSource, String metricsSourceValue, MetricsType metricsType, LocalDateTime startTime, LocalDateTime endTime) {
+        List<Metrics> metrics = metricsDAO.findByMetricsSourceAndAndMetricsSourceValueAndMetricsTypeAndMetricsTimeBetween(metricsSource, metricsSourceValue, metricsType, startTime, endTime);
+        return metrics.stream().map(MetricsConverter::convertToVO).collect(Collectors.toList());
+    }
+
+    @Override
+    public List<MetricsVO> getMetricsSourceCurrentStatus(MetricsSource metricsSource, String metricsSourceValue) {
+        List<MetricsVO> result = new ArrayList<>();
+        String deploymentNamespace = applicationProperties.getDeploymentNamespace();
+        switch (metricsSource) {
+            case POD:
+                PodMetrics podMetrics = fabricK8sClient.top().pods().metrics(deploymentNamespace, metricsSourceValue);
+                return statPodMetrics(Collections.singletonList(podMetrics), metricsSource, metricsSourceValue);
+            case NODE:
+                NodeMetrics nodeMetrics = fabricK8sClient.top().nodes().metrics(metricsSourceValue);
+                return statNodeMetrics(Collections.singletonList(nodeMetrics), metricsSource, metricsSourceValue);
+            case APPLICATION:
+                List<Environment> environments = environmentDAO.findAllByAppId(Integer.parseInt(metricsSourceValue));
+                List<PodMetrics> podMetricsList = new ArrayList<>();
+                environments.forEach(environment -> {
+                    String labelKey = ResourceLabel.RESOURCE.getCode();
+                    String labelValue = ResourceLabel.RESOURCE.getGenerator().gen("environment", metricsSourceValue, String.valueOf(environment.getId()));
+                    K8sObjectRequest request = K8sObjectRequest.builder().namespace(applicationProperties.getDeploymentNamespace()).labels(Collections.singletonMap(labelKey, labelValue)).build();
+                    List<Pod> pods = podApi.getByCondition(request);
+                    pods.forEach(pod -> {
+                        PodMetrics metrics = fabricK8sClient.top().pods().metrics(deploymentNamespace, pod.getName());
+                        podMetricsList.add(metrics);
+                    });
+                });
+                return statPodMetrics(podMetricsList, metricsSource, metricsSourceValue);
+            case ENVIRONMENT:
+                Environment environment = environmentDAO.findById(Integer.parseInt(metricsSourceValue)).orElse(null);
+                if (environment == null) {
+                    return Collections.emptyList();
+                }
+                List<PodMetrics> environmentMetricsList = new ArrayList<>();
+                String labelKey = ResourceLabel.RESOURCE.getCode();
+                String labelValue = ResourceLabel.RESOURCE.getGenerator().gen("environment", String.valueOf(environment.getAppId()), String.valueOf(environment.getId()));
+                K8sObjectRequest request = K8sObjectRequest.builder().namespace(applicationProperties.getDeploymentNamespace()).labels(Collections.singletonMap(labelKey, labelValue)).build();
+                List<Pod> pods = podApi.getByCondition(request);
+                pods.forEach(pod -> {
+                    PodMetrics metrics = fabricK8sClient.top().pods().metrics(deploymentNamespace, pod.getName());
+                    environmentMetricsList.add(metrics);
+                });
+                return statPodMetrics(environmentMetricsList, metricsSource, metricsSourceValue);
+            case CLUSTER:
+                NodeMetricsList nodeMetricsList = fabricK8sClient.top().nodes().metrics();
+                return statNodeMetrics(nodeMetricsList.getItems(), metricsSource, metricsSourceValue);
+        }
+        return result;
+    }
+
+    public List<MetricsVO> statPodMetrics(List<PodMetrics> podMetricsList, MetricsSource metricsSource, String metricsSourceValue) {
+        if (podMetricsList == null || podMetricsList.isEmpty()) {
+            return Collections.emptyList();
+        }
+        List<MetricsVO> result;
+        Map<String, Long> values = new HashMap<>();
+        podMetricsList.forEach(podMetrics ->  {
+            podMetrics.getContainers().forEach(containerMetrics -> {
+                Map<String, Quantity> metricValues = containerMetrics.getUsage();
+                metricValues.forEach((key, quantity) -> {
+                    if (values.get(key) != null) {
+                        values.put(key, values.get(key) + Long.parseLong(quantity.getAmount()));
+                    } else {
+                        values.put(key, Long.parseLong(quantity.getAmount()));
+                    }
+                });
+            });
+        });
+        result = values.entrySet().stream().map(entry -> {
+            MetricsVO vo = new MetricsVO();
+            vo.setMetricsSource(metricsSource);
+            vo.setMetricsSourceValue(metricsSourceValue);
+            vo.setMetricsType(entry.getKey());
+            vo.setMetricsTypeValue(Long.toString(entry.getValue()));
+            vo.setMetricsTime(podMetricsList.size() == 1 ? LocalDateTime.parse(podMetricsList.get(0).getTimestamp()) : LocalDateTime.now());
+            return vo;
+
+        }).collect(Collectors.toList());
+        if (podMetricsList.size() == 1) {
+            // duration
+            MetricsVO durationVO = new MetricsVO();
+            durationVO.setMetricsSource(metricsSource);
+            durationVO.setMetricsSourceValue(metricsSourceValue);
+            durationVO.setMetricsType(MetricsType.DURATION.getCode());
+            durationVO.setMetricsTypeValue(podMetricsList.get(0).getWindow().toString());
+            result.add(durationVO);
+        }
+        return result;
+    }
+
+    public List<MetricsVO> statNodeMetrics(List<NodeMetrics> nodeMetricsList, MetricsSource metricsSource, String metricsSourceValue) {
+        if (nodeMetricsList == null || nodeMetricsList.isEmpty()) {
+            return Collections.emptyList();
+        }
+        List<MetricsVO> result;
+        Map<String, Long> values = new HashMap<>();
+        nodeMetricsList.forEach(nodeMetrics ->  {
+            Map<String, Quantity> metricValues = nodeMetrics.getUsage();
+            metricValues.forEach((key, quantity) -> {
+                if (values.get(key) != null) {
+                    values.put(key, values.get(key) + Long.parseLong(quantity.getAmount()));
+                } else {
+                    values.put(key, Long.parseLong(quantity.getAmount()));
+                }
+            });
+        });
+        result = values.entrySet().stream().map(entry -> {
+            MetricsVO vo = new MetricsVO();
+            vo.setMetricsSource(metricsSource);
+            vo.setMetricsSourceValue(metricsSourceValue);
+            vo.setMetricsType(entry.getKey());
+            vo.setMetricsTypeValue(Long.toString(entry.getValue()));
+            vo.setMetricsTime(nodeMetricsList.size() == 1 ? LocalDateTime.parse(nodeMetricsList.get(0).getTimestamp()) : LocalDateTime.now());
+            return vo;
+
+        }).collect(Collectors.toList());
+        if (nodeMetricsList.size() == 1) {
+            // duration
+            MetricsVO durationVO = new MetricsVO();
+            durationVO.setMetricsSource(metricsSource);
+            durationVO.setMetricsSourceValue(metricsSourceValue);
+            durationVO.setMetricsType(MetricsType.DURATION.getCode());
+            durationVO.setMetricsTypeValue(nodeMetricsList.get(0).getWindow().toString());
+            result.add(durationVO);
+        }
+        return result;
+    }
+}

+ 20 - 0
src/main/java/cn/seecoder/paas/service/model/converter/MetricsConverter.java

@@ -0,0 +1,20 @@
+package cn.seecoder.paas.service.model.converter;
+
+import cn.seecoder.paas.data.entity.Metrics;
+import cn.seecoder.paas.service.model.vo.MetricsVO;
+import org.springframework.beans.BeanUtils;
+
+public class MetricsConverter {
+
+    public static MetricsVO convertToVO(Metrics metrics) {
+        MetricsVO vo = new MetricsVO();
+        BeanUtils.copyProperties(metrics, vo);
+        return vo;
+    }
+
+    public static Metrics convertToEntity(MetricsVO vo) {
+        Metrics metrics = new Metrics();
+        BeanUtils.copyProperties(vo, metrics);
+        return metrics;
+    }
+}

+ 22 - 0
src/main/java/cn/seecoder/paas/service/model/vo/MetricsVO.java

@@ -0,0 +1,22 @@
+package cn.seecoder.paas.service.model.vo;
+
+import cn.seecoder.paas.util.enums.MetricsSource;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Data
+public class MetricsVO {
+
+    private Integer id;
+
+    private MetricsSource metricsSource;
+
+    private String metricsSourceValue;
+
+    private String metricsType;
+
+    private String metricsTypeValue;
+
+    private LocalDateTime metricsTime;
+}

+ 32 - 0
src/main/java/cn/seecoder/paas/util/enums/MetricsSource.java

@@ -0,0 +1,32 @@
+package cn.seecoder.paas.util.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@AllArgsConstructor
+@Getter
+public enum MetricsSource {
+    APPLICATION("application", "应用"),
+
+    ENVIRONMENT("environment", "环境"),
+
+    NODE("node", "节点"),
+
+    POD("pod", "pod"),
+
+    CLUSTER("cluster", "集群")
+    ;
+
+    private String code;
+
+    private String desc;
+
+    public static MetricsSource getByCode(String code) {
+        for (MetricsSource objs : MetricsSource.values()) {
+            if (objs.getCode().equals(code)) {
+                return objs;
+            }
+        }
+        return null;
+    }
+}

+ 28 - 0
src/main/java/cn/seecoder/paas/util/enums/MetricsType.java

@@ -0,0 +1,28 @@
+package cn.seecoder.paas.util.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@AllArgsConstructor
+@Getter
+public enum MetricsType {
+    CPU("cpu", "cpu"),
+
+    MEMORY("memory", "内存"),
+
+    DURATION("duration", "运行时间")
+    ;
+
+    private String code;
+
+    private String desc;
+
+    public static MetricsType getByCode(String code) {
+        for (MetricsType objs : MetricsType.values()) {
+            if (objs.getCode().equals(code)) {
+                return objs;
+            }
+        }
+        return null;
+    }
+}

+ 36 - 0
src/main/java/cn/seecoder/paas/web/controller/api/MetricsController.java

@@ -0,0 +1,36 @@
+package cn.seecoder.paas.web.controller.api;
+
+import cn.seecoder.paas.service.MetricsService;
+import cn.seecoder.paas.util.ServiceException;
+import cn.seecoder.paas.util.enums.MetricsSource;
+import cn.seecoder.paas.util.enums.MetricsType;
+import cn.seecoder.paas.web.model.Response;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.time.LocalDateTime;
+
+@RestController
+@RequestMapping("/api/metrics")
+public class MetricsController {
+
+    private final MetricsService metricsService;
+
+    @Autowired
+    public MetricsController(MetricsService metricsService) {
+        this.metricsService = metricsService;
+    }
+
+    @GetMapping("/current")
+    public Response getCurrnetStatus(@RequestParam String metricsSource, @RequestParam String metricsSourceValue) throws ServiceException {
+        MetricsSource ms = MetricsSource.getByCode(metricsSource);
+        return Response.buildSuccess(metricsService.getMetricsSourceCurrentStatus(ms, metricsSourceValue));
+    }
+
+    @GetMapping("")
+    public Response getBetweenTime(@RequestParam String metricsSource, @RequestParam String metricsSourceValue, @RequestParam String metricsType, @RequestParam String startTime, @RequestParam String endTime) throws ServiceException {
+        MetricsSource ms = MetricsSource.getByCode(metricsSource);
+        MetricsType mt = MetricsType.getByCode(metricsType);
+        return Response.buildSuccess(metricsService.getMetricsBySourceAndTypeBetween(ms, metricsSourceValue, mt, LocalDateTime.parse(startTime), LocalDateTime.parse(endTime)));
+    }
+}