Merge branch 'develop-zw' into develop

# Conflicts:
#	app/nacos.go
#	main.go
This commit is contained in:
zw 2022-11-10 17:06:03 +08:00
commit ac2caf1293
24 changed files with 4432 additions and 1115 deletions

View File

@ -94,8 +94,7 @@ type ProxyCluster struct {
// @Failure 500
// @Router /api/v1/cluster/list [get]
func ListCluster(c *gin.Context) {
clusterName, _ := c.GetQuery("cluster_name")
clusterName := c.Query("cluster_name")
clusterList := make([]Cluster, 0)
clusters, err := KarmadaClient.ClusterV1alpha1().Clusters().List(context.TODO(), metav1.ListOptions{})
if err != nil {
@ -136,11 +135,9 @@ func ListCluster(c *gin.Context) {
total := len(clusterList)
page := &Page[Cluster]{}
page.List = clusterList
pageNum, _ := c.GetQuery("pageNum")
pageSize, _ := c.GetQuery("pageSize")
num, _ := strconv.ParseInt(pageNum, 10, 64)
size, _ := strconv.ParseInt(pageSize, 10, 64)
data := Paginator(page, int64(total), num, size)
pageNum := c.Query("pageNum")
pageSize := c.Query("pageSize")
data := Paginator(page, int64(total), pageNum, pageSize)
Response(c, http.StatusOK, "success", data)
}
@ -157,7 +154,7 @@ func ListCluster(c *gin.Context) {
// @Router /api/v1/cluster/listWithLabel [get]
func ListClusterWithLabel(c *gin.Context) {
clusterName, _ := c.GetQuery("cluster_name")
clusterName := c.Query("cluster_name")
clusterList := make([]Cluster, 0)
clusters, err := KarmadaClient.ClusterV1alpha1().Clusters().List(context.TODO(), metav1.ListOptions{})
@ -204,11 +201,9 @@ func ListClusterWithLabel(c *gin.Context) {
total := len(clusterList)
page := &Page[Cluster]{}
page.List = clusterList
pageNum, _ := c.GetQuery("pageNum")
pageSize, _ := c.GetQuery("pageSize")
num, _ := strconv.ParseInt(pageNum, 10, 64)
size, _ := strconv.ParseInt(pageSize, 10, 64)
data := Paginator(page, int64(total), num, size)
pageNum := c.Query("pageNum")
pageSize := c.Query("pageSize")
data := Paginator(page, int64(total), pageNum, pageSize)
Response(c, http.StatusOK, "success", data)
}
@ -224,8 +219,8 @@ func ListClusterWithLabel(c *gin.Context) {
// @Router /api/v1/cluster/unJoin [delete]
func UnJoin(c *gin.Context) {
copyContext := c.Copy()
clusterName, _ := c.GetQuery("cluster_name")
domainId, _ := c.GetQuery("domain_id")
clusterName := c.Query("cluster_name")
domainId := c.Query("domain_id")
if clusterName == "" || domainId == "" {
Response(c, http.StatusBadRequest, "invalid request params.", "")
return
@ -426,7 +421,7 @@ func ClusterExist(c *gin.Context) {
glog.Info("failed to retrieve cluster(%s). error: %v", clusters, err)
Response(c, http.StatusBadRequest, "failed to retrieve cluster", err)
}
clusterName := c.Param("clusterName")
clusterName := c.Query("clusterName")
//遍历集群
for i := 0; i < len(clusters.Items); i++ {
if clusters.Items[i].Name == clusterName {
@ -519,9 +514,9 @@ func deleteMaps(labels map[string]string, keys map[string]string) {
// @Failure 500
// @Router /api/v1/cluster/listByDomain [post]
func ListByDomain(c *gin.Context) {
namespaceName, _ := c.GetQuery("namespace")
deploymentName, _ := c.GetQuery("deployment_name")
domainId, _ := c.GetQuery("domain_id")
namespaceName := c.Query("namespace")
deploymentName := c.Query("deployment_name")
domainId := c.Query("domain_id")
//
deployJson := GetDeployFromOS(namespaceName, deploymentName, "")

View File

@ -2,6 +2,7 @@ package app
import (
"context"
"encoding/json"
"github.com/gin-gonic/gin"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@ -14,12 +15,30 @@ type ConfigMap struct {
TemplateId string `json:"templateId"`
}
type SecretRes struct {
Kind string `json:"kind"`
ApiVersion string `json:"apiVersion"`
Metadata string `json:"metadata"`
ResourceVersion string `json:"resourceVersion"`
Items []v1.Secret `json:"items"`
}
type ConfigMaoObject struct {
Kind string `json:"kind"`
ApiVersion string `json:"apiVersion"`
Metadata string `json:"metadata"`
ResourceVersion string `json:"resourceVersion"`
Items []v1.ConfigMap `json:"items"`
}
// CreateConfigMap 创建configMap
func CreateConfigMap(c *gin.Context) {
var cmRequest ConfigMap
if err := c.BindJSON(&cmRequest); err != nil {
Response(c, http.StatusBadRequest, "invalid request params.", "")
return
}
cmRequest.ConfigMap.Labels["jcce"] = "true"
ClientSet.CoreV1().ConfigMaps(cmRequest.ConfigMap.Namespace).Create(context.TODO(), &cmRequest.ConfigMap, metav1.CreateOptions{})
// 创建调度策略实例
CreatePropagationPolicies(PropagationPolicy{
@ -32,3 +51,25 @@ func CreateConfigMap(c *gin.Context) {
})
Response(c, http.StatusOK, "success", nil)
}
// ListSecret 查询命名空间下的secret
func ListSecret(c *gin.Context) {
clusterName := c.Query("clusterName")
namespace := c.Query("namespace")
result := SearchObject(secretConst, clusterName, namespace, "")
raw, _ := result.Raw()
var secretRes SecretRes
json.Unmarshal(raw, &secretRes)
Response(c, http.StatusOK, "success", secretRes.Items)
}
// ListConfigMap 查询命名空间下的configMap
func ListConfigMap(c *gin.Context) {
clusterName := c.Query("clusterName")
namespace := c.Query("namespace")
result := SearchObject(configMapConst, clusterName, namespace, "")
raw, _ := result.Raw()
var configMaoObject ConfigMaoObject
json.Unmarshal(raw, &configMaoObject)
Response(c, http.StatusOK, "success", configMaoObject.Items)
}

View File

@ -1,9 +1,13 @@
package app
import (
"context"
"encoding/json"
"fmt"
"github.com/gin-gonic/gin"
v1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"strings"
"net/http"
)
@ -16,11 +20,70 @@ type CRDRes struct {
Items []v1.CustomResourceDefinition `json:"items"`
}
type CRDParam struct {
ClusterName []string `json:"clusterName"`
Domain string `json:"domain"`
TemplateId string `json:"templateId"`
CustomResourceDefinition v1.CustomResourceDefinition `json:"CustomResourceDefinition"`
}
func ListCRD(c *gin.Context) {
clusterName := c.Param("clusterName")
clusterName := c.Query("clusterName")
Response(c, http.StatusOK, "success", queryCRD(clusterName))
}
func queryCRD(clusterName string) []v1.CustomResourceDefinition {
result := SearchObject(crdConst, clusterName, "", "")
raw, _ := result.Raw()
var cRDRes CRDRes
json.Unmarshal(raw, &cRDRes)
Response(c, http.StatusOK, "success", cRDRes.Items)
return cRDRes.Items
}
const crUrl = "/apis/cluster.karmada.io/v1alpha1/clusters/%s/proxy/apis/%s/namespaces/%s/%s"
func CreateCRD(c *gin.Context) {
var param CRDParam
if err := c.BindJSON(&param); err != nil {
Response(c, http.StatusBadRequest, "invalid request params.", "")
return
}
crdList, err := CrDClient.ApiextensionsV1().CustomResourceDefinitions().Create(context.TODO(), &param.CustomResourceDefinition, metav1.CreateOptions{})
if err != nil {
return
}
// 创建调度实例
CreatePropagationPolicies(PropagationPolicy{
ClusterName: param.ClusterName,
TemplateId: param.TemplateId,
ResourceName: param.CustomResourceDefinition.Name,
Name: "CustomResourceDefinition" + param.CustomResourceDefinition.Namespace + param.CustomResourceDefinition.Name,
Namespace: param.CustomResourceDefinition.Namespace,
Kind: "CustomResourceDefinition",
})
Response(c, http.StatusOK, "success", crdList)
}
func DetailCRD(c *gin.Context) {
clusterName := c.Query("clusterName")
namespace := c.Query("namespace")
kind := c.Query("kind")
customResourceDefinitions := queryCRD(clusterName)
for _, crd := range customResourceDefinitions {
if strings.EqualFold(crd.Spec.Names.Plural, kind) || strings.EqualFold(crd.Spec.Names.Singular, kind) {
url := fmt.Sprintf(crUrl, clusterName, crd.Spec.Group+"/"+crd.Spec.Versions[0].Name, namespace, crd.Spec.Names.Plural)
result := KarmadaClient.SearchV1alpha1().RESTClient().Get().AbsPath(url).Do(context.TODO())
raw, _ := result.Raw()
Response(c, http.StatusOK, "success", raw)
}
}
//if err != nil {
// return
//}
//Response(c, http.StatusOK, "success", crdList)
}

View File

@ -2,75 +2,60 @@ package app
import (
"context"
"encoding/json"
"github.com/bitly/go-simplejson"
"github.com/gin-gonic/gin"
appv1 "k8s.io/api/apps/v1"
v12 "k8s.io/api/autoscaling/v1"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"net/http"
"sort"
"strconv"
"strings"
"sync"
"time"
)
var deployMutex sync.Mutex
type HPAResult struct {
MinReplicas int32 `json:"minReplicas"`
MaxReplicas int32 `json:"maxReplicas"`
MemoryTargetValue string `json:"memoryTargetValue"`
CpuTargetUtilization string `json:"cpuTargetUtilization"`
}
type DeploymentParam struct {
ClusterName []string `json:"clusterName"`
TemplateId string `json:"templateId"`
Deployment appv1.Deployment `json:"deployment"`
}
type DeploymentParamSwagger struct {
ClusterName []string `json:"clusterName"`
TemplateId string `json:"templateId"`
Deployment struct {
APIVersion string `json:"apiVersion"`
Kind string `json:"kind"`
Metadata struct {
Namespace string `json:"namespace"`
Labels struct {
} `json:"labels"`
Name string `json:"name"`
Annotations struct {
KubesphereIoCreator string `json:"kubesphere.io/creator"`
} `json:"annotations"`
} `json:"metadata"`
Spec struct {
Replicas int `json:"replicas"`
Selector struct {
MatchLabels struct {
} `json:"matchLabels"`
} `json:"selector"`
Template struct {
Metadata struct {
Labels struct {
} `json:"labels"`
} `json:"metadata"`
Spec struct {
Containers []struct {
Name string `json:"name"`
ImagePullPolicy string `json:"imagePullPolicy"`
Image string `json:"image"`
Ports []struct {
Name string `json:"name"`
Protocol string `json:"protocol"`
ContainerPort int `json:"containerPort"`
} `json:"ports"`
} `json:"containers"`
ServiceAccount string `json:"serviceAccount"`
InitContainers []interface{} `json:"initContainers"`
Volumes []interface{} `json:"volumes"`
ImagePullSecrets interface{} `json:"imagePullSecrets"`
} `json:"spec"`
} `json:"template"`
Strategy struct {
Type string `json:"type"`
RollingUpdate struct {
MaxUnavailable string `json:"maxUnavailable"`
MaxSurge string `json:"maxSurge"`
} `json:"rollingUpdate"`
} `json:"strategy"`
} `json:"spec"`
} `json:"deployment"`
type HPAParam struct {
ClusterName []string `json:"clusterName"`
TemplateId string `json:"templateId"`
Hpa v12.HorizontalPodAutoscaler `json:"hpa"`
}
type StatefulSetParam struct {
ClusterName []string `json:"clusterName"`
TemplateId string `json:"templateId"`
StatefulSet appv1.StatefulSet `json:"statefulSet"`
}
type DaemonSetParam struct {
ClusterName []string `json:"clusterName"`
TemplateId string `json:"templateId"`
DaemonSet appv1.DaemonSet `json:"daemonSet"`
}
type RedeployParam struct {
ClusterName string `json:"clusterName"`
Namespace string `json:"namespace"`
DeploymentName string `json:"deploymentName"`
Num string `json:"num"`
Type string `json:"type"`
}
type DeploymentRes struct {
@ -82,12 +67,52 @@ type DeploymentRes struct {
Replicas int32 `json:"replicas"`
}
type DeploymentObject struct {
Kind string `json:"kind"`
ApiVersion string `json:"apiVersion"`
Metadata string `json:"metadata"`
ResourceVersion string `json:"resourceVersion"`
Items []appv1.Deployment `json:"items"`
}
type ControllerRevisionObject struct {
Kind string `json:"kind"`
ApiVersion string `json:"apiVersion"`
Metadata string `json:"metadata"`
ResourceVersion string `json:"resourceVersion"`
Items []appv1.ControllerRevision `json:"items"`
}
type ReplicaSetObject struct {
Kind string `json:"kind"`
ApiVersion string `json:"apiVersion"`
Metadata string `json:"metadata"`
ResourceVersion string `json:"resourceVersion"`
Items []appv1.ReplicaSet `json:"items"`
}
type StatefulSetObject struct {
Kind string `json:"kind"`
ApiVersion string `json:"apiVersion"`
Metadata string `json:"metadata"`
ResourceVersion string `json:"resourceVersion"`
Items []appv1.StatefulSet `json:"items"`
}
type DaemonSetObject struct {
Kind string `json:"kind"`
ApiVersion string `json:"apiVersion"`
Metadata string `json:"metadata"`
ResourceVersion string `json:"resourceVersion"`
Items []appv1.DaemonSet `json:"items"`
}
// CreateDeployment 创建工作负载
// @Summary 创建工作负载
// @Description 创建工作负载
// @Tags deployment
// @accept json
// @Produce json
// @Param param body DeploymentParamSwagger true "json"
// @Success 200
// @Failure 400
// @Router /api/v1/deployment/create [post]
@ -97,9 +122,10 @@ func CreateDeployment(c *gin.Context) {
Response(c, http.StatusBadRequest, "invalid request params.", "")
return
}
dpRequest.Deployment.Spec.Template.Labels = map[string]string{"jcce": "true"}
dpRequest.Deployment.Spec.Selector.MatchLabels = map[string]string{"jcce": "true"}
dpRequest.Deployment.Labels = map[string]string{"jcce": "true"}
if dpRequest.Deployment.Labels == nil {
dpRequest.Deployment.Labels = map[string]string{}
}
dpRequest.Deployment.Labels["jcce"] = "true"
deploymentList, err := ClientSet.AppsV1().Deployments(dpRequest.Deployment.Namespace).Create(context.TODO(), &dpRequest.Deployment, metav1.CreateOptions{})
if err != nil {
@ -110,12 +136,64 @@ func CreateDeployment(c *gin.Context) {
ClusterName: dpRequest.ClusterName,
TemplateId: dpRequest.TemplateId,
ResourceName: dpRequest.Deployment.Name,
Name: "DeploymentParam" + dpRequest.Deployment.Namespace + dpRequest.Deployment.Name,
Name: "Deployment" + "." + dpRequest.Deployment.Namespace + "." + dpRequest.Deployment.Name,
Namespace: dpRequest.Deployment.Namespace,
Kind: "DeploymentParam",
Kind: "Deployment",
})
Response(c, http.StatusOK, "success", deploymentList)
}
// ListDeploymentFromCluster 查询指定集群下的命名空间
func ListDeploymentFromCluster(c *gin.Context) {
clusterName := c.Query("clusterName")
namespace := c.Query("namespace")
name := c.Query("name")
state := c.Query("state")
pageNum := c.Query("pageNum")
pageSize := c.Query("pageSize")
searchObject := SearchObject(allDeploymentConst, clusterName, "", "")
raw, _ := searchObject.Raw()
var deploymentObject DeploymentObject
json.Unmarshal(raw, &deploymentObject)
deployments := deploymentObject.Items
// 根据条件过滤
count := 0
for i := range deployments {
if len(namespace) != 0 && !strings.EqualFold(deployments[i-count].Namespace, namespace) {
deployments = append(deployments[:i-count], deployments[i-count+1:]...)
count = count + 1
continue
}
if len(name) != 0 && !strings.Contains(deployments[i-count].Name, name) {
deployments = append(deployments[:i-count], deployments[i-count+1:]...)
count = count + 1
continue
}
if strings.EqualFold(state, "updating") && deployments[i-count].Status.UnavailableReplicas == 0 {
deployments = append(deployments[:i-count], deployments[i-count+1:]...)
count = count + 1
continue
}
if strings.EqualFold(state, "running") && deployments[i-count].Status.ReadyReplicas != deployments[i-count].Status.Replicas {
deployments = append(deployments[:i-count], deployments[i-count+1:]...)
count = count + 1
continue
}
if strings.EqualFold(state, "stopped") && deployments[i-count].Status.Replicas != 0 {
deployments = append(deployments[:i-count], deployments[i-count+1:]...)
count = count + 1
continue
}
}
// 分页
page := &Page[appv1.Deployment]{}
// 排序
sort.SliceStable(deployments, func(i, j int) bool {
return deployments[i].CreationTimestamp.Time.After(deployments[j].CreationTimestamp.Time)
})
page.List = deployments
data := Paginator(page, int64(len(deployments)), pageNum, pageSize)
Response(c, http.StatusOK, "success", data)
}
// ListDeployment 根据查询工作负载列表(控制平面)
@ -132,7 +210,7 @@ func CreateDeployment(c *gin.Context) {
// @Router /api/v1/deployment/list [get]
func ListDeployment(c *gin.Context) {
namespace, _ := c.GetQuery("namespace")
namespace := c.Query("namespace")
dpList := make([]DeploymentRes, 0)
deploymentList, err := ClientSet.AppsV1().Deployments(namespace).List(context.TODO(), metav1.ListOptions{})
@ -163,17 +241,14 @@ func ListDeployment(c *gin.Context) {
total := len(dpList)
page := &Page[DeploymentRes]{}
page.List = dpList
pageNum, _ := c.GetQuery("pageNum")
pageSize, _ := c.GetQuery("pageSize")
num, _ := strconv.ParseInt(pageNum, 10, 64)
size, _ := strconv.ParseInt(pageSize, 10, 64)
data := Paginator(page, int64(total), num, size)
pageNum := c.Query("pageNum")
pageSize := c.Query("pageSize")
data := Paginator(page, int64(total), pageNum, pageSize)
Response(c, http.StatusOK, "success", data)
}
// ListClusterDeployment 查询工作负载列表(所有集群)
func ListClusterDeployment(c *gin.Context) {
//TODO 逻辑待完善
ss, _ := KarmadaClient.SearchV1alpha1().ResourceRegistries().Get(context.TODO(), "clustercache-sample", metav1.GetOptions{})
@ -181,6 +256,92 @@ func ListClusterDeployment(c *gin.Context) {
Response(c, http.StatusOK, "success", ss)
}
// DetailDeployment 根据Deployment名查询Deployment详情
func DetailDeployment(c *gin.Context) {
clusterName := c.Query("clusterName")
namespace := c.Query("namespace")
name := c.Query("name")
searchObject := SearchObject(deploymentConst, clusterName, namespace, name)
raw, _ := searchObject.Raw()
var deployment appv1.Deployment
json.Unmarshal(raw, &deployment)
Response(c, http.StatusOK, "success", deployment)
}
func DetailDaemonSet(c *gin.Context) {
clusterName := c.Query("clusterName")
namespace := c.Query("namespace")
name := c.Query("name")
searchObject := SearchObject(daemonSetConst, clusterName, namespace, name)
raw, _ := searchObject.Raw()
var daemonSet appv1.DaemonSet
json.Unmarshal(raw, &daemonSet)
Response(c, http.StatusOK, "success", daemonSet)
}
func ListStatefulSetFromCluster(c *gin.Context) {
clusterName := c.Query("clusterName")
namespace := c.Query("namespace")
name := c.Query("name")
state := c.Query("state")
pageNum := c.Query("pageNum")
pageSize := c.Query("pageSize")
searchObject := SearchObject(allStatefulSetConst, clusterName, "", "")
raw, _ := searchObject.Raw()
var statefulSetObject StatefulSetObject
json.Unmarshal(raw, &statefulSetObject)
statefulSets := statefulSetObject.Items
// 根据条件过滤
count := 0
for i := range statefulSets {
if len(namespace) != 0 && !strings.EqualFold(statefulSets[i-count].Namespace, namespace) {
statefulSets = append(statefulSets[:i-count], statefulSets[i-count+1:]...)
count = count + 1
continue
}
if len(name) != 0 && !strings.Contains(statefulSets[i-count].Name, name) {
statefulSets = append(statefulSets[:i-count], statefulSets[i-count+1:]...)
count = count + 1
continue
}
if strings.EqualFold(state, "updating") && statefulSets[i-count].Status.UpdatedReplicas == 0 {
statefulSets = append(statefulSets[:i-count], statefulSets[i-count+1:]...)
count = count + 1
continue
}
if strings.EqualFold(state, "running") && statefulSets[i-count].Status.ReadyReplicas != statefulSets[i-count].Status.Replicas {
statefulSets = append(statefulSets[:i-count], statefulSets[i-count+1:]...)
count = count + 1
continue
}
if strings.EqualFold(state, "stopped") && statefulSets[i-count].Status.Replicas != 0 {
statefulSets = append(statefulSets[:i-count], statefulSets[i-count+1:]...)
count = count + 1
continue
}
}
// 分页
page := &Page[appv1.StatefulSet]{}
// 排序
sort.SliceStable(statefulSets, func(i, j int) bool {
return statefulSets[i].CreationTimestamp.Time.After(statefulSets[j].CreationTimestamp.Time)
})
page.List = statefulSets
data := Paginator(page, int64(len(statefulSets)), pageNum, pageSize)
Response(c, http.StatusOK, "success", data)
}
func DetailStatefulSet(c *gin.Context) {
clusterName := c.Query("clusterName")
namespace := c.Query("namespace")
name := c.Query("name")
searchObject := SearchObject(statefulSetConst, clusterName, namespace, name)
raw, _ := searchObject.Raw()
var statefulSet appv1.StatefulSet
json.Unmarshal(raw, &statefulSet)
Response(c, http.StatusOK, "success", statefulSet)
}
// DescribeDeployment 查询工作负载列表(所有集群)
// @Summary 查询工作负载列表(所有集群)
// @Description 查询工作负载列表(所有集群)
@ -194,8 +355,8 @@ func ListClusterDeployment(c *gin.Context) {
// @Router /api/v1/deployment/describe [get]
func DescribeDeployment(c *gin.Context) {
namespace, _ := c.GetQuery("namespace")
deployName, _ := c.GetQuery("deploy_name")
namespace := c.Query("namespace")
deployName := c.Query("deploy_name")
ClientSet.CoreV1().Pods(namespace).List(context.TODO(), metav1.ListOptions{})
podList := make([]Pod, 0)
pods := GetPodFromOS(namespace, deployName)
@ -268,14 +429,565 @@ func DescribeDeployment(c *gin.Context) {
// @Failure 400
// @Router /api/v1/deployment/delete/{namespace}/{name} [delete]
func DeleteDeployment(c *gin.Context) {
clusterName := c.Param("clusterName")
namespace := c.Param("namespace")
name := c.Param("name")
err := ClientSet.AppsV1().Deployments(namespace).Delete(context.TODO(), name, metav1.DeleteOptions{})
if err != nil {
Response(c, http.StatusInternalServerError, "delete deployment failed", err)
return
label := c.Param("label")
if strings.EqualFold(label, "jcce") {
err := ClientSet.AppsV1().Deployments(namespace).Delete(context.TODO(), name, metav1.DeleteOptions{})
if err != nil {
Response(c, http.StatusInternalServerError, "delete deployment failed", err)
return
}
// 删除调度策略
DeletePropagationPolicies(namespace, "Deployment"+"."+namespace+"."+name)
} else {
result := DeleteObject(deploymentConst, clusterName, namespace, name)
if result.Error() != nil {
Response(c, http.StatusInternalServerError, "delete deployment failed", result.Error())
return
}
}
// 删除调度策略
DeletePropagationPolicies(namespace, "pod"+namespace+name)
Response(c, http.StatusOK, "success", nil)
}
func ListDaemonSetFromCluster(c *gin.Context) {
clusterName := c.Query("clusterName")
namespace := c.Query("namespace")
name := c.Query("name")
state := c.Query("state")
pageNum := c.Query("pageNum")
pageSize := c.Query("pageSize")
searchObject := SearchObject(allDaemonSetConst, clusterName, "", "")
raw, _ := searchObject.Raw()
var daemonSetObject DaemonSetObject
json.Unmarshal(raw, &daemonSetObject)
daemonSets := daemonSetObject.Items
// 根据条件过滤
count := 0
for i := range daemonSets {
if len(namespace) != 0 && !strings.EqualFold(daemonSets[i-count].Namespace, namespace) {
daemonSets = append(daemonSets[:i-count], daemonSets[i-count+1:]...)
count = count + 1
continue
}
if len(name) != 0 && !strings.Contains(daemonSets[i-count].Name, name) {
daemonSets = append(daemonSets[:i-count], daemonSets[i-count+1:]...)
count = count + 1
continue
}
if strings.EqualFold(state, "updating") && daemonSets[i-count].Status.UpdatedNumberScheduled == 0 {
daemonSets = append(daemonSets[:i-count], daemonSets[i-count+1:]...)
count = count + 1
continue
}
if strings.EqualFold(state, "running") && daemonSets[i-count].Status.CurrentNumberScheduled != daemonSets[i-count].Status.NumberReady {
daemonSets = append(daemonSets[:i-count], daemonSets[i-count+1:]...)
count = count + 1
continue
}
if strings.EqualFold(state, "stopped") && daemonSets[i-count].Status.CurrentNumberScheduled != 0 {
daemonSets = append(daemonSets[:i-count], daemonSets[i-count+1:]...)
count = count + 1
continue
}
}
// 分页
page := &Page[appv1.DaemonSet]{}
// 排序
sort.SliceStable(daemonSets, func(i, j int) bool {
return daemonSets[i].CreationTimestamp.Time.After(daemonSets[j].CreationTimestamp.Time)
})
page.List = daemonSets
data := Paginator(page, int64(len(daemonSets)), pageNum, pageSize)
Response(c, http.StatusOK, "success", data)
}
func IsExistDaemonSet(c *gin.Context) {
clusterName := c.Query("clusterName")
namespace := c.Query("namespace")
name := c.Query("name")
result := SearchObject(daemonSetConst, clusterName, namespace, name)
if result.Error() != nil {
Response(c, http.StatusOK, "success", false)
return
}
raw, _ := result.Raw()
var daemonSet appv1.DaemonSet
json.Unmarshal(raw, &daemonSet)
if len(daemonSet.Name) == 0 {
Response(c, http.StatusOK, "success", false)
return
}
Response(c, http.StatusOK, "success", true)
}
func IsExistStatefulSet(c *gin.Context) {
clusterName := c.Query("clusterName")
namespace := c.Query("namespace")
name := c.Query("name")
result := SearchObject(statefulSetConst, clusterName, namespace, name)
if result.Error() != nil {
Response(c, http.StatusOK, "success", false)
return
}
raw, _ := result.Raw()
var statefulSet appv1.StatefulSet
json.Unmarshal(raw, &statefulSet)
if len(statefulSet.Name) == 0 {
Response(c, http.StatusOK, "success", false)
return
}
Response(c, http.StatusOK, "success", true)
}
// @Summary 获取弹性伸缩信息
// @Description 获取弹性伸缩信息
// @Tags deployment
// @accept json
// @Produce json
// @Param clusterName query string true "集群名称"
// @Param namespace query string true "命名空间"
// @Param deployName query string true "deployName"
// @Success 200
// @Failure 400
// @Router /api/v1/deployment/hpa [get]
func getHpa(c *gin.Context) {
clusterName := c.Query("clusterName")
namespace := c.Query("namespace")
name := c.Query("name")
var hpa v12.HorizontalPodAutoscaler
result := SearchObject(detailHPAConst, clusterName, namespace, name)
raw, err := result.Raw()
if err != nil {
Response(c, http.StatusOK, "the server could not find the requested resource", "")
return
}
json.Unmarshal(raw, &hpa)
Response(c, http.StatusOK, "success", hpa)
}
// @Summary 弹性伸缩
// @Description 弹性伸缩
// @Tags deployment
// @accept json
// @Produce json
// @Param param body HPAParam true "json"
// @Success 200
// @Failure 400
// @Router /api/v1/deployment/autoScaling [post]
func AutoScaling(c *gin.Context) {
clusterName := c.Query("clusterName")
var hpa v12.HorizontalPodAutoscaler
if err := c.BindJSON(&hpa); err != nil {
Response(c, http.StatusBadRequest, "invalid request params.", "")
return
}
if len(hpa.Labels["jcce"]) != 0 {
_, err := ClientSet.AutoscalingV1().HorizontalPodAutoscalers(hpa.Namespace).Update(context.TODO(), &hpa, metav1.UpdateOptions{})
if err != nil {
Response(c, http.StatusInternalServerError, "update hpa failed", err)
return
}
} else {
result := UpdateObject(detailHPAConst, clusterName, hpa.Namespace, hpa.Name, hpa)
if result.Error() != nil {
Response(c, http.StatusInternalServerError, "update hpa failed", result.Error())
return
}
}
Response(c, http.StatusOK, "success", "")
}
// @Summary 创建弹性伸缩
func CreateHpa(c *gin.Context) {
var param HPAParam
if err := c.BindJSON(&param); err != nil {
Response(c, http.StatusBadRequest, "invalid request params.", "")
return
}
// 查询deployment来源
searchObject := SearchObject(deploymentConst, param.ClusterName[0], param.Hpa.Namespace, param.Hpa.Spec.ScaleTargetRef.Name)
raw, _ := searchObject.Raw()
var deployment appv1.Deployment
json.Unmarshal(raw, &deployment)
if len(deployment.Labels["jcce"]) != 0 {
if param.Hpa.Labels == nil {
param.Hpa.Labels = map[string]string{}
}
param.Hpa.Labels["jcce"] = "true"
_, err := ClientSet.AutoscalingV1().HorizontalPodAutoscalers(param.Hpa.Namespace).Create(context.TODO(), &param.Hpa, metav1.CreateOptions{})
if err != nil {
Response(c, http.StatusInternalServerError, "create hpa failed.", err)
return
}
CreatePropagationPolicies(PropagationPolicy{
ClusterName: param.ClusterName,
TemplateId: param.TemplateId,
ResourceName: param.Hpa.Name,
Name: "hpa" + "." + param.Hpa.Namespace + "." + param.Hpa.Name,
Namespace: param.Hpa.Namespace,
Kind: "HorizontalPodAutoscaler",
})
} else {
postObject := PostObject(hpaListConst, param.ClusterName[0], param.Hpa.Namespace, "", param.Hpa)
if postObject.Error() != nil {
Response(c, http.StatusInternalServerError, "create hpa failed.", postObject.Error())
return
}
}
Response(c, http.StatusOK, "success", "")
}
func UpdateDeployment(c *gin.Context) {
clusterName := c.Query("clusterName")
var deployment appv1.Deployment
if err := c.BindJSON(&deployment); err != nil {
Response(c, http.StatusBadRequest, "invalid request params.", "")
return
}
if len(deployment.Labels["jcce"]) != 0 {
_, err := ClientSet.AppsV1().Deployments(deployment.Namespace).Update(context.TODO(), &deployment, metav1.UpdateOptions{})
if err != nil {
Response(c, http.StatusInternalServerError, "failed", err)
return
}
} else {
result := UpdateObject(deploymentConst, clusterName, deployment.Namespace, deployment.Name, deployment)
if result.Error() != nil {
Response(c, http.StatusInternalServerError, "update deployment failed", result.Error())
return
}
}
Response(c, http.StatusOK, "success", "")
}
// @Summary 重新部署
// @Description 重新部署
// @Tags deployment
// @accept json
// @Produce json
// @Param param body RedeployParam true "json"
// @Success 200
// @Failure 500
// @Router /api/v1/deployment/deployments/redeploy [patch]
func Redeploy(c *gin.Context) {
var param RedeployParam
if err := c.BindJSON(&param); err != nil {
Response(c, http.StatusBadRequest, "invalid request params.", "")
return
}
if param.Type == "deploy" {
deployment, err := ClientSet.AppsV1().Deployments(param.Namespace).Get(context.TODO(), param.DeploymentName, metav1.GetOptions{})
if err != nil {
Response(c, http.StatusInternalServerError, "failed", err)
return
}
deployment.Spec.Template.Spec.Containers[0].Env = append(deployment.Spec.Template.Spec.Containers[0].Env, v1.EnvVar{Name: "RESTART_TIME", Value: time.Now().String()})
ClientSet.AppsV1().Deployments(param.Namespace).Update(context.TODO(), deployment, metav1.UpdateOptions{})
} else if param.Type == "sts" {
statefulSet, err := ClientSet.AppsV1().StatefulSets(param.Namespace).Get(context.TODO(), param.DeploymentName, metav1.GetOptions{})
if err != nil {
Response(c, http.StatusInternalServerError, "failed", err)
return
}
statefulSet.Spec.Template.Spec.Containers[0].Env = append(statefulSet.Spec.Template.Spec.Containers[0].Env, v1.EnvVar{Name: "RESTART_TIME", Value: time.Now().String()})
ClientSet.AppsV1().StatefulSets(param.Namespace).Update(context.TODO(), statefulSet, metav1.UpdateOptions{})
} else if param.Type == "ds" {
daemonSet, err := ClientSet.AppsV1().DaemonSets(param.Namespace).Get(context.TODO(), param.DeploymentName, metav1.GetOptions{})
if err != nil {
Response(c, http.StatusInternalServerError, "failed", err)
return
}
daemonSet.Spec.Template.Spec.Containers[0].Env = append(daemonSet.Spec.Template.Spec.Containers[0].Env, v1.EnvVar{Name: "RESTART_TIME", Value: time.Now().String()})
ClientSet.AppsV1().DaemonSets(param.Namespace).Update(context.TODO(), daemonSet, metav1.UpdateOptions{})
}
Response(c, http.StatusOK, "success", nil)
}
func CreateStatefulSet(c *gin.Context) {
var param StatefulSetParam
if err := c.BindJSON(&param); err != nil {
Response(c, http.StatusBadRequest, "invalid request params.", "")
return
}
if param.StatefulSet.Labels == nil {
param.StatefulSet.Labels = map[string]string{}
}
param.StatefulSet.Labels["jcce"] = "true"
ssResult, err := ClientSet.AppsV1().StatefulSets(param.StatefulSet.Namespace).Create(context.TODO(), &param.StatefulSet, metav1.CreateOptions{})
if err != nil {
Response(c, http.StatusInternalServerError, "failed", err)
return
}
CreatePropagationPolicies(PropagationPolicy{
ClusterName: param.ClusterName,
TemplateId: param.TemplateId,
ResourceName: param.StatefulSet.Name,
Name: "StatefulSet" + "." + param.StatefulSet.Namespace + "." + param.StatefulSet.Name,
Namespace: param.StatefulSet.Namespace,
Kind: "StatefulSet",
})
Response(c, http.StatusOK, "success", ssResult)
}
// UpdateStatefulSet 更新statefulSet
func UpdateStatefulSet(c *gin.Context) {
clusterName := c.Query("clusterName")
var statefulSet appv1.StatefulSet
if err := c.BindJSON(&statefulSet); err != nil {
Response(c, http.StatusBadRequest, "invalid request params.", "")
return
}
if len(statefulSet.Labels["jcce"]) != 0 {
_, err := ClientSet.AppsV1().StatefulSets(statefulSet.Namespace).Update(context.TODO(), &statefulSet, metav1.UpdateOptions{})
if err != nil {
Response(c, http.StatusInternalServerError, "update statefulSet failed", err)
return
}
} else {
result := UpdateObject(statefulSetConst, clusterName, statefulSet.Namespace, statefulSet.Name, statefulSet)
if result.Error() != nil {
Response(c, http.StatusInternalServerError, "update statefulSet failed", result.Error())
return
}
}
Response(c, http.StatusOK, "success", "")
}
func UpdateDaemonSet(c *gin.Context) {
clusterName := c.Query("clusterName")
var daemonSet appv1.DaemonSet
if err := c.BindJSON(&daemonSet); err != nil {
Response(c, http.StatusBadRequest, "invalid request params.", "")
return
}
if len(daemonSet.Labels["jcce"]) != 0 {
_, err := ClientSet.AppsV1().DaemonSets(daemonSet.Namespace).Update(context.TODO(), &daemonSet, metav1.UpdateOptions{})
if err != nil {
Response(c, http.StatusInternalServerError, "failed", err)
return
}
} else {
result := UpdateObject(daemonSetConst, clusterName, daemonSet.Namespace, daemonSet.Name, daemonSet)
if result.Error() != nil {
Response(c, http.StatusInternalServerError, "update daemonSet failed", result.Error())
return
}
}
Response(c, http.StatusOK, "success", "")
}
func CreateDaemonSet(c *gin.Context) {
var param DaemonSetParam
if err := c.BindJSON(&param); err != nil {
Response(c, http.StatusBadRequest, "invalid request params.", "")
return
}
if param.DaemonSet.Labels == nil {
param.DaemonSet.Labels = map[string]string{}
}
param.DaemonSet.Labels["jcce"] = "true"
deResult, err := ClientSet.AppsV1().DaemonSets(param.DaemonSet.Namespace).Create(context.TODO(), &param.DaemonSet, metav1.CreateOptions{})
if err != nil {
Response(c, http.StatusInternalServerError, "failed", err)
return
}
CreatePropagationPolicies(PropagationPolicy{
ClusterName: param.ClusterName,
TemplateId: param.TemplateId,
ResourceName: param.DaemonSet.Name,
Name: "DaemonSet" + "." + param.DaemonSet.Namespace + "." + param.DaemonSet.Name,
Namespace: param.DaemonSet.Namespace,
Kind: "DaemonSet",
})
Response(c, http.StatusOK, "success", deResult)
}
func DeleteDaemonSet(c *gin.Context) {
clusterName := c.Param("clusterName")
namespace := c.Param("namespace")
name := c.Param("name")
label := c.Param("label")
if strings.EqualFold(label, "jcce") {
err := ClientSet.AppsV1().DaemonSets(namespace).Delete(context.TODO(), name, metav1.DeleteOptions{})
if err != nil {
Response(c, http.StatusInternalServerError, "delete deployment failed", err)
return
}
// 删除调度策略
DeletePropagationPolicies(namespace, "DaemonSet"+"."+namespace+"."+name)
} else {
result := DeleteObject(daemonSetConst, clusterName, namespace, name)
if result.Error() != nil {
Response(c, http.StatusInternalServerError, "delete daemonSet failed", result.Error())
return
}
Response(c, http.StatusOK, "success", nil)
}
}
func DeleteStatefulSet(c *gin.Context) {
clusterName := c.Param("clusterName")
namespace := c.Param("namespace")
name := c.Param("name")
label := c.Param("label")
if strings.EqualFold(label, "jcce") {
err := ClientSet.AppsV1().StatefulSets(namespace).Delete(context.TODO(), name, metav1.DeleteOptions{})
if err != nil {
Response(c, http.StatusInternalServerError, "delete deployment failed", err)
return
}
// 删除调度策略
DeletePropagationPolicies(namespace, "StatefulSet"+"."+namespace+"."+name)
} else {
result := DeleteObject(statefulSetConst, clusterName, namespace, name)
if result.Error() != nil {
Response(c, http.StatusInternalServerError, "delete statefulSet failed", result.Error())
return
}
}
Response(c, http.StatusOK, "success", nil)
}
func IsExistDeployment(c *gin.Context) {
clusterName := c.Query("clusterName")
namespace := c.Query("namespace")
name := c.Query("name")
searchObject := SearchObject(deploymentConst, clusterName, namespace, name)
if searchObject.Error() != nil {
Response(c, http.StatusOK, "success", false)
return
}
raw, _ := searchObject.Raw()
var deploymentRes appv1.Deployment
json.Unmarshal(raw, &deploymentRes)
if len(deploymentRes.Name) == 0 {
Response(c, http.StatusOK, "success", false)
return
}
Response(c, http.StatusOK, "success", true)
}
// @Summary 获取部署监控
// @Description 获取部署监控
// @Tags deployment
// @accept json
// @Produce json
// @Param clusterName query string true "集群名称"
// @Param namespace query string true "namespace"
// @Param deployment query string true "部署名称"
// @Param queryType query string true "类型"
// @Success 200
// @Failure 500
// @Router /api/v1/deployment/getMetrics [get]
func GetDeploymentMetrics(c *gin.Context) {
clusterName := c.Query("clusterName")
namespace := c.Query("namespace")
label := c.Query("label")
// 将label拼接成label集合
var labelMap = make(map[string]string)
labelArray := strings.Split(label, ",")
for _, label := range labelArray {
labelKV := strings.Split(label, "=")
labelMap[labelKV[0]] = labelKV[1]
}
podList := GetPodForDeployment(clusterName, namespace, labelMap)
metricUrls := make([][]MetricUrl, 4)
for _, item := range podList {
imap := map[string]string{
ClusterName: clusterName,
PodName: item.ObjectMeta.Name,
}
metricUrls[0] = append(metricUrls[0], MetricUrl{PodName, item.ObjectMeta.Name, GetMetricUrl(pod_net_bytes_transmitted, imap, PodName, metric_range_8h, steps_8h)})
metricUrls[1] = append(metricUrls[1], MetricUrl{PodName, item.ObjectMeta.Name, GetMetricUrl(pod_memery_usage_wo_cache, imap, PodName, metric_range_8h, steps_8h)})
metricUrls[2] = append(metricUrls[2], MetricUrl{PodName, item.ObjectMeta.Name, GetMetricUrl(pod_net_bytes_received, imap, PodName, metric_range_8h, steps_8h)})
metricUrls[3] = append(metricUrls[3], MetricUrl{PodName, item.ObjectMeta.Name, GetMetricUrl(pod_cpu_usage, imap, PodName, metric_range_8h, steps_8h)})
}
metricMap := map[string][]MetricUrl{
"pod_net_bytes_transmitted": metricUrls[0],
"pod_memory_usage_wo_cache": metricUrls[1],
"pod_net_bytes_received": metricUrls[2],
"pod_cpu_usage": metricUrls[3],
}
ch := make(chan MetricResult, len(metricMap))
var wg sync.WaitGroup
for k, v := range metricMap {
wg.Add(1)
go HttpGetMetrics(k, v, &wg, ch)
}
wg.Wait()
close(ch)
mr := []MetricResult{}
for v := range ch {
mr = append(mr, v)
}
Response(c, http.StatusOK, "success", mr)
}
func ListReplicaSets(c *gin.Context) {
clusterName := c.Query("clusterName")
namespace := c.Query("namespace")
label := c.Query("label")
// 将label拼接到map
var labelMap = make(map[string]string)
labelArray := strings.Split(label, ",")
for _, label := range labelArray {
labelKV := strings.Split(label, "=")
labelMap[labelKV[0]] = labelKV[1]
}
// 查询replicaSet
var replicaSetObject ReplicaSetObject
searchResult := SearchObject(replicaSetConst, clusterName, namespace, "")
raw, err := searchResult.Raw()
json.Unmarshal(raw, &replicaSetObject)
if err != nil {
Response(c, http.StatusInternalServerError, "query controllerRevisions failed", err)
return
}
var result []appv1.ReplicaSet
// 根据标签匹配
for _, replicaSet := range replicaSetObject.Items {
for k, v := range labelMap {
if replicaSet.Labels[k] != v {
goto loop
}
}
result = append(result, replicaSet)
loop:
}
Response(c, http.StatusOK, "success", result)
}
func ControllerRevisions(c *gin.Context) {
clusterName := c.Query("clusterName")
namespace := c.Query("namespace")
name := c.Query("name")
queryType := c.Query("queryType")
var controllerRevisions []appv1.ControllerRevision
var controllerRevisionObject ControllerRevisionObject
result := SearchObject(controllerVersionConst, clusterName, namespace, "")
raw, err := result.Raw()
if err != nil {
Response(c, http.StatusInternalServerError, "query controllerRevisions failed", err)
return
}
json.Unmarshal(raw, &controllerRevisionObject)
for i := range controllerRevisionObject.Items {
if controllerRevisionObject.Items[i].OwnerReferences[0].Kind == queryType && controllerRevisionObject.Items[i].OwnerReferences[0].Name == name {
controllerRevisions = append(controllerRevisions, controllerRevisionObject.Items[i])
}
}
Response(c, http.StatusOK, "success", controllerRevisions)
}

View File

@ -97,7 +97,7 @@ func CreateDomain(c *gin.Context) {
// @Router /api/v1/domain/list [get]
func ListDomain(c *gin.Context) {
domainName, _ := c.GetQuery("domain_name")
domainName := c.Query("domain_name")
//获取域列表
rows, _ := DB.Query("select domain_id,domain_name,longitude,latitude from domain where domain_name like ?", "%"+domainName+"%")
@ -185,8 +185,8 @@ func ListDomain(c *gin.Context) {
func DescribeDomain(c *gin.Context) {
var domain Domain
domainId, _ := c.GetQuery("domain_id")
namespace, _ := c.GetQuery("namespace")
domainId := c.Query("domain_id")
namespace := c.Query("namespace")
rows, _ := DB.Query("select d.domain_name,dc.cluster_name,d.longitude,d.latitude from domain_cluster dc,domain d where dc.domain_id = d.domain_id and dc.domain_id = ?", domainId)
var domainName string
var longitude float64
@ -247,8 +247,8 @@ func DescribeDomain(c *gin.Context) {
// @Router /api/v1/domain/listByDeployment [get]
func ListByDeployment(c *gin.Context) {
domainList := make([]Domain, 0)
namespaceName, _ := c.GetQuery("namespace")
deploymentName, _ := c.GetQuery("deployment_name")
namespaceName := c.Query("namespace")
deploymentName := c.Query("deployment_name")
domainList = getDomainsByDeployment(namespaceName, deploymentName)

View File

@ -3,7 +3,6 @@ package app
import (
"github.com/gin-gonic/gin"
"net/http"
"strconv"
"time"
)
@ -79,7 +78,7 @@ func DeleteLabel(c *gin.Context) {
// @Router /api/v1/label/list [post]
func ListLabel(c *gin.Context) {
labelName, _ := c.GetQuery("label_name")
labelName := c.Query("label_name")
LabelList := make([]Label, 0)
rows, err := DB.Query(`SELECT l.label_id,l.label_type_id ,lt.label_type ,l.label_name, l.create_time,l.update_time FROM label l,label_type lt WHERE l.label_type_id = lt.label_type_id and l.label_name like ?`, "%"+labelName+"%")
@ -108,11 +107,9 @@ func ListLabel(c *gin.Context) {
total := len(LabelList)
page := &Page[Label]{}
page.List = LabelList
pageNum, _ := c.GetQuery("pageNum")
pageSize, _ := c.GetQuery("pageSize")
num, _ := strconv.ParseInt(pageNum, 10, 64)
size, _ := strconv.ParseInt(pageSize, 10, 64)
data := Paginator(page, int64(total), num, size)
pageNum := c.Query("pageNum")
pageSize := c.Query("pageSize")
data := Paginator(page, int64(total), pageNum, pageSize)
Response(c, http.StatusOK, "success", data)
//Response(c, http.StatusOK, "success", LabelList)

View File

@ -3,7 +3,6 @@ package app
import (
"github.com/gin-gonic/gin"
"net/http"
"strconv"
)
type LabelType struct {
@ -77,7 +76,7 @@ func DeleteLabelType(c *gin.Context) {
// @Router /api/v1/labelType/list [get]
func ListLabelType(c *gin.Context) {
labelType, _ := c.GetQuery("label_type")
labelType := c.Query("label_type")
LabelTypeList := make([]LabelType, 0)
rows, err := DB.Query(`SELECT label_type_id,label_type,multi_check FROM label_type WHERE label_type like ?`, "%"+labelType+"%")
@ -99,11 +98,9 @@ func ListLabelType(c *gin.Context) {
total := len(LabelTypeList)
page := &Page[LabelType]{}
page.List = LabelTypeList
pageNum, _ := c.GetQuery("pageNum")
pageSize, _ := c.GetQuery("pageSize")
num, _ := strconv.ParseInt(pageNum, 10, 64)
size, _ := strconv.ParseInt(pageSize, 10, 64)
data := Paginator(page, int64(total), num, size)
pageNum := c.Query("pageNum")
pageSize := c.Query("pageSize")
data := Paginator(page, int64(total), pageNum, pageSize)
Response(c, http.StatusOK, "success", data)
//Response(c, http.StatusOK, "success", LabelTypeList)

View File

@ -2,15 +2,28 @@ package app
import (
"context"
"encoding/json"
"github.com/gin-gonic/gin"
"github.com/karmada-io/karmada/pkg/util"
v1 "k8s.io/api/batch/v1"
coreV1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"net/http"
"sort"
"strconv"
"strings"
"sync"
"time"
)
const (
namespace_memory_usage_wo_cache = "namespace:container_memory_usage_bytes_wo_cache:sum{cluster_name='clusterName',namespace='nameSpace', prometheus_replica='prometheus-k8s-0'}"
namespace_cpu_usage = "sum by (namespace) (namespace:workload_cpu_usage:sum{cluster_name='clusterName',namespace='nameSpace', prometheus_replica='prometheus-k8s-0'})"
namespace_pod_count = "count(sum by (pod) (kube_pod_container_info{cluster_name='clusterName', namespace='nameSpace', prometheus_replica='prometheus-k8s-0'}))"
metric_range_12h = "12h"
steps_namespace = 1080
)
type Namespace struct {
NsName string `json:"ns_name"`
State string `json:"state"`
@ -23,6 +36,13 @@ type Namespace struct {
AvailablePodNum int32 `json:"available_pod_num"`
Alias string `json:"alias"`
Describe string `json:"describe"`
TemplateId string `json:"templateId"`
}
type NamespaceParam struct {
Namespace coreV1.Namespace `json:"namespace"`
TemplateId string `json:"templateId"`
ClusterName []string `json:"clusterName"`
}
type DomainResult struct {
@ -30,6 +50,82 @@ type DomainResult struct {
Location [2]float64 `json:"location"`
}
type NamespaceObject struct {
Kind string `json:"kind"`
ApiVersion string `json:"apiVersion"`
Metadata string `json:"metadata"`
ResourceVersion string `json:"resourceVersion"`
Items []coreV1.Namespace `json:"items"`
}
type JobObject struct {
Kind string `json:"kind"`
ApiVersion string `json:"apiVersion"`
Metadata string `json:"metadata"`
ResourceVersion string `json:"resourceVersion"`
Items []v1.Job `json:"items"`
}
type NsResources struct {
PodCount int `json:"podCount"`
DeploymentCount int `json:"deploymentCount"`
StatefulSetCount int `json:"statefulSetCount"`
DaemonSetCount int `json:"daemonSetCount"`
JobCount int `json:"jobCount"`
PvcCount int `json:"pvcCount"`
ServiceCount int `json:"serviceCount"`
}
func GetNamespaceResources(c *gin.Context) {
clusterName := c.Query("clusterName")
namespace := c.Query("namespace")
// 查询pod
podResult := SearchObject(podListConst, clusterName, namespace, "")
var podObject PodObject
podRaw, _ := podResult.Raw()
json.Unmarshal(podRaw, &podObject)
// 查询deployment
deploymentResult := SearchObject(deploymentListConst, clusterName, namespace, "")
var deploymentObject DeploymentObject
deploymentRaw, _ := deploymentResult.Raw()
json.Unmarshal(deploymentRaw, &deploymentObject)
// 查询statefulSet
statefulSetResult := SearchObject(statefulSetListConst, clusterName, namespace, "")
var statefulSetObject StatefulSetObject
statefulSetRaw, _ := statefulSetResult.Raw()
json.Unmarshal(statefulSetRaw, &statefulSetObject)
// 查询daemonSet
daemonSetResult := SearchObject(daemonSetListConst, clusterName, namespace, "")
var daemonSetObject DaemonSetObject
daemonSetRaw, _ := daemonSetResult.Raw()
json.Unmarshal(daemonSetRaw, &daemonSetObject)
// 查询job
jobResult := SearchObject(jobListConst, clusterName, namespace, "")
var jobObject JobObject
jobRaw, _ := jobResult.Raw()
json.Unmarshal(jobRaw, &jobObject)
// 查询pvc
pvcResult := SearchObject(pvcListConst, clusterName, namespace, "")
var pvcObject PVCObject
pvcRaw, _ := pvcResult.Raw()
json.Unmarshal(pvcRaw, &pvcObject)
// 查询service
serviceResult := SearchObject(serviceConst, clusterName, namespace, "")
var serviceObject ServiceObject
serviceRaw, _ := serviceResult.Raw()
json.Unmarshal(serviceRaw, &serviceObject)
Response(c, http.StatusOK, "success", NsResources{
PodCount: len(podObject.Items),
DeploymentCount: len(deploymentObject.Items),
StatefulSetCount: len(statefulSetObject.Items),
DaemonSetCount: len(daemonSetObject.Items),
JobCount: len(jobObject.Items),
PvcCount: len(pvcObject.Items),
ServiceCount: len(serviceObject.Items),
})
}
// CreateNamespace 创建命名空间(项目)
// @Summary 创建命名空间(项目)
// @Description 创建命名空间(项目)
// @Tags namespace
@ -40,38 +136,125 @@ type DomainResult struct {
// @Failure 400
// @Router /api/v1/namespace/create [post]
func CreateNamespace(c *gin.Context) {
var j Namespace
labels := make(map[string]string)
labels["jcce"] = "true"
if err := c.BindJSON(&j); err != nil {
var nsParam NamespaceParam
if nsParam.Namespace.Labels == nil {
nsParam.Namespace.Labels = map[string]string{}
}
nsParam.Namespace.Labels["jcce"] = "true"
if err := c.BindJSON(&nsParam); err != nil {
Response(c, http.StatusBadRequest, "invalid request params.", "")
return
}
sqlStr1 := "INSERT INTO joint_domain.namespace (namespace_name, alias, `describe`) VALUES(?,?,?)"
_, err := DB.Exec(sqlStr1, j.NsName, j.Alias, j.Describe)
_, err := DB.Exec(sqlStr1, nsParam.Namespace.Name, nsParam.Namespace.Annotations["kubesphere.io/alias-name"], nsParam.Namespace.Annotations["kubesphere.io/description"])
if err != nil {
Response(c, http.StatusBadRequest, "query failed!", err)
return
}
ns := coreV1.Namespace{
TypeMeta: metav1.TypeMeta{},
ObjectMeta: metav1.ObjectMeta{
Name: j.NsName,
Labels: labels,
},
Spec: coreV1.NamespaceSpec{},
Status: coreV1.NamespaceStatus{},
}
nsResult, err := ClientSet.CoreV1().Namespaces().Create(context.TODO(), &ns, metav1.CreateOptions{})
nsResult, err := ClientSet.CoreV1().Namespaces().Create(context.TODO(), &nsParam.Namespace, metav1.CreateOptions{})
if err != nil {
println(err)
}
// 创建调度策略实例
CreatePropagationPolicies(PropagationPolicy{
ClusterName: nsParam.ClusterName,
TemplateId: nsParam.TemplateId,
ResourceName: nsParam.Namespace.Name,
Name: "Namespace" + "." + nsParam.Namespace.Name,
Kind: "Namespace",
})
Response(c, http.StatusOK, "success", nsResult)
}
// ListNamespaceFromCluster 根据指定集群查询命名空间
func ListNamespaceFromCluster(c *gin.Context) {
clusterName := c.Query("clusterName")
name := c.Query("name")
pageNum := c.Query("pageNum")
pageSize := c.Query("pageSize")
queryType := c.Query("queryType")
searchObject := SearchObject(namespaceConst, clusterName, "", "")
raw, _ := searchObject.Raw()
var namespaceObject NamespaceObject
json.Unmarshal(raw, &namespaceObject)
var result []coreV1.Namespace
// 查询用户项目or系统项目
if strings.EqualFold(queryType, "system") {
for i := range namespaceObject.Items {
value, ok := namespaceObject.Items[i].Labels["kubesphere.io/workspace"]
if ok && strings.Contains(value, "system-workspace") {
result = append(result, namespaceObject.Items[i])
}
}
}
if strings.EqualFold(queryType, "user") {
for i := range namespaceObject.Items {
value, ok := namespaceObject.Items[i].Labels["kubesphere.io/workspace"]
if !(ok && strings.Contains(value, "system-workspace")) {
result = append(result, namespaceObject.Items[i])
}
}
}
var nameQueryResult []coreV1.Namespace
// 模糊查询
if len(name) != 0 {
for i := range result {
if strings.Contains(result[i].Name, name) {
nameQueryResult = append(nameQueryResult, result[i])
}
}
result = nameQueryResult
}
if result == nil {
Response(c, http.StatusOK, "success", nil)
return
}
// 分页
page := &Page[coreV1.Namespace]{}
page.List = result
// 排序
sort.SliceStable(result, func(i, j int) bool {
return result[i].CreationTimestamp.Time.After(result[j].CreationTimestamp.Time)
})
data := Paginator(page, int64(len(result)), pageNum, pageSize)
Response(c, http.StatusOK, "success", data)
}
// ListName 获取所有项目名
func ListName(c *gin.Context) {
clusterName := c.Query("clusterName")
result := SearchObject(namespaceConst, clusterName, "", "")
raw, _ := result.Raw()
var namespaceObject NamespaceObject
json.Unmarshal(raw, &namespaceObject)
var namespaceList []string
for _, namespace := range namespaceObject.Items {
namespaceList = append(namespaceList, namespace.Name)
}
Response(c, http.StatusOK, "success", namespaceList)
}
func IsExistNamespace(c *gin.Context) {
clusterName := c.Query("clusterName")
name := c.Query("name")
result := SearchObject(detailNamespaceConst, clusterName, "", name)
if result.Error() != nil {
Response(c, http.StatusOK, "success", false)
return
}
raw, _ := result.Raw()
var namespace coreV1.Namespace
json.Unmarshal(raw, &namespace)
if len(namespace.Name) == 0 {
Response(c, http.StatusOK, "success", false)
return
}
Response(c, http.StatusOK, "success", true)
}
// ListNamespace 查询Namespace列表
// @Summary 查询Namespace列表
// @Description 查询Namespace列表
// @Tags namespace
@ -137,13 +320,21 @@ func ListNamespace(ctx *gin.Context) {
page.List = nsList
pageNum, _ := ctx.GetQuery("pageNum")
pageSize, _ := ctx.GetQuery("pageSize")
num, _ := strconv.ParseInt(pageNum, 10, 64)
size, _ := strconv.ParseInt(pageSize, 10, 64)
data := Paginator(page, int64(total), num, size)
data := Paginator(page, int64(total), pageNum, pageSize)
Response(ctx, http.StatusOK, "success", data)
}
func DetailNamespace(c *gin.Context) {
clusterName := c.Query("clusterName")
name := c.Query("name")
result := SearchObject(detailNamespaceConst, clusterName, "", name)
raw, _ := result.Raw()
var namespace coreV1.Namespace
json.Unmarshal(raw, &namespace)
Response(c, http.StatusOK, "success", namespace)
}
// @Summary 查询Namespace详情
// @Description 查询Namespace详情
// @Tags namespace
@ -155,7 +346,7 @@ func ListNamespace(ctx *gin.Context) {
// @Router /api/v1/namespace/describe [get]
func DescribeNamespace(c *gin.Context) {
namespace, _ := c.GetQuery("namespace")
namespace := c.Query("namespace")
optsGet := metav1.GetOptions{
TypeMeta: metav1.TypeMeta{},
@ -273,48 +464,146 @@ func DescribeNamespace(c *gin.Context) {
// @Failure 400
// @Router /api/v1/namespace/update [post]
func UpdateNamespace(c *gin.Context) {
var j Namespace
if err := c.BindJSON(&j); err != nil {
clusterName := c.Query("clusterName")
var namespace coreV1.Namespace
if err := c.BindJSON(&namespace); err != nil {
Response(c, http.StatusBadRequest, "invalid request params.", "")
return
}
ns := coreV1.Namespace{
TypeMeta: metav1.TypeMeta{},
ObjectMeta: metav1.ObjectMeta{
Name: j.NsName,
},
Spec: coreV1.NamespaceSpec{},
Status: coreV1.NamespaceStatus{},
if len(namespace.Labels["jcce"]) != 0 {
_, err := ClientSet.CoreV1().Namespaces().Update(context.TODO(), &namespace, metav1.UpdateOptions{})
if err != nil {
Response(c, http.StatusInternalServerError, "update namespace failed", err)
return
}
} else {
result := UpdateObject(detailNamespaceConst, clusterName, "", namespace.Name, namespace)
if result.Error() != nil {
Response(c, http.StatusInternalServerError, "update namespace failed", result.Error())
return
}
}
nsResult, err := ClientSet.CoreV1().Namespaces().Update(context.TODO(), &ns, metav1.UpdateOptions{})
if err != nil {
println(err)
}
Response(c, http.StatusOK, "success", nsResult)
Response(c, http.StatusOK, "success", "")
}
// DeleteNamespace 删除命名空间(项目)
func DeleteNamespace(c *gin.Context) {
var j Namespace
if err := c.BindJSON(&j); err != nil {
Response(c, http.StatusBadRequest, "invalid request params.", "")
return
}
err := ClientSet.CoreV1().Namespaces().Delete(context.TODO(), j.NsName, metav1.DeleteOptions{})
if err != nil {
Response(c, http.StatusInternalServerError, "delete namespace "+j.NsName+"failed", "")
println(err)
}
// 删除数据库记录policy实例
_, err = DB.Exec(`delete from joint_domain.namespace where namespace_name = ? `, j.NsName)
if err != nil {
Response(c, http.StatusInternalServerError, "delete db failed", err)
return
clusterName := c.Param("clusterName")
name := c.Param("name")
label := c.Param("label")
if strings.EqualFold(label, "jcce") {
err := ClientSet.CoreV1().Namespaces().Delete(context.TODO(), name, metav1.DeleteOptions{})
if err != nil {
Response(c, http.StatusInternalServerError, "delete namespace "+name+"failed", "")
return
}
// 删除数据库记录policy实例
_, err = DB.Exec(`delete from joint_domain.namespace where namespace_name = ? `, name)
if err != nil {
Response(c, http.StatusInternalServerError, "delete db failed", err)
return
}
// 删除调度策略
DeletePropagationPolicies(name, "Namespace"+"."+name)
} else {
result := DeleteObject(detailNamespaceConst, clusterName, "", name)
if result.Error() != nil {
Response(c, http.StatusInternalServerError, "delete persistentVolumeClaim failed", result.Error())
return
}
}
Response(c, http.StatusOK, "success", "")
}
// @Summary namespace监控
// @Description namespace监控
// @Tags namespace
// @accept json
// @Produce json
// @Param clusterName query string true "集群名"
// @Param namespace query string true "命名空间名称"
// @Success 200
// @Failure 400
// @Router /api/v1/namespace/getMetrics [get]
func GetNamespaceMetrics(c *gin.Context) {
clusterName, _ := c.GetQuery("clusterName")
namespace, _ := c.GetQuery("namespace")
replaceMap := make(map[string]string)
replaceMap[ClusterName] = clusterName
replaceMap["nameSpace"] = namespace
metricMap := map[string][]MetricUrl{
"namespace_memory_usage_wo_cache": {{"nameSpace", namespace, GetMetricUrl(namespace_memory_usage_wo_cache, replaceMap, "nameSpace", metric_range_12h, steps_namespace)}},
"namespace_cpu_usage": {{"nameSpace", namespace, GetMetricUrl(namespace_cpu_usage, replaceMap, "nameSpace", metric_range_12h, steps_namespace)}},
}
ch := make(chan MetricResult, len(metricMap))
var wg sync.WaitGroup
for k, v := range metricMap {
wg.Add(1)
go HttpGetMetrics(k, v, &wg, ch)
}
wg.Wait()
close(ch)
mr := []MetricResult{}
for v := range ch {
mr = append(mr, v)
}
Response(c, http.StatusOK, "success", mr)
}
// @Summary 批量获取namespace监控
// @Description 批量获取namespace监控
// @Tags namespace
// @accept json
// @Produce json
// @Param clusterName query string true "集群名"
// @Param namespaces query string true "逗号分隔多个命名空间名称"
// @Success 200
// @Failure 400
// @Router /api/v1/namespace/getBatchMetrics [get]
func GetBatchNamespaceMetrics(c *gin.Context) {
clusterName := c.Query("clusterName")
namespaces := c.Query("namespaces")
namespace := strings.Split(namespaces, ",")
metricUrls := make([][]MetricUrl, 3)
for _, name := range namespace {
imap := map[string]string{
ClusterName: clusterName,
"nameSpace": name,
}
metricUrls[0] = append(metricUrls[0], MetricUrl{"nameSpace", name, GetMetricUrl(namespace_memory_usage_wo_cache, imap, "nameSpace", metric_range_1s, steps_1s)})
metricUrls[1] = append(metricUrls[1], MetricUrl{"nameSpace", name, GetMetricUrl(namespace_cpu_usage, imap, "nameSpace", metric_range_1s, steps_1s)})
metricUrls[2] = append(metricUrls[2], MetricUrl{"nameSpace", name, GetMetricUrl(namespace_pod_count, imap, "nameSpace", metric_range_1s, steps_1s)})
}
metricMap := map[string][]MetricUrl{
"namespace_memory_usage_wo_cache": metricUrls[0],
"namespace_cpu_usage": metricUrls[1],
"namespace_pod_count": metricUrls[2],
}
ch := make(chan MetricResult, len(metricMap))
var wg sync.WaitGroup
for k, v := range metricMap {
wg.Add(1)
go HttpGetMetrics(k, v, &wg, ch)
}
wg.Wait()
close(ch)
mr := []MetricResult{}
for v := range ch {
mr = append(mr, v)
}
Response(c, http.StatusOK, "success", mr)
}

View File

@ -1,12 +1,20 @@
package app
import (
"context"
"encoding/json"
"fmt"
"github.com/gin-gonic/gin"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/metrics/pkg/apis/metrics"
"math"
"net/http"
"sort"
"strconv"
"strings"
"sync"
)
type NodeRes struct {
@ -30,6 +38,97 @@ type NodeExtendRes struct {
PodStatus v1.PodPhase `json:"podStatus"`
}
type NodeCountResult struct {
MasterCount int `json:"masterCount"`
AllCount int `json:"allCount"`
WorkCount int `json:"workCount"`
}
const (
node_cpu_utilisation_1h = "node:node_cpu_utilisation:avg1m{cluster_name='clusterName',node='nodeName', prometheus_replica='prometheus-k8s-0'}"
node_pod_utilisation_1h = "node:pod_utilization:ratio{cluster_name='clusterName',node='nodeName', prometheus_replica='prometheus-k8s-0'}"
node_memory_utilisation_1h = "node:node_memory_utilisation:{cluster_name='clusterName',node='nodeName', prometheus_replica='prometheus-k8s-0'}"
node_disk_size_utilisation_1h = "node:disk_space_utilization:ratio{cluster_name='clusterName',node='nodeName', prometheus_replica='prometheus-k8s-0'}"
node_load15_8h = "node:load15:ratio{cluster_name='clusterName',node='nodeName', prometheus_replica='prometheus-k8s-0'}"
node_disk_write_iops_8h = "node:data_volume_iops_writes:sum{cluster_name='clusterName',node='nodeName', prometheus_replica='prometheus-k8s-0'}"
node_cpu_utilisation_8h = "node:node_cpu_utilisation:avg1m{cluster_name='clusterName',node='nodeName', prometheus_replica='prometheus-k8s-0'}"
node_net_bytes_transmitted_8h = "node:node_net_bytes_transmitted:sum_irate{cluster_name='clusterName',node='nodeName', prometheus_replica='prometheus-k8s-0'}"
node_disk_inode_total_8h = "node:node_inodes_total:{cluster_name='clusterName',node='nodeName', prometheus_replica='prometheus-k8s-0'}"
node_disk_read_throughput_8h = "node:data_volume_throughput_bytes_read:sum{cluster_name='clusterName',node='nodeName', prometheus_replica='prometheus-k8s-0'}"
node_net_bytes_received_8h = "node:node_net_bytes_received:sum_irate{cluster_name='clusterName',node='nodeName', prometheus_replica='prometheus-k8s-0'}"
node_memory_utilisation_8h = "node:node_memory_utilisation:{cluster_name='clusterName',node='nodeName', prometheus_replica='prometheus-k8s-0'}"
node_disk_write_throughput_8h = "node:data_volume_throughput_bytes_written:sum{cluster_name='clusterName',node='nodeName', prometheus_replica='prometheus-k8s-0'}"
node_load5_8h = "node:load5:ratio{cluster_name='clusterName',node='nodeName', prometheus_replica='prometheus-k8s-0'}"
node_disk_inode_usage_8h = "node:node_inodes_total:{cluster_name='clusterName',node='nodeName', prometheus_replica='prometheus-k8s-0'} * node:disk_inode_utilization:ratio{cluster_name='clusterName',node='nodeName', prometheus_replica='prometheus-k8s-0'}"
node_disk_read_iops_8h = "node:data_volume_iops_reads:sum{cluster_name='clusterName',node='nodeName', prometheus_replica='prometheus-k8s-0'}"
node_disk_size_utilisation_8h = "node:disk_space_utilization:ratio{cluster_name='clusterName',node='nodeName', prometheus_replica='prometheus-k8s-0'}"
node_disk_inode_utilisation_8h = "node:disk_inode_utilization:ratio{cluster_name='clusterName',node='nodeName', prometheus_replica='prometheus-k8s-0'}"
node_load1_8h = "node:load1:ratio{cluster_name='clusterName',node='nodeName', prometheus_replica='prometheus-k8s-0'}"
node_cpu_limits = "sum by (node) (kube_pod_container_resource_limits_cpu_cores{cluster_name='clusterName',node='nodeName', prometheus_replica='prometheus-k8s-0'})"
node_cpu_requests = "sum by (node) (kube_pod_container_resource_requests_cpu_cores{cluster_name='clusterName',node='nodeName', prometheus_replica='prometheus-k8s-0'})"
node_memory_limits = "sum by (node) (kube_pod_container_resource_limits_memory_bytes{cluster_name='clusterName',node='nodeName', prometheus_replica='prometheus-k8s-0'})"
node_memory_requests = "sum by (node) (kube_pod_container_resource_requests_memory_bytes{cluster_name='clusterName',node='nodeName', prometheus_replica='prometheus-k8s-0'})"
NodeName = "nodeName"
metric_range_1h = "1h"
steps_1h = 180
metric_range_8h = "8.333h"
steps_8h = 600
max = 10
)
// NodeCount 查询节点数量
func NodeCount(c *gin.Context) {
clusterName := c.Query("clusterName")
result := SearchObject(nodeConst, clusterName, "", "")
raw, _ := result.Raw()
var nodeRes NodeRes
json.Unmarshal(raw, &nodeRes)
var masterCount int
var edgerCount int
for i := range nodeRes.Items {
if _, ok := nodeRes.Items[i].Labels["node-role.kubernetes.io/master"]; ok {
masterCount++
}
if _, ok := nodeRes.Items[i].Labels["node-role.kubernetes.io/edge"]; ok {
edgerCount++
}
}
Response(c, http.StatusOK, "success", NodeCountResult{
AllCount: len(nodeRes.Items) - edgerCount,
MasterCount: masterCount,
WorkCount: len(nodeRes.Items) - masterCount - edgerCount,
})
}
// UpdateNode 更新节点信息
func UpdateNode(c *gin.Context) {
clusterName := c.Query("clusterName")
var node v1.Node
if err := c.BindJSON(&node); err != nil {
Response(c, http.StatusBadRequest, "invalid request params.", "")
return
}
if len(node.Labels["jcce"]) != 0 {
_, err := ClientSet.CoreV1().Nodes().Update(context.TODO(), &node, metav1.UpdateOptions{})
if err != nil {
Response(c, http.StatusBadRequest, "update node error.", "")
return
}
} else {
result := UpdateObject(detailNodeConst, clusterName, "", node.Name, node)
if result.Error() != nil {
Response(c, http.StatusInternalServerError, "update persistentVolumeClaim failed", result.Error())
return
}
}
Response(c, http.StatusOK, "success", "")
}
// ListNode 查询节点列表
// @Summary 查询节点列表
// @Description 查询节点列表
// @Tags node
@ -40,12 +139,132 @@ type NodeExtendRes struct {
// @Failure 500
// @Router /api/v1/node/list/{clusterName} [get]
func ListNode(c *gin.Context) {
clusterName := c.Param("clusterName")
result := SearchObject(nodeConst, clusterName, "", "")
raw, _ := result.Raw()
clusterName := c.Query("clusterName")
pageNum := c.Query("pageNum")
pageSize := c.Query("pageSize")
queryType := c.Query("queryType")
nodeResult := SearchObject(nodeConst, clusterName, "", "")
raw, _ := nodeResult.Raw()
var nodeRes NodeRes
json.Unmarshal(raw, &nodeRes)
Response(c, http.StatusOK, "success", nodeRes.Items)
var result []v1.Node
if strings.EqualFold(queryType, "edge") {
for i := range nodeRes.Items {
if _, ok := nodeRes.Items[i].Labels["node-role.kubernetes.io/edge"]; ok {
result = append(result, nodeRes.Items[i])
}
}
} else {
for i := range nodeRes.Items {
if _, ok := nodeRes.Items[i].Labels["node-role.kubernetes.io/edge"]; !ok {
result = append(result, nodeRes.Items[i])
}
}
}
// 分页
page := &Page[v1.Node]{}
page.List = result
// 排序
sort.SliceStable(page.List, func(i, j int) bool {
return page.List[i].CreationTimestamp.Time.After(page.List[j].CreationTimestamp.Time)
})
data := Paginator(page, int64(len(page.List)), pageNum, pageSize)
Response(c, http.StatusOK, "success", data)
}
// DetailNode 查询节点详情
func DetailNode(c *gin.Context) {
clusterName := c.Query("clusterName")
name := c.Query("name")
// 查询节点信息
nodeRes := SearchObject(detailNodeConst, clusterName, "", name)
nodeRaw, _ := nodeRes.Raw()
var node v1.Node
json.Unmarshal(nodeRaw, &node)
cpu_capacity, _ := node.Status.Capacity.Cpu().AsInt64()
cpu_capacity_float := float64(cpu_capacity)
ephemeral_storage, _ := node.Status.Capacity.StorageEphemeral().AsInt64()
ephemeral_storage_float := float64(ephemeral_storage)
replaceMap := make(map[string]string)
replaceMap[ClusterName] = clusterName
replaceMap[NodeName] = name
metricMap := map[string][]MetricUrl{
"node_cpu_limits": {{NodeName, name, GetMetricUrl(node_cpu_limits, replaceMap, NodeName, metric_range_1s, steps_1s)}},
"node_cpu_requests": {{NodeName, name, GetMetricUrl(node_cpu_requests, replaceMap, NodeName, metric_range_1s, steps_1s)}},
"node_memory_limits": {{NodeName, name, GetMetricUrl(node_memory_limits, replaceMap, NodeName, metric_range_1s, steps_1s)}},
"node_memory_requests": {{NodeName, name, GetMetricUrl(node_memory_requests, replaceMap, NodeName, metric_range_1s, steps_1s)}},
}
ch := make(chan MetricResult, len(metricMap))
var wg sync.WaitGroup
for k, v := range metricMap {
wg.Add(1)
go HttpGetMetrics(k, v, &wg, ch)
}
wg.Wait()
close(ch)
aMap := map[string]string{}
for v := range ch {
if len(v.MetricData.Result) == 0 {
continue
}
format := v.MetricData.Result[0]["values"]
valStr := fmt.Sprintf("%v", format)
vals := strings.Split(valStr, " ")
val := strings.Trim(vals[1], "]]")
switch v.MetricName {
case "node_cpu_limits":
aMap["node_cpu_limits"] = val
ival, _ := strconv.ParseFloat(val, 64)
fraction := ival / cpu_capacity_float
aMap["node_cpu_limits_fraction"] = fmt.Sprintf("%.0f%%", math.Round(fraction*100))
case "node_cpu_requests":
aMap["node_cpu_requests"] = val
ival, _ := strconv.ParseFloat(val, 64)
fraction := ival / cpu_capacity_float
aMap["node_cpu_requests_fraction"] = fmt.Sprintf("%.0f%%", math.Round(fraction*100))
case "node_memory_limits":
aMap["node_memory_limits"] = val
ival, _ := strconv.ParseFloat(val, 64)
fraction := ival / ephemeral_storage_float
aMap["node_memory_limits_fraction"] = fmt.Sprintf("%.0f%%", math.Round(fraction*100))
case "node_memory_requests":
aMap["node_memory_requests"] = val
ival, _ := strconv.ParseFloat(val, 64)
fraction := ival / ephemeral_storage_float
aMap["node_memory_requests_fraction"] = fmt.Sprintf("%.0f%%", math.Round(fraction*100))
}
}
nodeMetricLength := 8
if len(aMap) != nodeMetricLength {
Response(c, http.StatusOK, "query node list success", node)
return
}
formatted_str := fmt.Sprintf(`[{"op":"replace","path":"/metadata/annotations/node.kubesphere.io~1cpu-limits", "value": "%s"},
{"op":"replace","path":"/metadata/annotations/node.kubesphere.io~1cpu-limits-fraction", "value": "%s"},
{"op":"replace","path":"/metadata/annotations/node.kubesphere.io~1cpu_requests", "value": "%s"},
{"op":"replace","path":"/metadata/annotations/node.kubesphere.io~1cpu_requests-fraction", "value": "%s"},
{"op":"replace","path":"/metadata/annotations/node.kubesphere.io~1memory_limits", "value": "%s"},
{"op":"replace","path":"/metadata/annotations/node.kubesphere.io~1memory_limits-fraction", "value": "%s"},
{"op":"replace","path":"/metadata/annotations/node.kubesphere.io~1memory_requests", "value": "%s"},
{"op":"replace","path":"/metadata/annotations/node.kubesphere.io~1memory_requests-fraction", "value": "%s"}]`,
aMap["node_cpu_limits"], aMap["node_cpu_limits_fraction"], aMap["node_cpu_requests"],
aMap["node_cpu_requests_fraction"], aMap["node_memory_limits"], aMap["node_memory_limits_fraction"],
aMap["node_memory_requests"], aMap["node_memory_requests_fraction"])
aliasJson := []byte(formatted_str)
PatchObject(detailNodeConst, clusterName, "", node.Name, aliasJson, types.JSONPatchType)
Response(c, http.StatusOK, "query node list success", node)
}
// @Summary 根据集群名称 命名空间 pod名称查询节点信息
@ -60,9 +279,9 @@ func ListNode(c *gin.Context) {
// @Failure 500
// @Router /api/v1/node/detail/{clusterName}/{namespace}/{podName} [get]
func queryNodeInfo(c *gin.Context) {
clusterName := c.Param("clusterName")
namespace := c.Param("namespace")
podName := c.Param("podName")
clusterName := c.Query("clusterName")
namespace := c.Query("namespace")
podName := c.Query("podName")
var result NodeExtendRes
// 查询节点信息
nodeRes := SearchObject(nodeConst, clusterName, "", "")
@ -95,7 +314,7 @@ func queryNodeInfo(c *gin.Context) {
// @Failure 500
// @Router /api/v1/node/edge/{clusterName} [get]
func ListEdgeNode(c *gin.Context) {
clusterName := c.Param("clusterName")
clusterName := c.Query("clusterName")
result := SearchObject(nodeConst, clusterName, "", "")
raw, _ := result.Raw()
var nodeRes NodeRes
@ -120,10 +339,111 @@ func ListEdgeNode(c *gin.Context) {
// @Failure 500
// @Router /api/v1/node/metrics/{clusterName} [get]
func ListNodeMetrics(c *gin.Context) {
clusterName := c.Param("clusterName")
clusterName := c.Query("clusterName")
result := SearchObject(nodeMetrics, clusterName, "", "")
raw, _ := result.Raw()
var metricsRes MetricsRes
json.Unmarshal(raw, &metricsRes)
Response(c, http.StatusOK, "success", metricsRes.Items)
}
// @Summary 获取集群节点1h监控
// @Description 获取集群节点1h监控
// @Tags node
// @accept json
// @Produce json
// @Param clusterName query string true "集群名称"
// @Param nodeName query string true "节点名称"
// @Success 200
// @Failure 400
// @Router /api/v1/node/getNodeMetrics1h [get]
func GetNodeMetrics1h(c *gin.Context) {
clusterName := c.Query("clusterName")
nodeName := c.Query("nodeName")
replaceMap := make(map[string]string)
replaceMap[ClusterName] = clusterName
replaceMap[NodeName] = nodeName
metricMap := map[string][]MetricUrl{
"node_cpu_utilisation": {{NodeName, nodeName, GetMetricUrl(node_cpu_utilisation_1h, replaceMap, NodeName, metric_range_1h, steps_1h)}},
"node_pod_utilisation": {{NodeName, nodeName, GetMetricUrl(node_pod_utilisation_1h, replaceMap, NodeName, metric_range_1h, steps_1h)}},
"node_memory_utilisation": {{NodeName, nodeName, GetMetricUrl(node_memory_utilisation_1h, replaceMap, NodeName, metric_range_1h, steps_1h)}},
"node_disk_size_utilisation": {{NodeName, nodeName, GetMetricUrl(node_disk_size_utilisation_1h, replaceMap, NodeName, metric_range_1h, steps_1h)}},
}
ch := make(chan MetricResult, len(metricMap))
var wg sync.WaitGroup
for k, v := range metricMap {
wg.Add(1)
go HttpGetMetrics(k, v, &wg, ch)
}
wg.Wait()
close(ch)
mr := []MetricResult{}
for v := range ch {
mr = append(mr, v)
}
Response(c, http.StatusOK, "success", mr)
}
// @Summary 获取集群节点8h监控
// @Description 获取集群节点8h监控
// @Tags node
// @accept json
// @Produce json
// @Param clusterName query string true "集群名称"
// @Param nodeName query string true "节点名称"
// @Success 200
// @Failure 400
// @Router /api/v1/node/getNodeMetrics8h [get]
func GetNodeMetrics8h(c *gin.Context) {
clusterName := c.Query("clusterName")
nodeName := c.Query("nodeName")
replaceMap := make(map[string]string)
replaceMap[ClusterName] = clusterName
replaceMap[NodeName] = nodeName
metricMap := map[string][]MetricUrl{
"node_load15": {{NodeName, nodeName, GetMetricUrl(node_load15_8h, replaceMap, NodeName, metric_range_8h, steps_8h)}},
"node_disk_write_iops": {{NodeName, nodeName, GetMetricUrl(node_disk_write_iops_8h, replaceMap, NodeName, metric_range_8h, steps_8h)}},
"node_cpu_utilisation": {{NodeName, nodeName, GetMetricUrl(node_cpu_utilisation_8h, replaceMap, NodeName, metric_range_8h, steps_8h)}},
"node_net_bytes_transmitted": {{NodeName, nodeName, GetMetricUrl(node_net_bytes_transmitted_8h, replaceMap, NodeName, metric_range_8h, steps_8h)}},
"node_disk_inode_total": {{NodeName, nodeName, GetMetricUrl(node_disk_inode_total_8h, replaceMap, NodeName, metric_range_8h, steps_8h)}},
"node_disk_read_throughput": {{NodeName, nodeName, GetMetricUrl(node_disk_read_throughput_8h, replaceMap, NodeName, metric_range_8h, steps_8h)}},
"node_net_bytes_received": {{NodeName, nodeName, GetMetricUrl(node_net_bytes_received_8h, replaceMap, NodeName, metric_range_8h, steps_8h)}},
"node_memory_utilisation": {{NodeName, nodeName, GetMetricUrl(node_memory_utilisation_8h, replaceMap, NodeName, metric_range_8h, steps_8h)}},
"node_disk_write_throughput": {{NodeName, nodeName, GetMetricUrl(node_disk_write_throughput_8h, replaceMap, NodeName, metric_range_8h, steps_8h)}},
"node_load5": {{NodeName, nodeName, GetMetricUrl(node_load5_8h, replaceMap, NodeName, metric_range_8h, steps_8h)}},
"node_disk_inode_usage": {{NodeName, nodeName, GetMetricUrl(node_disk_inode_usage_8h, replaceMap, NodeName, metric_range_8h, steps_8h)}},
"node_disk_read_iops": {{NodeName, nodeName, GetMetricUrl(node_disk_read_iops_8h, replaceMap, NodeName, metric_range_8h, steps_8h)}},
"node_disk_size_utilisation": {{NodeName, nodeName, GetMetricUrl(node_disk_size_utilisation_8h, replaceMap, NodeName, metric_range_8h, steps_8h)}},
"node_disk_inode_utilisation": {{NodeName, nodeName, GetMetricUrl(node_disk_inode_utilisation_8h, replaceMap, NodeName, metric_range_8h, steps_8h)}},
"node_load1": {{NodeName, nodeName, GetMetricUrl(node_load1_8h, replaceMap, NodeName, metric_range_8h, steps_8h)}},
}
ch := make(chan MetricResult, len(metricMap))
limit := make(chan bool, max)
var wg sync.WaitGroup
for k, v := range metricMap {
limit <- true
wg.Add(1)
go HttpGetMetrics(k, v, &wg, ch)
<-limit
}
wg.Wait()
close(ch)
mr := []MetricResult{}
for v := range ch {
mr = append(mr, v)
}
Response(c, http.StatusOK, "success", mr)
}

View File

@ -3,9 +3,11 @@ package app
import (
"bytes"
"context"
"encoding/json"
"fmt"
"github.com/bitly/go-simplejson"
"github.com/opensearch-project/opensearch-go/v2/opensearchapi"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/rest"
"strings"
)
@ -13,26 +15,77 @@ import (
const (
clusterProxy = "/apis/cluster.karmada.io/v1alpha1/clusters/%s/proxy"
nodeConst = "node"
deploymentConst = "deployment"
podDetailConst = "podDetail"
podListConst = "podList"
nodeConst = "node"
detailHPAConst = "hpa"
deploymentConst = "deployment"
deploymentListConst = "deploymentList"
namespaceConst = "namespace"
detailNamespaceConst = "detailNamespace"
podDetailConst = "podDetail"
podListConst = "podList"
detailPvcConst = "detailPvc"
pvcListConst = "pvcList"
serviceConst = "service"
detailServiceConst = "detailService"
allServiceConst = "allService"
scConst = "sc"
pvcConst = "pvc"
pvConst = "pv"
podMetrics = "podMetrics"
nodeMetrics = "nodeMetrics"
crdConst = "crd"
secretConst = "secret"
configMapConst = "configMap"
statefulSetConst = "statefulSet"
daemonSetConst = "daemonSet"
allPodConst = "allPod"
detailPodConst = "detailPod"
detailNodeConst = "detailNode"
statefulSetListConst = "statefulSetList"
daemonSetListConst = "daemonSetList"
jobListConst = "jobList"
allDeploymentConst = "allDeployment"
allDaemonSetConst = "allDaemonSet"
allStatefulSetConst = "allStatefulSet"
controllerVersionConst = "controllerVersion"
hpaListConst = "hpaList"
replicaSetConst = "replicaSet"
pvcConst = "pvc"
pvConst = "pv"
podMetrics = "podMetrics"
nodeMetrics = "nodeMetrics"
crdConst = "crd"
pvUrl = "/api/v1/persistentvolumes"
pvcUrl = "/api/v1/namespaces/%s/persistentvolumeclaims"
nodeUrl = "/api/v1/nodes"
deploymentUrl = "/apis/apps/v1/namespaces/%s/deployments"
podListUrl = "/api/v1/namespaces/%s/pods"
podDetailUrl = "/api/v1/namespaces/%s/pods/%s"
podMetricsUrl = "/apis/metrics.k8s.io/v1beta1/namespaces/%s/pods/%s"
nodeMetricsUrl = "/apis/metrics.k8s.io/v1beta1/nodes"
crdUrl = "/apis/apiextensions.k8s.io/v1/customresourcedefinitions"
hpaListUrl = "/apis/autoscaling/v1/namespaces/%s/horizontalpodautoscalers"
detailHpaUrl = "/apis/autoscaling/v1/namespaces/%s/horizontalpodautoscalers/%s"
deploymentListUrl = "/apis/apps/v1/namespaces/%s/deployments"
daemonSetUrl = "/apis/apps/v1/namespaces/%s/daemonsets/%s"
statefulSetUrl = "/apis/apps/v1/namespaces/%s/statefulsets/%s"
statefulSetListUrl = "/apis/apps/v1/namespaces/%s/statefulsets"
daemonSetListUrl = "/apis/apps/v1/namespaces/%s/daemonsets"
replicaSetUrl = "/apis/apps/v1/namespaces/%s/replicasets"
secretUrl = "/api/v1/namespaces/%s/secrets"
configMapUrl = "/api/v1/namespaces/%s/configmaps"
scUrl = "/apis/storage.k8s.io/v1/storageclasses"
pvUrl = "/api/v1/persistentvolumes"
pvcUrl = "/api/v1/persistentvolumeclaims"
detailPvcUrl = "/api/v1/namespaces/%s/persistentvolumeclaims/%s"
nodeUrl = "/api/v1/nodes"
detailNodeUrl = "/api/v1/nodes/%s"
namespaceUrl = "/api/v1/namespaces"
deploymentUrl = "/apis/apps/v1/namespaces/%s/deployments/%s"
allDeploymentUrl = "/apis/apps/v1/deployments"
allStatefulSetUrl = "/apis/apps/v1/statefulsets"
allDaemonSetUrl = "/apis/apps/v1/daemonsets"
podListUrl = "/api/v1/namespaces/%s/pods"
allPodUrl = "/api/v1/pods"
detailPodUrl = "/api/v1/namespaces/%s/pods/%s"
podDetailUrl = "/api/v1/namespaces/%s/pods/%s"
serviceUrl = "/api/v1/namespaces/%s/services"
allServiceUrl = "/api/v1/services"
detailServiceUrl = "/api/v1/namespaces/%s/services/%s"
podMetricsUrl = "/apis/metrics.k8s.io/v1beta1/namespaces/%s/pods/%s"
nodeMetricsUrl = "/apis/metrics.k8s.io/v1beta1/nodes"
crdUrl = "/apis/apiextensions.k8s.io/v1/customresourcedefinitions"
detailNamespaceUrl = "/api/v1/namespaces/%s"
jobListUrl = "/apis/batch/v1/namespaces/%s/jobs"
pvcListUrl = "/api/v1/namespaces/%s/persistentvolumeclaims"
controllerVersionUrl = "/apis/apps/v1/namespaces/%s/controllerrevisions"
)
func JointUrl(objectType string, clusterName string, namespace string, objectName string) string {
@ -46,7 +99,13 @@ func JointUrl(objectType string, clusterName string, namespace string, objectNam
case "node":
url.WriteString(nodeUrl)
case "deployment":
url.WriteString(fmt.Sprintf(deploymentUrl, namespace))
url.WriteString(fmt.Sprintf(deploymentUrl, namespace, objectName))
case "allStatefulSet":
url.WriteString(allStatefulSetUrl)
case "allDaemonSet":
url.WriteString(allDaemonSetUrl)
case "allDeployment":
url.WriteString(allDeploymentUrl)
case "podList":
url.WriteString(fmt.Sprintf(podListUrl, namespace))
case "podDetail":
@ -54,10 +113,57 @@ func JointUrl(objectType string, clusterName string, namespace string, objectNam
case "pv":
url.WriteString(pvUrl)
case "pvc":
url.WriteString(fmt.Sprintf(pvcUrl, namespace))
url.WriteString(pvcUrl)
case "crd":
url.WriteString(crdUrl)
case "namespace":
url.WriteString(namespaceUrl)
case "sc":
url.WriteString(scUrl)
case "service":
url.WriteString(fmt.Sprintf(serviceUrl, namespace))
case "allService":
url.WriteString(allServiceUrl)
case "detailService":
url.WriteString(fmt.Sprintf(detailServiceUrl, namespace, objectName))
case "secret":
url.WriteString(fmt.Sprintf(secretUrl, namespace))
case "replicaSet":
url.WriteString(fmt.Sprintf(replicaSetUrl, namespace))
case "statefulSet":
url.WriteString(fmt.Sprintf(statefulSetUrl, namespace, objectName))
case "daemonSet":
url.WriteString(fmt.Sprintf(daemonSetUrl, namespace, objectName))
case "detailPvc":
url.WriteString(fmt.Sprintf(detailPvcUrl, namespace, objectName))
case "configMap":
url.WriteString(fmt.Sprintf(configMapUrl, namespace))
case "allPod":
url.WriteString(fmt.Sprintf(allPodUrl))
case "detailPod":
url.WriteString(fmt.Sprintf(detailPodUrl, namespace, objectName))
case "detailNode":
url.WriteString(fmt.Sprintf(detailNodeUrl, objectName))
case "detailNamespace":
url.WriteString(fmt.Sprintf(detailNamespaceUrl, objectName))
case "deploymentList":
url.WriteString(fmt.Sprintf(deploymentListUrl, namespace))
case "statefulSetList":
url.WriteString(fmt.Sprintf(statefulSetListUrl, namespace))
case "daemonSetList":
url.WriteString(fmt.Sprintf(daemonSetListUrl, namespace))
case "jobList":
url.WriteString(fmt.Sprintf(jobListUrl, namespace))
case "pvcList":
url.WriteString(fmt.Sprintf(pvcListUrl, namespace))
case "controllerVersion":
url.WriteString(fmt.Sprintf(controllerVersionUrl, namespace))
case "hpa":
url.WriteString(fmt.Sprintf(detailHpaUrl, namespace, objectName))
case "hpaList":
url.WriteString(fmt.Sprintf(hpaListUrl, namespace))
}
return url.String()
}
@ -66,16 +172,28 @@ func SearchObject(objectType string, clusterName string, namespace string, objec
return KarmadaClient.SearchV1alpha1().RESTClient().Get().AbsPath(url).Do(context.TODO())
}
func CreateObject(objectType string, clusterName string, namespace string, object interface{}) rest.Result {
url := JointUrl(objectType, clusterName, namespace, "")
return KarmadaClient.SearchV1alpha1().RESTClient().Post().Body(object).AbsPath(url).Do(context.TODO())
func UpdateObject(objectType string, clusterName string, namespace string, objectName string, object interface{}) rest.Result {
url := JointUrl(objectType, clusterName, namespace, objectName)
objectParam, _ := json.Marshal(object)
return KarmadaClient.SearchV1alpha1().RESTClient().Put().Body(objectParam).AbsPath(url).Do(context.TODO())
}
func DeleteObject(objectType string, clusterName string, namespace string) rest.Result {
url := JointUrl(objectType, clusterName, namespace, "")
func PostObject(objectType string, clusterName string, namespace string, objectName string, object interface{}) rest.Result {
url := JointUrl(objectType, clusterName, namespace, objectName)
objectParam, _ := json.Marshal(object)
return KarmadaClient.SearchV1alpha1().RESTClient().Post().Body(objectParam).AbsPath(url).Do(context.TODO())
}
func DeleteObject(objectType string, clusterName string, namespace string, objectName string) rest.Result {
url := JointUrl(objectType, clusterName, namespace, objectName)
return KarmadaClient.SearchV1alpha1().RESTClient().Delete().AbsPath(url).Do(context.TODO())
}
func PatchObject(objectType string, clusterName string, namespace string, objectName string, object interface{}, pt types.PatchType) rest.Result {
url := JointUrl(objectType, clusterName, namespace, objectName)
return KarmadaClient.SearchV1alpha1().RESTClient().Patch(pt).Body(object).AbsPath(url).Do(context.TODO())
}
func GetDeployFromOS(namespaceName string, deploymentName string, clusterName string) *simplejson.Json {
var content *strings.Reader

View File

@ -6,6 +6,43 @@ import (
"github.com/golang/glog"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"net/http"
"sync"
)
const (
apiserver_request_rate = "apiserver:apiserver_request_total:sum_irate{cluster_name='clusterName', prometheus_replica='prometheus-k8s-0'}"
apiserver_request_latencies = "apiserver:apiserver_request_duration:avg{cluster_name='clusterName', prometheus_replica='prometheus-k8s-0'}"
Schedule = "Schedule"
scheduler_schedule_attempts = "scheduler:scheduler_schedule_attempts:sum{cluster_name='clusterName', result='Schedule', prometheus_replica='prometheus-k8s-0'}"
cluster_pod_running_count = "cluster:pod_running:count{cluster_name='clusterName',prometheus_replica='prometheus-k8s-0'}"
cluster_memory_total = "sum by (cluster) (node:node_memory_bytes_total:sum{cluster_name='clusterName',prometheus_replica='prometheus-k8s-0'})"
cluster_cpu_total = "sum by (cluster) (node:node_num_cpu:sum{cluster_name='clusterName',prometheus_replica='prometheus-k8s-0'})"
cluster_disk_size_capacity = "sum by (cluster) (node:disk_space_available:{cluster_name='clusterName',prometheus_replica='prometheus-k8s-0'} / (1 - node:disk_space_utilization:ratio{cluster_name='clusterName',prometheus_replica='prometheus-k8s-0'}))"
cluster_cpu_usage = "sum by (cluster) (node:node_num_cpu:sum{cluster_name='clusterName',prometheus_replica='prometheus-k8s-0'} * node:node_cpu_utilisation:avg1m{cluster_name='clusterName',prometheus_replica='prometheus-k8s-0'})"
cluster_pod_quota = "sum by (cluster) (node:pod_capacity:sum{cluster_name='clusterName',prometheus_replica='prometheus-k8s-0'})"
cluster_memory_usage_wo_cache = "sum by (cluster) (node:node_memory_bytes_total:sum{cluster_name='clusterName',prometheus_replica='prometheus-k8s-0'} - node:node_memory_bytes_available:sum{cluster_name='clusterName',prometheus_replica='prometheus-k8s-0'})"
cluster_disk_size_usage = "(sum by (cluster) (node:disk_space_available:{cluster_name='clusterName',prometheus_replica='prometheus-k8s-0'}) / (1 - cluster:disk_utilization:ratio{cluster_name='clusterName',prometheus_replica='prometheus-k8s-0'})) * cluster:disk_utilization:ratio{cluster_name='clusterName',prometheus_replica='prometheus-k8s-0'}"
node_cpu_total = "node:node_num_cpu:sum{cluster_name='clusterName',prometheus_replica='prometheus-k8s-0'}"
node_cpu_usage = "node:node_num_cpu:sum{cluster_name='clusterName',prometheus_replica='prometheus-k8s-0'} * node:node_cpu_utilisation:avg1m{cluster_name='clusterName',prometheus_replica='prometheus-k8s-0'}"
node_cpu_utilisation = "node:node_cpu_utilisation:avg1m{cluster_name='clusterName',prometheus_replica='prometheus-k8s-0'}"
node_load1 = "node:load1:ratio{cluster_name='clusterName', prometheus_replica='prometheus-k8s-0'}"
node_load15 = "node:load15:ratio{cluster_name='clusterName', prometheus_replica='prometheus-k8s-0'}"
node_memory_total = "node:node_memory_bytes_total:sum{cluster_name='clusterName',prometheus_replica='prometheus-k8s-0'}"
node_memory_usage_wo_cache = "node:node_memory_bytes_total:sum{cluster_name='clusterName',prometheus_replica='prometheus-k8s-0'} - node:node_memory_bytes_available:sum{cluster_name='clusterName',prometheus_replica='prometheus-k8s-0'}"
node_memory_utilisation = "node:node_memory_utilisation:{cluster_name='clusterName',prometheus_replica='prometheus-k8s-0'}"
node_pod_quota = "node:pod_capacity:sum{cluster_name='clusterName',prometheus_replica='prometheus-k8s-0'}"
node_pod_running_count = "node:pod_running:count{cluster_name='clusterName', prometheus_replica='prometheus-k8s-0'}"
nvidia_smi_utilization_gpu_ratio = "nvidia_smi_utilization_gpu_ratio{cluster_name='clusterName'}"
nvidia_smi_utilization_memory_ratio = "nvidia_smi_utilization_memory_ratio{cluster_name='clusterName'}"
ClusterName = "clusterName"
metric_range_1s = "1s"
steps_1s = 100
buffer = 5
)
type Overview struct {
@ -14,6 +51,215 @@ type Overview struct {
Pod int32 `json:"podListConst"`
}
// @Summary 获取容器集群调度器监控
// @Description 获取容器集群调度器监控
// @Tags overview
// @accept json
// @Produce json
// @Param clusterName query string true "集群名称"
// @Success 200
// @Failure 400
// @Router /api/v1/overview/getScheduleMetrics [get]
func GetScheduleMetrics(c *gin.Context) {
clusterName := c.Query(ClusterName)
scheduleSlice := []string{"error", "scheduled", "unschedulable"}
var metricUrls []MetricUrl
for _, s := range scheduleSlice {
imap := map[string]string{
ClusterName: clusterName,
Schedule: s,
}
metricUrls = append(metricUrls, MetricUrl{Schedule, s, GetMetricUrl(scheduler_schedule_attempts, imap, Schedule, metric_range_1s, steps_1s)})
}
metricMap := map[string][]MetricUrl{
"scheduler_schedule_attempts": metricUrls,
}
ch := make(chan MetricResult, len(metricMap))
var wg sync.WaitGroup
for k, v := range metricMap {
wg.Add(1)
go HttpGetMetrics(k, v, &wg, ch)
}
wg.Wait()
close(ch)
mr := []MetricResult{}
for v := range ch {
mr = append(mr, v)
}
Response(c, http.StatusOK, "success", mr)
}
// @Summary 获取容器集群资源监控
// @Description 获取容器集群资源监控
// @Tags overview
// @accept json
// @Produce json
// @Param clusterName query string true "集群名称"
// @Success 200
// @Failure 400
// @Router /api/v1/overview/getClusterMetrics [get]
func GetClusterMetrics(c *gin.Context) {
clusterName := c.Query(ClusterName)
replaceMap := make(map[string]string)
replaceMap[ClusterName] = clusterName
metricMap := map[string][]MetricUrl{
"cluster_pod_running_count": {{ClusterName, clusterName, GetMetricUrl(cluster_pod_running_count, replaceMap, ClusterName, metric_range_1s, steps_1s)}},
"cluster_memory_total": {{ClusterName, clusterName, GetMetricUrl(cluster_memory_total, replaceMap, ClusterName, metric_range_1s, steps_1s)}},
"cluster_cpu_total": {{ClusterName, clusterName, GetMetricUrl(cluster_cpu_total, replaceMap, ClusterName, metric_range_1s, steps_1s)}},
"cluster_disk_size_capacity": {{ClusterName, clusterName, GetMetricUrl(cluster_disk_size_capacity, replaceMap, ClusterName, metric_range_1s, steps_1s)}},
"cluster_cpu_usage": {{ClusterName, clusterName, GetMetricUrl(cluster_cpu_usage, replaceMap, ClusterName, metric_range_1s, steps_1s)}},
"cluster_pod_quota": {{ClusterName, clusterName, GetMetricUrl(cluster_pod_quota, replaceMap, ClusterName, metric_range_1s, steps_1s)}},
"cluster_memory_usage_wo_cache": {{ClusterName, clusterName, GetMetricUrl(cluster_memory_usage_wo_cache, replaceMap, ClusterName, metric_range_1s, steps_1s)}},
"cluster_disk_size_usage": {{ClusterName, clusterName, GetMetricUrl(cluster_disk_size_usage, replaceMap, ClusterName, metric_range_1s, steps_1s)}},
}
mr := []MetricResult{}
ch := make(chan MetricResult, len(metricMap))
limit := make(chan bool, buffer)
var wg sync.WaitGroup
for k, v := range metricMap {
limit <- true
wg.Add(1)
go HttpGetMetrics(k, v, &wg, ch)
<-limit
}
wg.Wait()
close(ch)
for v := range ch {
mr = append(mr, v)
}
Response(c, http.StatusOK, "success", mr)
}
// @Summary 获取容器节点资源监控
// @Description 获取容器节点资源监控
// @Tags overview
// @accept json
// @Produce json
// @Param clusterName query string true "集群名称"
// @Success 200
// @Failure 400
// @Router /api/v1/overview/getNodeMetrics [get]
func GetNodeMetrics(c *gin.Context) {
clusterName := c.Query(ClusterName)
//client, err := clientSet.GetClientSet(clusterName)
//if err != nil {
// log.Fatalln(err)
//}
//nodeList, err := client.CoreV1().Nodes().List(context.TODO(), metav1.ListOptions{})
//if err != nil {
// log.Fatalln(err)
//}
//
//nodes := []string{}
//for i := range nodeList.Items {
// nodes = append(nodes, nodeList.Items[i].Name)
//}
replaceMap := make(map[string]string)
replaceMap[ClusterName] = clusterName
mr := []MetricResult{}
//node_rs := []map[string]interface{}{}
//rd := ResultData {
// Status: "success",
// Data: MetricData{
// Result: node_rs,
// ResultType: "",
// },
//}
//nodes_mr := MetricResult{
// MetricName: "node",
// ResultData: rd,
//}
//mr = append(mr, nodes_mr)
metricMap := map[string][]MetricUrl{
"node_cpu_total": {{ClusterName, clusterName, GetMetricUrl(node_cpu_total, replaceMap, ClusterName, metric_range_1s, steps_1s)}},
"node_cpu_usage": {{ClusterName, clusterName, GetMetricUrl(node_cpu_usage, replaceMap, ClusterName, metric_range_1s, steps_1s)}},
"node_cpu_utilisation": {{ClusterName, clusterName, GetMetricUrl(node_cpu_utilisation, replaceMap, ClusterName, metric_range_1s, steps_1s)}},
"node_load1": {{ClusterName, clusterName, GetMetricUrl(node_load1, replaceMap, ClusterName, metric_range_1s, steps_1s)}},
"node_load15": {{ClusterName, clusterName, GetMetricUrl(node_load15, replaceMap, ClusterName, metric_range_1s, steps_1s)}},
"node_memory_total": {{ClusterName, clusterName, GetMetricUrl(node_memory_total, replaceMap, ClusterName, metric_range_1s, steps_1s)}},
"node_memory_usage_wo_cache": {{ClusterName, clusterName, GetMetricUrl(node_memory_usage_wo_cache, replaceMap, ClusterName, metric_range_1s, steps_1s)}},
"node_memory_utilisation": {{ClusterName, clusterName, GetMetricUrl(node_memory_utilisation, replaceMap, ClusterName, metric_range_1s, steps_1s)}},
"node_pod_quota": {{ClusterName, clusterName, GetMetricUrl(node_pod_quota, replaceMap, ClusterName, metric_range_1s, steps_1s)}},
"node_pod_running_count": {{ClusterName, clusterName, GetMetricUrl(node_pod_running_count, replaceMap, ClusterName, metric_range_1s, steps_1s)}},
"nvidia_smi_utilization_gpu_ratio": {{ClusterName, clusterName, GetMetricUrl(nvidia_smi_utilization_gpu_ratio, replaceMap, ClusterName, metric_range_1s, steps_1s)}},
"nvidia_smi_utilization_memory_ratio": {{ClusterName, clusterName, GetMetricUrl(nvidia_smi_utilization_memory_ratio, replaceMap, ClusterName, metric_range_1s, steps_1s)}},
}
ch := make(chan MetricResult, len(metricMap))
limit := make(chan bool, buffer)
var wg sync.WaitGroup
for k, v := range metricMap {
limit <- true
wg.Add(1)
go HttpGetMetrics(k, v, &wg, ch)
<-limit
}
wg.Wait()
close(ch)
for v := range ch {
mr = append(mr, v)
}
Response(c, http.StatusOK, "success", mr)
}
// @Summary 获取ApiServer请求数和请求延迟
// @Description 获取ApiServer请求数和请求延迟
// @Tags overview
// @accept json
// @Produce json
// @Param clusterName query string true "集群名称"
// @Success 200
// @Failure 400
// @Router /api/v1/overview/getApiServerMetrics [get]
func GetApiServerMetrics(c *gin.Context) {
clusterName := c.Query(ClusterName)
replaceMap := make(map[string]string)
replaceMap[ClusterName] = clusterName
metricMap := map[string][]MetricUrl{
"apiserver_request_rate": {{ClusterName, clusterName, GetMetricUrl(apiserver_request_rate, replaceMap, ClusterName, metric_range_1s, steps_1s)}},
"apiserver_request_latencies": {{ClusterName, clusterName, GetMetricUrl(apiserver_request_latencies, replaceMap, ClusterName, metric_range_1s, steps_1s)}},
}
ch := make(chan MetricResult, len(metricMap))
var wg sync.WaitGroup
for k, v := range metricMap {
wg.Add(1)
go HttpGetMetrics(k, v, &wg, ch)
}
wg.Wait()
close(ch)
mr := []MetricResult{}
for v := range ch {
mr = append(mr, v)
}
Response(c, http.StatusOK, "success", mr)
}
func ResourceCount(c *gin.Context) {
overview := &Overview{}
//纳管资源域、纳管集群总计、容器创建数量 资源域

View File

@ -1,5 +1,7 @@
package app
import "strconv"
type Page[T any] struct {
// 当前页码
PageNum int64 `json:"pageNum"`
@ -14,7 +16,9 @@ type Page[T any] struct {
}
// Paginator 生成新的分页数据对象
func Paginator[T any](items *Page[T], total, pageNum, pageSize int64) *Page[T] {
func Paginator[T any](items *Page[T], total int64, pageNumParam, pageSizeParam string) *Page[T] {
pageNum, _ := strconv.ParseInt(pageNumParam, 10, 64)
pageSize, _ := strconv.ParseInt(pageSizeParam, 10, 64)
var (
pageStart int64
pageEnd int64

View File

@ -5,6 +5,7 @@ import (
"encoding/json"
"github.com/gin-gonic/gin"
"github.com/shopspring/decimal"
v12 "k8s.io/api/apps/v1"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/metrics/pkg/apis/metrics"
@ -12,11 +13,22 @@ import (
"net/http"
"sort"
"strings"
"sync"
)
const (
pod_cpu_usage = "irate(container_cpu_usage_seconds_total{cluster_name='clusterName', pod='podName', container='', prometheus_replica='prometheus-k8s-0'}[10m])"
pod_memery_usage_wo_cache = "container_memory_working_set_bytes{cluster_name='clusterName', pod='podName', container='', prometheus_replica='prometheus-k8s-0'}"
pod_net_bytes_transmitted = "irate(container_network_transmit_bytes_total{cluster_name='clusterName', pod='podName', interface='eth0', prometheus_replica='prometheus-k8s-0'}[10m])"
pod_net_bytes_received = "irate(container_network_receive_bytes_total{cluster_name='clusterName', pod='podName', interface='eth0',prometheus_replica='prometheus-k8s-0'}[10m])"
PodName = "podName"
pod_metric_range = "8.333h"
steps_pod = 600
)
type Pod struct {
PageNum int64 `json:"page_num"`
PageSize int64 `json:"page_size"`
PageNum string `json:"page_num"`
PageSize string `json:"page_size"`
Name string `json:"name"`
ClusterName string `json:"cluster_name"`
DomainName string `json:"domain_name"`
@ -34,7 +46,7 @@ type Pod struct {
TemplateId string `json:"template_id"`
}
type PodRes struct {
type PodObject struct {
Kind string `json:"kind"`
ApiVersion string `json:"apiVersion"`
Metadata string `json:"metadata"`
@ -42,13 +54,27 @@ type PodRes struct {
Items []v1.Pod `json:"items"`
}
//type MetricsRes struct {
// Kind string `json:"kind"`
// ApiVersion string `json:"apiVersion"`
// Metadata string `json:"metadata"`
// ResourceVersion string `json:"resourceVersion"`
// Items []metrics.PodMetrics `json:"items"`
//}
type DeploymentPods struct {
Replicas int32 `json:"replicas"`
AvailableReplicas int32 `json:"availableReplicas"`
Pods []v1.Pod `json:"pods"`
}
type ReplicaSetRes struct {
Kind string `json:"kind"`
ApiVersion string `json:"apiVersion"`
Metadata string `json:"metadata"`
ResourceVersion string `json:"resourceVersion"`
Items []v12.ReplicaSet `json:"items"`
}
type StatefulSetRes struct {
Kind string `json:"kind"`
ApiVersion string `json:"apiVersion"`
Metadata string `json:"metadata"`
ResourceVersion string `json:"resourceVersion"`
Items []v12.StatefulSet `json:"items"`
}
// PodMetrics 根据集群名称、命名空间和pod名称查询pod使用率
// @Summary 根据集群名称、命名空间和pod名称查询pod使用率
@ -63,9 +89,9 @@ type PodRes struct {
// @Failure 500
// @Router /api/v1/pod/metrics/{clusterName}/{namespace}/{name} [get]
func PodMetrics(c *gin.Context) {
clusterName := c.Param("clusterName")
namespace := c.Param("namespace")
name := c.Param("name")
clusterName := c.Query("clusterName")
namespace := c.Query("namespace")
name := c.Query("name")
result := SearchObject(podMetrics, clusterName, namespace, name)
var metrics metrics.PodMetrics
raw, _ := result.Raw()
@ -94,12 +120,13 @@ func PodMetrics(c *gin.Context) {
// @Success 200
// @Failure 500
// @Router /api/v1/pod/detail/{clusterName}/{namespace}/{name} [get]
// PodDetail 根据指定集群查询Pod详情
func PodDetail(c *gin.Context) {
clusterName := c.Param("clusterName")
namespace := c.Param("namespace")
name := c.Param("name")
clusterName := c.Query("clusterName")
namespace := c.Query("namespace")
name := c.Query("name")
result := SearchObject(podListConst, clusterName, namespace, "")
var podRes PodRes
var podRes PodObject
raw, _ := result.Raw()
json.Unmarshal(raw, &podRes)
for _, pod := range podRes.Items {
@ -111,28 +138,46 @@ func PodDetail(c *gin.Context) {
Response(c, http.StatusOK, "success", nil)
}
// IsExist 判断名称是否重复
func IsExist(c *gin.Context) {
clusterName := c.Query("clusterName")
namespace := c.Query("namespace")
name := c.Query("name")
result := SearchObject(podDetailConst, clusterName, namespace, name)
if result.Error() != nil {
Response(c, http.StatusOK, "success", false)
return
}
var pod v1.Pod
raw, _ := result.Raw()
json.Unmarshal(raw, &pod)
if len(pod.Name) == 0 {
Response(c, http.StatusOK, "success", false)
return
}
Response(c, http.StatusOK, "success", true)
}
// ListPod 根据指定集群查询Pod列表
// @Summary 根据指定集群查询Pod列表
// @Description 根据指定集群查询Pod列表
// @Tags pod
// @accept json
// @Produce json
// @Param param body Pod true "json"
// @Success 200
// @Failure 500
// @Router /api/v1/pod/list [get]
func ListPod(c *gin.Context) {
var param Pod
if err := c.BindJSON(&param); err != nil {
Response(c, http.StatusBadRequest, "invalid request params.", "")
return
}
result := SearchObject(podListConst, param.ClusterName, param.Namespace, "")
clusterName := c.Query("clusterName")
namespace := c.Query("namespace")
pageNum := c.Query("pageNum")
pageSize := c.Query("pageSize")
result := SearchObject(podListConst, clusterName, namespace, "")
if result.Error() != nil {
Response(c, http.StatusInternalServerError, "failed", result.Error())
return
}
var podRes PodRes
var podRes PodObject
raw, _ := result.Raw()
json.Unmarshal(raw, &podRes)
@ -143,7 +188,43 @@ func ListPod(c *gin.Context) {
return podRes.Items[i].CreationTimestamp.Time.After(podRes.Items[j].CreationTimestamp.Time)
})
page.List = podRes.Items
data := Paginator(page, int64(len(podRes.Items)), param.PageNum, param.PageSize)
data := Paginator(page, int64(len(podRes.Items)), pageNum, pageSize)
Response(c, http.StatusOK, "success", data)
}
// ListPod 根据指定集群查询Pod列表
// @Summary 根据指定集群查询Pod列表
// @Description 根据指定集群查询Pod列表
// @Param clusterName query string true "集群名称"
// @Param pageNum query int true "pageNum"
// @Param pageSize query int true "pageSize"
// @Tags pod
// @accept json
// @Produce json
// @Success 200
// @Failure 500
// @Router /api/v1/pod/all [get]
func ALLPod(c *gin.Context) {
clusterName := c.Query("clusterName")
pageNum := c.Query("pageNum")
pageSize := c.Query("pageSize")
result := SearchObject(allPodConst, clusterName, "", "")
if result.Error() != nil {
Response(c, http.StatusInternalServerError, "failed", result.Error())
return
}
var podRes PodObject
raw, _ := result.Raw()
json.Unmarshal(raw, &podRes)
// 分页
page := &Page[v1.Pod]{}
// 排序
sort.SliceStable(podRes.Items, func(i, j int) bool {
return podRes.Items[i].CreationTimestamp.Time.After(podRes.Items[j].CreationTimestamp.Time)
})
page.List = podRes.Items
data := Paginator(page, int64(len(podRes.Items)), pageNum, pageSize)
Response(c, http.StatusOK, "success", data)
}
@ -205,20 +286,30 @@ func CreatePod(c *gin.Context) {
// @accept json
// @Produce json
// @Param namespace path string true "命名空间名"
//@param name path string true "Pod名"
// @param name path string true "Pod名"
// @Success 200
// @Failure 400
// @Router /api/v1/pod/delete/{namespace}/{name} [delete]
func DeletePod(c *gin.Context) {
clusterName := c.Param("clusterName")
namespace := c.Param("namespace")
name := c.Param("name")
err := ClientSet.CoreV1().Pods(namespace).Delete(context.TODO(), name, metav1.DeleteOptions{})
if err != nil {
Response(c, http.StatusInternalServerError, "delete podListConst failed", err)
return
label := c.Param("label")
if strings.EqualFold(label, "jcce") {
err := ClientSet.CoreV1().Pods(namespace).Delete(context.TODO(), name, metav1.DeleteOptions{})
if err != nil {
Response(c, http.StatusInternalServerError, "delete pod failed", err)
return
}
// 删除调度策略
DeletePropagationPolicies(namespace, "Pod"+namespace+name)
} else {
result := DeleteObject(detailPodConst, clusterName, namespace, name)
if result.Error() != nil {
Response(c, http.StatusInternalServerError, "delete pod failed", result.Error())
return
}
}
// 删除调度策略
DeletePropagationPolicies(namespace, "pod"+namespace+name)
Response(c, http.StatusOK, "success", nil)
}
@ -258,6 +349,90 @@ func UpdatePod(c *gin.Context) {
Response(c, http.StatusOK, "success", podResult)
}
// ListPodFromNode 获取节点下的pod
func ListPodFromNode(c *gin.Context) {
clusterName := c.Query("clusterName")
nodeName := c.Query("nodeName")
podResult := SearchObject(allPodConst, clusterName, "", "")
if podResult.Error() != nil {
Response(c, http.StatusInternalServerError, "failed", podResult.Error())
return
}
var podRes PodObject
raw, _ := podResult.Raw()
json.Unmarshal(raw, &podRes)
var result []v1.Pod
for i := range podRes.Items {
if strings.EqualFold(podRes.Items[i].Spec.NodeName, nodeName) {
result = append(result, podRes.Items[i])
}
}
Response(c, http.StatusOK, "success", result)
}
func GetPodForDeployment(clusterName string, namespace string, labelMap map[string]string) []v1.Pod {
// 查询pod当前命名空间下的列表
podResult := SearchObject(podListConst, clusterName, namespace, "")
var podObject PodObject
podRaw, _ := podResult.Raw()
json.Unmarshal(podRaw, &podObject)
// 查询label匹配的pod
var podsResult []v1.Pod
for _, pod := range podObject.Items {
for k, v := range labelMap {
if pod.Labels[k] != v {
goto loop
}
}
podsResult = append(podsResult, pod)
loop:
}
return podsResult
}
// ListPodFromDeployment 获取deployment下的pod
func ListPodFromDeployment(c *gin.Context) {
clusterName := c.Query("clusterName")
namespace := c.Query("namespace")
label := c.Query("label")
var labelMap = make(map[string]string)
labelArray := strings.Split(label, ",")
for _, label := range labelArray {
labelKV := strings.Split(label, "=")
labelMap[labelKV[0]] = labelKV[1]
}
podList := GetPodForDeployment(clusterName, namespace, labelMap)
var replicas, availableReplicas int32
// 查询replicaSet
var replicaSetObject ReplicaSetObject
searchResult := SearchObject(replicaSetConst, clusterName, namespace, "")
raw, _ := searchResult.Raw()
json.Unmarshal(raw, &replicaSetObject)
for _, replicaSet := range replicaSetObject.Items {
for k, v := range labelMap {
if replicaSet.Labels[k] != v {
goto loop1
}
}
if replicaSet.Status.Replicas != 0 {
replicas = replicas + 1
if replicaSet.Status.AvailableReplicas != 0 {
availableReplicas = availableReplicas + 1
}
}
loop1:
}
Response(c, http.StatusOK, "success", DeploymentPods{
Pods: podList,
Replicas: replicas,
AvailableReplicas: availableReplicas,
})
}
// GetPodDetail 获取容器组详情
// @Summary 获取容器组详情
// @Description 获取容器组详情
@ -269,21 +444,60 @@ func UpdatePod(c *gin.Context) {
// @Failure 400
// @Router /api/v1/pod/detail [put]
func GetPodDetail(c *gin.Context) {
var param Pod
if err := c.BindJSON(&param); err != nil {
Response(c, http.StatusBadRequest, "invalid request params.", "")
return
}
podResult, err := ClientSet.CoreV1().Pods(param.Namespace).Get(context.TODO(), param.Name, metav1.GetOptions{})
if err != nil {
Response(c, http.StatusInternalServerError, "query podListConst failed", err)
return
}
clusterName := c.Query("clusterName")
namespace := c.Query("namespace")
name := c.Query("name")
rsRes := SearchObject(detailPodConst, clusterName, namespace, name)
raw, _ := rsRes.Raw()
var pod v1.Pod
json.Unmarshal(raw, &pod)
err_ := AddTypeMetaToObject(podResult)
err_ := AddTypeMetaToObject(&pod)
if err_ != nil {
log.Println(err_)
}
Response(c, http.StatusOK, "success", podResult)
Response(c, http.StatusOK, "success", pod)
}
// @Summary 获取容器组监控
// @Description 获取容器组监控
// @Tags pod
// @accept json
// @Produce json
// @Param clusterName query string true "集群名称"
// @Param podName query string true "容器组名称"
// @Success 200
// @Failure 400
// @Router /api/v1/pod/metrics [get]
func GetMetrics(c *gin.Context) {
clusterName := c.Query("clusterName")
podName := c.Query("podName")
replaceMap := make(map[string]string)
replaceMap[ClusterName] = clusterName
replaceMap[PodName] = podName
metricMap := map[string][]MetricUrl{
"pod_cpu_usage": {{PodName, podName, GetMetricUrl(pod_cpu_usage, replaceMap, PodName, pod_metric_range, steps_pod)}},
"pod_memory_usage_wo_cache": {{PodName, podName, GetMetricUrl(pod_memery_usage_wo_cache, replaceMap, PodName, pod_metric_range, steps_pod)}},
"pod_net_bytes_transmitted": {{PodName, podName, GetMetricUrl(pod_net_bytes_transmitted, replaceMap, PodName, pod_metric_range, steps_pod)}},
"pod_net_bytes_received": {{PodName, podName, GetMetricUrl(pod_net_bytes_received, replaceMap, PodName, pod_metric_range, steps_pod)}},
}
ch := make(chan MetricResult, len(metricMap))
var wg sync.WaitGroup
for k, v := range metricMap {
wg.Add(1)
go HttpGetMetrics(k, v, &wg, ch)
}
wg.Wait()
close(ch)
mr := []MetricResult{}
for v := range ch {
mr = append(mr, v)
}
Response(c, http.StatusOK, "success", mr)
}

View File

@ -8,7 +8,6 @@ import (
policyv1alpha1 "github.com/karmada-io/karmada/pkg/apis/policy/v1alpha1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"net/http"
"strconv"
"strings"
)
@ -119,9 +118,11 @@ func CreatePropagationPolicies(propagationPolicy PropagationPolicy) error {
},
}
switch propagationPolicy.Kind {
case "Pod", "Service", "PersistentVolumeClaim", "ConfigMap":
case "HorizontalPodAutoscaler":
policy.Spec.ResourceSelectors[0].APIVersion = "autoscaling/v1"
case "Pod", "Service", "PersistentVolumeClaim", "ConfigMap", "Namespace":
policy.Spec.ResourceSelectors[0].APIVersion = "v1"
case "DeploymentParam":
case "Deployment", "StatefulSet", "DaemonSet":
policy.Spec.ResourceSelectors[0].APIVersion = "apps/v1"
}
_, err := KarmadaClient.PolicyV1alpha1().PropagationPolicies(propagationPolicy.Namespace).Create(context.TODO(), policy, v1.CreateOptions{})
@ -153,9 +154,9 @@ func CreatePropagationPolicies(propagationPolicy PropagationPolicy) error {
// @Router /api/v1/propagationPolicy/list [get]
func ListPropagationPolicies(c *gin.Context) {
labelKey, _ := c.GetQuery("label_key")
labelValue, _ := c.GetQuery("label_value")
policyName, _ := c.GetQuery("policy_name")
labelKey := c.Query("label_key")
labelValue := c.Query("label_value")
policyName := c.Query("policy_name")
opts := v1.ListOptions{
TypeMeta: v1.TypeMeta{},
@ -239,18 +240,21 @@ func ListPropagationPolicies(c *gin.Context) {
total := len(proPolicyList)
page := &Page[PropagationPolicy]{}
page.List = proPolicyList
pageNum, _ := c.GetQuery("pageNum")
pageSize, _ := c.GetQuery("pageSize")
num, _ := strconv.ParseInt(pageNum, 10, 64)
size, _ := strconv.ParseInt(pageSize, 10, 64)
data := Paginator(page, int64(total), num, size)
pageNum := c.Query("pageNum")
pageSize := c.Query("pageSize")
data := Paginator(page, int64(total), pageNum, pageSize)
Response(c, http.StatusOK, "success", data)
}
// UpdatePropagationPolicies 更新集群分发策略
func UpdatePropagationPolicies(c *gin.Context) {
var propagationPolicy policyv1alpha1.PropagationPolicy
_, err := KarmadaClient.PolicyV1alpha1().PropagationPolicies(propagationPolicy.Namespace).Update(context.TODO(), &propagationPolicy, v1.UpdateOptions{})
if err != nil {
Response(c, http.StatusInternalServerError, "update propagationPolicy failed", err)
return
}
Response(c, http.StatusOK, "success", nil)
}

View File

@ -3,7 +3,6 @@ package app
import (
"github.com/gin-gonic/gin"
"net/http"
"strconv"
)
type PropagationPolicyTemplate struct {
@ -79,7 +78,7 @@ func DeletePropagationPolicyTemplate(c *gin.Context) {
// @Router /api/v1/propagationPolicyTemplate/list [get]
func ListPropagationPolicyTemplate(c *gin.Context) {
pptName, _ := c.GetQuery("template_name")
pptName := c.Query("template_name")
PptList := make([]PropagationPolicyTemplate, 0)
rows, err := DB.Query(`SELECT * FROM propagation_policy_template ppt where ppt.template_name like ?`, "%"+pptName+"%")
@ -102,11 +101,9 @@ func ListPropagationPolicyTemplate(c *gin.Context) {
total := len(PptList)
page := &Page[PropagationPolicyTemplate]{}
page.List = PptList
pageNum, _ := c.GetQuery("pageNum")
pageSize, _ := c.GetQuery("pageSize")
num, _ := strconv.ParseInt(pageNum, 10, 64)
size, _ := strconv.ParseInt(pageSize, 10, 64)
data := Paginator(page, int64(total), num, size)
pageNum := c.Query("pageNum")
pageSize := c.Query("pageSize")
data := Paginator(page, int64(total), pageNum, pageSize)
Response(c, http.StatusOK, "success", data)
//Response(c, http.StatusOK, "success", PptList)

View File

@ -12,6 +12,7 @@ import (
swaggerFiles "github.com/swaggo/files"
ginSwagger "github.com/swaggo/gin-swagger"
_ "jcc-schedule/docs"
"k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
kubeclient "k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
@ -25,6 +26,7 @@ var KarmadaConfig karmadactl.KarmadaConfig
var ControlPlaneRestConfig *rest.Config
var ClientSet *kubeclient.Clientset
var OpenSearchClient *opensearch.Client
var CrDClient *clientset.Clientset
var ConfigNacos = GetNacosConfig()
@ -47,7 +49,7 @@ func InitRouter() *gin.Engine {
ControlPlaneRestConfig, _ = KarmadaConfig.GetRestConfig("", dir+"/karmadaConfig/karmada-host")
KarmadaClient = karmadaclientset.NewForConfigOrDie(ControlPlaneRestConfig)
ClientSet, _ = utils.NewClientSet(ControlPlaneRestConfig)
CrDClient, _ = utils.NewCRDsClient(ControlPlaneRestConfig)
// 初始化OpenSearch客户端
OpenSearchClient, _ = opensearch.NewClient(opensearch.Config{
Transport: &http.Transport{
@ -79,10 +81,17 @@ func InitRouter() *gin.Engine {
//Namespace
namespace := v1.Group("namespace")
namespace.GET("/list", ListNamespace)
namespace.GET("/isExist", IsExistNamespace)
namespace.GET("/list/name", ListName)
namespace.GET("/listFromCluster", ListNamespaceFromCluster)
namespace.GET("/describe", DescribeNamespace)
namespace.GET("/detail", DetailNamespace)
namespace.POST("/create", CreateNamespace)
namespace.POST("/delete", DeleteNamespace)
namespace.POST("/update", UpdateNamespace)
namespace.DELETE("/delete/:clusterName/:name/:label", DeleteNamespace)
namespace.PUT("/update", UpdateNamespace)
namespace.GET("/getBatchMetrics", GetBatchNamespaceMetrics)
namespace.GET("/getMetrics", GetNamespaceMetrics)
namespace.GET("/resources", GetNamespaceResources)
//Domain
domain := v1.Group("domain")
@ -94,12 +103,18 @@ func InitRouter() *gin.Engine {
//Pod
pod := v1.Group("pod")
pod.GET("/list", ListPod)
pod.GET("/detail/:clusterName/:namespace/:name", PodDetail)
pod.GET("/metrics/:clusterName/:namespace/:name", PodMetrics)
pod.GET("/all", ALLPod)
pod.GET("/isExist", IsExist)
pod.GET("/detail", PodDetail)
pod.GET("/cpuAndMemory", PodMetrics)
pod.POST("/create", CreatePod)
pod.DELETE("/delete/:namespace/:name", DeletePod)
pod.DELETE("/delete/:clusterName/:namespace/:name/:label", DeletePod)
pod.PUT("/updatePod", UpdatePod)
pod.PUT("/detail", GetPodDetail)
pod.GET("/listFromDeployment", ListPodFromDeployment)
pod.GET("/listFromNode", ListPodFromNode)
pod.GET("/pod/metrics", ListPodFromNode)
pod.GET("/metrics", GetMetrics)
//Cluster
cluster := v1.Group("cluster")
@ -117,37 +132,86 @@ func InitRouter() *gin.Engine {
//Node
node := v1.Group("node")
node.GET("/list/:clusterName", ListNode)
node.GET("/edge/:clusterName", ListEdgeNode)
node.GET("/metrics/:clusterName", ListNodeMetrics)
node.GET("/detail/:clusterName/:namespace/:podName", queryNodeInfo)
node.PUT("/update", UpdateNode)
node.GET("/list", ListNode)
node.GET("/count", NodeCount)
node.GET("/edge", ListEdgeNode)
node.GET("/metrics", ListNodeMetrics)
node.GET("/detail/pod", queryNodeInfo)
node.GET("/detail", DetailNode)
node.GET("/getNodeMetrics1h", GetNodeMetrics1h)
node.GET("/getNodeMetrics8h", GetNodeMetrics8h)
//DeploymentParam
deployment := v1.Group("deployment")
deployment := v1.Group("deployments")
deployment.POST("/create", CreateDeployment)
deployment.DELETE("/delete/:namespace/:name", DeleteDeployment)
deployment.DELETE("/delete/:clusterName/:namespace/:name/:label", DeleteDeployment)
deployment.GET("/list", ListDeployment)
deployment.GET("/listFromCluster", ListDeploymentFromCluster)
deployment.GET("/describe", DescribeDeployment)
deployment.GET("/detail", DetailDeployment)
deployment.GET("/listGlobal", ListClusterDeployment)
deployment.PUT("/redeploy", Redeploy)
deployment.PUT("/update", UpdateDeployment)
deployment.GET("/hpa", getHpa)
deployment.PUT("/autoScaling", AutoScaling)
deployment.POST("/hpa/create", CreateHpa)
deployment.GET("/getMetrics", GetDeploymentMetrics)
deployment.GET("isExist", IsExistDeployment)
deployment.GET("/controllerVersions", ControllerRevisions)
deployment.GET("/replicaSets", ListReplicaSets)
//daemonSet
daemonSet := v1.Group("daemonsets")
daemonSet.GET("/detail", DetailDaemonSet)
daemonSet.POST("/create", CreateDaemonSet)
daemonSet.DELETE("/delete/:clusterName/:namespace/:name/:label", DeleteDaemonSet)
daemonSet.PUT("/update", UpdateDaemonSet)
daemonSet.GET("isExist", IsExistDaemonSet)
daemonSet.GET("/listFromCluster", ListDaemonSetFromCluster)
//statefulSet
statefulSet := v1.Group("statefulsets")
statefulSet.GET("/listFromCluster", ListStatefulSetFromCluster)
statefulSet.GET("/detail", DetailStatefulSet)
statefulSet.DELETE("/delete/:clusterName/:namespace/:name/:label", DeleteStatefulSet)
statefulSet.POST("/create", CreateStatefulSet)
statefulSet.PUT("/update", UpdateStatefulSet)
statefulSet.GET("/isExist", IsExistStatefulSet)
// storage
storage := v1.Group("storage")
storage.POST("/pv", CreatePV)
storage.POST("/pvc", CreatePVC)
storage.GET("/pv/:clusterName", ListPV)
storage.GET("/pvc/:clusterName/:namespace", ListPVC)
storage.PUT("/pvc", UpdatePVC)
storage.DELETE("/pvc/:clusterName/:namespace/:name/:label", DeletePVC)
storage.GET("/pvc/detail", DetailPVC)
storage.GET("/pvc/isExist", IsExistPVC)
storage.GET("/pv", ListPV)
storage.GET("/pvc", ListPVC)
storage.GET("/list", ListStorageClass)
// storage
crd := v1.Group("crd")
crd.GET("/list/:clusterName", ListCRD)
crd.GET("/detail/:clusterName/:namespace/:kind", DetailCRD)
crd.GET("/create", CreateCRD)
// configMap
configMap := v1.Group("configMap")
configMap.POST("/create", CreateConfigMap)
configMap := v1.Group("config")
configMap.POST("/configMap/create", CreateConfigMap)
configMap.GET("/secret/list", ListSecret)
configMap.GET("/configMap/list", ListConfigMap)
// service
service := v1.Group("service")
service.POST("/create", CreateService)
service.PUT("/update", UpdateService)
service.DELETE("/delete/:clusterName/:namespace/:name/:label", DeleteService)
service.GET("/all", AllService)
service.GET("/list", ListService)
service.GET("/isExist", IsExistService)
service.GET("/detail", DetailService)
//PropagationPolicyTemplate
propagationPolicyTemplate := v1.Group("propagationPolicyTemplate")
@ -171,6 +235,11 @@ func InitRouter() *gin.Engine {
//Overview
overview := v1.Group("resource")
overview.GET("/count", ResourceCount)
overview.GET("/getApiServerMetrics", GetApiServerMetrics)
overview.GET("/getNodeMetrics", GetNodeMetrics)
overview.GET("/getClusterMetrics", GetClusterMetrics)
overview.GET("/getScheduleMetrics", GetScheduleMetrics)
overview.GET("/getOverallMetrics", GetOverallMetrics)
}

View File

@ -2,10 +2,13 @@ package app
import (
"context"
"encoding/json"
"github.com/gin-gonic/gin"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"net/http"
"sort"
"strings"
)
type ServiceParam struct {
@ -13,44 +16,21 @@ type ServiceParam struct {
TemplateId string `json:"templateId"`
ClusterName []string `json:"clusterName"`
}
type ServiceParam1 struct {
Service JSONData111 `json:"service"`
TemplateId string `json:"templateId"`
ClusterName []string `json:"clusterName"`
}
type JSONData111 struct {
APIVersion string `json:"apiVersion"`
Kind string `json:"kind"`
Metadata struct {
Namespace string `json:"namespace"`
Labels struct {
App string `json:"app"`
} `json:"labels"`
Name string `json:"name"`
Annotations struct {
KubesphereIoCreator string `json:"kubesphere.io/creator"`
} `json:"annotations"`
} `json:"metadata"`
Spec struct {
SessionAffinity string `json:"sessionAffinity"`
Selector struct {
Jcce string `json:"jcce"`
} `json:"selector"`
Ports []struct {
Name string `json:"name"`
Protocol string `json:"protocol"`
TargetPort int `json:"targetPort"`
Port int `json:"port"`
} `json:"ports"`
} `json:"spec"`
type ServiceObject struct {
Kind string `json:"kind"`
ApiVersion string `json:"apiVersion"`
Metadata string `json:"metadata"`
ResourceVersion string `json:"resourceVersion"`
Items []v1.Service `json:"items"`
}
// CreateService 创建服务
// @Summary 创建服务
// @Description 创建服务
// @Tags service
// @accept json
// @Produce json
// @Param param body ServiceParam1 true "json"
// @Success 200
// @Failure 500
// @Router /api/v1/service/create [post]
@ -60,15 +40,135 @@ func CreateService(c *gin.Context) {
Response(c, http.StatusBadRequest, "invalid request params.", "")
return
}
ClientSet.CoreV1().Services(sRequest.Service.Namespace).Create(context.TODO(), &sRequest.Service, metav1.CreateOptions{})
if sRequest.Service.Labels == nil {
sRequest.Service.Labels = map[string]string{}
}
sRequest.Service.Labels["jcce"] = "true"
_, serviceErr := ClientSet.CoreV1().Services(sRequest.Service.Namespace).Create(context.TODO(), &sRequest.Service, metav1.CreateOptions{})
if serviceErr != nil {
Response(c, http.StatusBadRequest, "create service error.", serviceErr)
return
}
// 创建调度策略实例
CreatePropagationPolicies(PropagationPolicy{
err := CreatePropagationPolicies(PropagationPolicy{
ClusterName: sRequest.ClusterName,
TemplateId: sRequest.TemplateId,
ResourceName: sRequest.Service.Name,
Name: "Service" + sRequest.Service.Namespace + sRequest.Service.Name,
Name: "service" + "." + sRequest.Service.Namespace + "." + sRequest.Service.Name,
Namespace: sRequest.Service.Namespace,
Kind: "Service",
})
if err != nil {
Response(c, http.StatusBadRequest, "create propagationPolicy error.", err)
return
}
Response(c, http.StatusOK, "success", nil)
}
// UpdateService 更新服务
func UpdateService(c *gin.Context) {
var sevice v1.Service
if err := c.BindJSON(&sevice); err != nil {
Response(c, http.StatusBadRequest, "invalid request params.", "")
return
}
ClientSet.CoreV1().Services(sevice.Namespace).Update(context.TODO(), &sevice, metav1.UpdateOptions{})
Response(c, http.StatusOK, "success", nil)
}
// DeleteService 删除服务
func DeleteService(c *gin.Context) {
clusterName := c.Param("clusterName")
namespace := c.Param("namespace")
name := c.Param("name")
label := c.Param("label")
if strings.EqualFold(label, "jcce") {
err := ClientSet.CoreV1().Services(namespace).Delete(context.TODO(), name, metav1.DeleteOptions{})
if err != nil {
Response(c, http.StatusInternalServerError, "delete service failed", err)
return
}
// 删除调度策略
DeletePropagationPolicies(namespace, "service"+"."+namespace+"."+name)
} else {
result := DeleteObject(detailServiceConst, clusterName, namespace, name)
if result.Error() != nil {
Response(c, http.StatusInternalServerError, "delete service failed", result.Error())
return
}
}
Response(c, http.StatusOK, "success", nil)
}
// IsExistService 判断输入service名称是否重复
func IsExistService(c *gin.Context) {
clusterName := c.Query("clusterName")
namespace := c.Query("namespace")
name := c.Query("name")
result := SearchObject(detailServiceConst, clusterName, namespace, name)
if result.Error() != nil {
Response(c, http.StatusOK, "success", false)
return
}
raw, _ := result.Raw()
var service v1.Service
json.Unmarshal(raw, &service)
if len(service.Name) == 0 {
Response(c, http.StatusOK, "success", false)
return
}
Response(c, http.StatusOK, "success", true)
}
// DetailService 查询service详情
func DetailService(c *gin.Context) {
clusterName := c.Query("clusterName")
namespace := c.Query("namespace")
name := c.Query("name")
result := SearchObject(detailServiceConst, clusterName, namespace, name)
if result.Error() != nil {
Response(c, http.StatusInternalServerError, "failed", result.Error())
return
}
raw, _ := result.Raw()
var service v1.Service
json.Unmarshal(raw, &service)
Response(c, http.StatusOK, "success", service)
}
// ListService 查询命名空间下的service列表
func ListService(c *gin.Context) {
clusterName := c.Query("clusterName")
namespace := c.Query("namespace")
result := SearchObject(serviceConst, clusterName, namespace, "")
if result.Error() != nil {
Response(c, http.StatusInternalServerError, "failed", result.Error())
return
}
raw, _ := result.Raw()
var scRes SCRes
json.Unmarshal(raw, &scRes)
Response(c, http.StatusOK, "success", scRes.Items)
}
// AllService 查询service列表
func AllService(c *gin.Context) {
clusterName := c.Query("clusterName")
pageNum := c.Query("pageNum")
pageSize := c.Query("pageSize")
result := SearchObject(allServiceConst, clusterName, "", "")
if result.Error() != nil {
Response(c, http.StatusInternalServerError, "failed", result.Error())
return
}
raw, _ := result.Raw()
var serviceRes ServiceObject
json.Unmarshal(raw, &serviceRes)
page := &Page[v1.Service]{}
page.List = serviceRes.Items
sort.SliceStable(serviceRes.Items, func(i, j int) bool {
return serviceRes.Items[i].CreationTimestamp.Time.After(serviceRes.Items[j].CreationTimestamp.Time)
})
data := Paginator(page, int64(len(serviceRes.Items)), pageNum, pageSize)
Response(c, http.StatusOK, "success", data)
}

67
app/sphere.go Normal file
View File

@ -0,0 +1,67 @@
package app
import (
"github.com/gin-gonic/gin"
"net/http"
"strings"
"sync"
)
const (
cpu_avg_usage = "avg_over_time(sum by (cluster) (node:node_num_cpu:sum{cluster_name='clusterName',prometheus_replica='prometheus-k8s-0'} * node:node_cpu_utilisation:avg1m{cluster_name='clusterName',prometheus_replica='prometheus-k8s-0'})[7d])"
mem_avg_usage = "avg_over_time(sum by (cluster) (node:node_memory_bytes_total:sum{cluster_name='clusterName',prometheus_replica='prometheus-k8s-0'} - node:node_memory_bytes_available:sum{cluster_name='clusterName',prometheus_replica='prometheus-k8s-0'})[7d])"
cpu_total_usage = "round(:node_cpu_utilisation:avg1m{cluster_name='clusterName'} * sum(node:node_num_cpu:sum{cluster_name='clusterName'}), 0.001) "
mem_total_usage = "sum(node:node_memory_bytes_total:sum{cluster_name='clusterName',prometheus_replica='prometheus-k8s-0'}) - sum(node:node_memory_bytes_available:sum{cluster_name='clusterName',prometheus_replica='prometheus-k8s-0'})"
clusters_test = "host,member-01,member-02,member-05"
//clusters_test = "host,member-01,member-02,member-04-ali,member-05,zhijiang-gpu7,zhijiang-gpu8,zhijiang-gpu9"
clusters_prod = "host,fedjcce-fx001,fedjcce-zj002,fedjcce-zj003,fedjcce-zj004,fedjcce-zj005,fedjcce-zj006,zhijiang-gpu5,zhijiang-hw2,zhijiang-gpu4,member-04-ali-zj"
metric_range_7d = "168h"
steps_7d = 90000
)
// @Summary 获取大球监控数据
// @Description 获取大球监控数据
// @Tags namespace
// @accept json
// @Produce json
// @Success 200
// @Failure 400
// @Router /api/v1/sphere/getOverallMetrics [get]
func GetOverallMetrics(c *gin.Context) {
imap := make(map[string]string)
clusters := strings.Split(clusters_test, ",")
for _, cluster := range clusters {
replaceMap := map[string]string{
ClusterName: cluster,
}
imap["cpu_avg_usage"] += replacePromql(cpu_avg_usage, replaceMap, ClusterName) + "+"
imap["mem_avg_usage"] += replacePromql(mem_avg_usage, replaceMap, ClusterName) + "+"
imap["cpu_total_usage"] += replacePromql(cpu_total_usage, replaceMap, ClusterName) + "+"
imap["mem_total_usage"] += replacePromql(mem_total_usage, replaceMap, ClusterName) + "+"
}
metricMap := map[string][]MetricUrl{
"cpu_avg_usage": {{ClusterName, "", GetMetricUrl(strings.TrimRight(imap["cpu_avg_usage"], "+"), nil, "", metric_range_7d, steps_7d)}},
"mem_avg_usage": {{ClusterName, "", GetMetricUrl(strings.TrimRight(imap["mem_avg_usage"], "+"), nil, "", metric_range_7d, steps_7d)}},
"cpu_total_usage": {{ClusterName, "", GetMetricUrl(strings.TrimRight(imap["cpu_total_usage"], "+"), nil, "", metric_range_7d, steps_7d)}},
"mem_total_usage": {{ClusterName, "", GetMetricUrl(strings.TrimRight(imap["mem_total_usage"], "+"), nil, "", metric_range_7d, steps_7d)}},
}
ch := make(chan MetricResult, len(metricMap))
var wg sync.WaitGroup
for k, v := range metricMap {
wg.Add(1)
go HttpGetMetrics(k, v, &wg, ch)
}
wg.Wait()
close(ch)
mr := []MetricResult{}
for v := range ch {
mr = append(mr, v)
}
Response(c, http.StatusOK, "success", mr)
}

View File

@ -5,8 +5,12 @@ import (
"encoding/json"
"github.com/gin-gonic/gin"
v1 "k8s.io/api/core/v1"
"k8s.io/api/storage/v1beta1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"net/http"
"reflect"
"sort"
"strings"
)
type PVRes struct {
@ -17,7 +21,7 @@ type PVRes struct {
Items []v1.PersistentVolume `json:"items"`
}
type PVCRes struct {
type PVCObject struct {
Kind string `json:"kind"`
ApiVersion string `json:"apiVersion"`
Metadata string `json:"metadata"`
@ -25,6 +29,14 @@ type PVCRes struct {
Items []v1.PersistentVolumeClaim `json:"items"`
}
type SCRes struct {
Kind string `json:"kind"`
ApiVersion string `json:"apiVersion"`
Metadata string `json:"metadata"`
ResourceVersion string `json:"resourceVersion"`
Items []v1beta1.StorageClass `json:"items"`
}
type PersistentVolume struct {
TemplateId string `json:"templateId"`
ClusterName []string `json:"clusterName"`
@ -85,6 +97,7 @@ type PersistentVolumeClaim struct {
PersistentVolumeClaim v1.PersistentVolumeClaim `json:"persistentVolumeClaim"`
}
// CreatePV 创建PV
type PersistentVolumeClaim1 struct {
TemplateId string `json:"templateId"`
ClusterName []string `json:"clusterName"`
@ -116,12 +129,102 @@ func CreatePV(c *gin.Context) {
ClusterName: pvRequest.ClusterName,
TemplateId: pvRequest.TemplateId,
ResourceName: pvRequest.PersistentVolume.Name,
Name: "PersistentVolume" + pvRequest.PersistentVolume.Name,
Name: "persistentVolume" + pvRequest.PersistentVolume.Name,
Kind: "PersistentVolume",
})
Response(c, http.StatusOK, "success", persistentVolume)
}
// IsExistPVC 查询pvc是否存在
func IsExistPVC(c *gin.Context) {
clusterName := c.Query("clusterName")
namespace := c.Query("namespace")
name := c.Query("name")
result := SearchObject(detailPvcConst, clusterName, namespace, name)
if result.Error() != nil {
Response(c, http.StatusOK, "success", false)
return
}
raw, _ := result.Raw()
var pvc v1.PersistentVolumeClaim
json.Unmarshal(raw, &pvc)
if len(pvc.Name) == 0 {
Response(c, http.StatusOK, "success", false)
return
}
Response(c, http.StatusOK, "success", true)
}
// DetailPVC 查询PVC详情
func DetailPVC(c *gin.Context) {
clusterName := c.Query("clusterName")
namespace := c.Query("namespace")
name := c.Query("name")
result := SearchObject(detailPvcConst, clusterName, namespace, name)
if result.Error() != nil {
Response(c, http.StatusInternalServerError, "failed", result.Error())
return
}
raw, _ := result.Raw()
var pvc v1.PersistentVolumeClaim
json.Unmarshal(raw, &pvc)
err_ := AddTypeMetaToObject(&pvc)
if err_ != nil {
Response(c, http.StatusInternalServerError, "failed", result.Error())
}
Response(c, http.StatusOK, "success", pvc)
}
// DeletePVC 删除存储卷
func DeletePVC(c *gin.Context) {
clusterName := c.Param("clusterName")
namespace := c.Param("namespace")
name := c.Param("name")
label := c.Param("label")
if strings.EqualFold(label, "jcce") {
err := ClientSet.CoreV1().PersistentVolumeClaims(namespace).Delete(context.TODO(), name, metav1.DeleteOptions{})
if err != nil {
Response(c, http.StatusInternalServerError, "delete persistentVolumeClaim failed", err)
return
}
// 删除调度策略实例
DeletePropagationPolicies(namespace, "PersistentVolumeClaim"+"."+name)
} else {
result := DeleteObject(detailPvcConst, clusterName, namespace, name)
if result.Error() != nil {
Response(c, http.StatusInternalServerError, "delete persistentVolumeClaim failed", result.Error())
return
}
}
Response(c, http.StatusOK, "success", "")
}
// UpdatePVC 更新存储卷信息
func UpdatePVC(c *gin.Context) {
clusterName := c.Query("clusterName")
var pvc v1.PersistentVolumeClaim
if err := c.BindJSON(&pvc); err != nil {
Response(c, http.StatusBadRequest, "invalid request params.", "")
return
}
if len(pvc.Labels["jcce"]) != 0 {
_, err := ClientSet.CoreV1().PersistentVolumeClaims(pvc.Namespace).Update(context.TODO(), &pvc, metav1.UpdateOptions{})
if err != nil {
Response(c, http.StatusInternalServerError, "update persistentVolumeClaim failed", err)
return
}
} else {
result := UpdateObject(detailPvcConst, clusterName, pvc.Namespace, pvc.Name, pvc)
if result.Error() != nil {
Response(c, http.StatusInternalServerError, "update persistentVolumeClaim failed", result.Error())
return
}
}
Response(c, http.StatusOK, "success", "")
}
// @Summary 创建PVC
// @Description 创建PVC
// @Tags storage
@ -137,9 +240,13 @@ func CreatePVC(c *gin.Context) {
Response(c, http.StatusBadRequest, "invalid request params.", "")
return
}
if pvcRequest.PersistentVolumeClaim.Labels == nil {
pvcRequest.PersistentVolumeClaim.Labels = map[string]string{}
}
pvcRequest.PersistentVolumeClaim.Labels["jcce"] = "true"
persistentVolume, err := ClientSet.CoreV1().PersistentVolumeClaims(pvcRequest.PersistentVolumeClaim.Namespace).Create(context.TODO(), &pvcRequest.PersistentVolumeClaim, metav1.CreateOptions{})
if err != nil {
Response(c, http.StatusInternalServerError, "create persistentVolume failed", err)
Response(c, http.StatusInternalServerError, "Create PersistentVolumeClaim Failed", err)
return
}
// 创建调度策略实例
@ -147,7 +254,7 @@ func CreatePVC(c *gin.Context) {
ClusterName: pvcRequest.ClusterName,
TemplateId: pvcRequest.TemplateId,
ResourceName: pvcRequest.PersistentVolumeClaim.Name,
Name: "PersistentVolumeClaim" + pvcRequest.PersistentVolumeClaim.Namespace + pvcRequest.PersistentVolumeClaim.Name,
Name: "persistentVolumeClaim" + "." + pvcRequest.PersistentVolumeClaim.Namespace + "." + pvcRequest.PersistentVolumeClaim.Name,
Namespace: pvcRequest.PersistentVolumeClaim.Namespace,
Kind: "PersistentVolumeClaim",
})
@ -165,7 +272,7 @@ func CreatePVC(c *gin.Context) {
// @Failure 500
// @Router /api/v1/storage/pv/{clusterName} [get]
func ListPV(c *gin.Context) {
clusterName := c.Param("clusterName")
clusterName := c.Query("clusterName")
result := SearchObject(pvConst, clusterName, "", "")
if result.Error() != nil {
Response(c, http.StatusInternalServerError, "failed", result.Error())
@ -187,17 +294,86 @@ func ListPV(c *gin.Context) {
// @Param namespace path string true "命名空间"
// @Success 200
// @Failure 500
// @Router /api/v1/storage/pvc/{clusterName}/{namespace} [get]
// @Router /api/v1/storage/pvc [get]
func ListPVC(c *gin.Context) {
clusterName := c.Param("clusterName")
namespace := c.Param("namespace")
result := SearchObject(pvcConst, clusterName, namespace, "")
clusterName := c.Query("clusterName")
pageNum := c.Query("pageNum")
pageSize := c.Query("pageSize")
name := c.Query("name")
status := c.Query("status")
result := SearchObject(pvcConst, clusterName, "", "")
if result.Error() != nil {
Response(c, http.StatusInternalServerError, "failed", result.Error())
return
}
raw, _ := result.Raw()
var pvcRes PVCRes
json.Unmarshal(raw, &pvcRes)
Response(c, http.StatusOK, "success", pvcRes.Items)
var pvcResult PVCObject
json.Unmarshal(raw, &pvcResult)
if len(name) != 0 {
count := 0
for i := range pvcResult.Items {
if !strings.Contains(pvcResult.Items[i-count].Name, name) {
pvcResult.Items = append(pvcResult.Items[:i-count], pvcResult.Items[i-count+1:]...)
count = count + 1
}
}
}
if len(status) != 0 {
count := 0
for i := range pvcResult.Items {
if !strings.EqualFold(reflect.ValueOf(pvcResult.Items[i-count].Status.Phase).String(), status) {
pvcResult.Items = append(pvcResult.Items[:i-count], pvcResult.Items[i-count+1:]...)
count = count + 1
}
}
}
if len(pvcResult.Items) == 0 {
Response(c, http.StatusOK, "success", pvcResult.Items)
return
}
page := &Page[v1.PersistentVolumeClaim]{}
page.List = pvcResult.Items
sort.SliceStable(pvcResult.Items, func(i, j int) bool {
return page.List[i].CreationTimestamp.Time.After(page.List[j].CreationTimestamp.Time)
})
data := Paginator(page, int64(len(page.List)), pageNum, pageSize)
// 查询是否有pod挂载到当前pvc下
podResult := SearchObject(allPodConst, clusterName, "", "")
if podResult.Error() != nil {
Response(c, http.StatusInternalServerError, "failed", podResult.Error())
return
}
var podRes PodObject
podRaw, _ := podResult.Raw()
json.Unmarshal(podRaw, &podRes)
for _, pvc := range data.List {
for _, pod := range podRes.Items {
for _, podPvc := range pod.Spec.Volumes {
if podPvc.PersistentVolumeClaim != nil && pvc.Annotations != nil && podPvc.PersistentVolumeClaim.ClaimName == pvc.Name {
pvc.Annotations["in-use"] = "true"
}
}
}
}
Response(c, http.StatusOK, "success", data)
}
// ListStorageClass 查询StorageClass名称列表
func ListStorageClass(c *gin.Context) {
clusterName := c.Query("clusterName")
scResult := SearchObject(scConst, clusterName, "", "")
if scResult.Error() != nil {
Response(c, http.StatusInternalServerError, "failed", scResult.Error())
return
}
raw, _ := scResult.Raw()
var scRes SCRes
json.Unmarshal(raw, &scRes)
// 遍历获取名称集合
var result []string
for i := range scRes.Items {
result = append(result, scRes.Items[i].Name)
}
Response(c, http.StatusOK, "success", result)
}

View File

@ -48,3 +48,12 @@ func (c Cli) Run(shell string) (string, error) {
c.LastResult = string(buf)
return c.LastResult, err
}
func stringInclude(items []string, item string) bool {
for _, eachItem := range items {
if eachItem == item {
return true
}
}
return false
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -41,100 +41,6 @@ definitions:
version:
type: string
type: object
app.DeploymentParamSwagger:
properties:
clusterName:
items:
type: string
type: array
deployment:
properties:
apiVersion:
type: string
kind:
type: string
metadata:
properties:
annotations:
properties:
kubesphere.io/creator:
type: string
type: object
labels:
type: object
name:
type: string
namespace:
type: string
type: object
spec:
properties:
replicas:
type: integer
selector:
properties:
matchLabels:
type: object
type: object
strategy:
properties:
rollingUpdate:
properties:
maxSurge:
type: string
maxUnavailable:
type: string
type: object
type:
type: string
type: object
template:
properties:
metadata:
properties:
labels:
type: object
type: object
spec:
properties:
containers:
items:
properties:
image:
type: string
imagePullPolicy:
type: string
name:
type: string
ports:
items:
properties:
containerPort:
type: integer
name:
type: string
protocol:
type: string
type: object
type: array
type: object
type: array
imagePullSecrets: {}
initContainers:
items: {}
type: array
serviceAccount:
type: string
volumes:
items: {}
type: array
type: object
type: object
type: object
type: object
templateId:
type: string
type: object
app.Domain:
properties:
clusters:
@ -172,6 +78,23 @@ definitions:
memory_rate:
type: number
type: object
app.HPAParam:
properties:
HPAName:
type: string
clusterName:
type: string
cpuTargetUtilization:
type: string
maxReplicas:
type: integer
memoryTargetValue:
type: string
minReplicas:
type: integer
namespace:
type: string
type: object
app.JSONData:
properties:
apiVersion:
@ -243,53 +166,6 @@ definitions:
type: string
type: object
type: object
app.JSONData111:
properties:
apiVersion:
type: string
kind:
type: string
metadata:
properties:
annotations:
properties:
kubesphere.io/creator:
type: string
type: object
labels:
properties:
app:
type: string
type: object
name:
type: string
namespace:
type: string
type: object
spec:
properties:
ports:
items:
properties:
name:
type: string
port:
type: integer
protocol:
type: string
targetPort:
type: integer
type: object
type: array
selector:
properties:
jcce:
type: string
type: object
sessionAffinity:
type: string
type: object
type: object
app.Label:
properties:
create_time:
@ -344,6 +220,8 @@ definitions:
type: integer
state:
type: string
templateId:
type: string
type: object
app.OverridePolicy:
properties:
@ -411,9 +289,9 @@ definitions:
node:
type: string
page_num:
type: integer
type: string
page_size:
type: integer
type: string
ready:
type: string
restarts:
@ -449,15 +327,17 @@ definitions:
memberClusterIp:
type: string
type: object
app.ServiceParam1:
app.RedeployParam:
properties:
clusterName:
items:
type: string
type: array
service:
$ref: '#/definitions/app.JSONData111'
templateId:
type: string
deploymentName:
type: string
namespace:
type: string
num:
type: string
type:
type: string
type: object
info:
@ -777,18 +657,33 @@ paths:
summary: 集群删除标签
tags:
- cluster
/api/v1/deployment/create:
/api/v1/deployment/autoScaling:
post:
consumes:
- application/json
description: 创建工作负载
description: 弹性伸缩
parameters:
- description: json
in: body
name: param
required: true
schema:
$ref: '#/definitions/app.DeploymentParamSwagger'
$ref: '#/definitions/app.HPAParam'
produces:
- application/json
responses:
"200":
description: OK
"400":
description: Bad Request
summary: 弹性伸缩
tags:
- deployment
/api/v1/deployment/create:
post:
consumes:
- application/json
description: 创建工作负载
produces:
- application/json
responses:
@ -825,6 +720,28 @@ paths:
summary: 删除工作负载
tags:
- deployment
/api/v1/deployment/deployments/redeploy:
patch:
consumes:
- application/json
description: 重新部署
parameters:
- description: json
in: body
name: param
required: true
schema:
$ref: '#/definitions/app.RedeployParam'
produces:
- application/json
responses:
"200":
description: OK
"500":
description: Internal Server Error
summary: 重新部署
tags:
- deployment
/api/v1/deployment/describe:
get:
consumes:
@ -850,6 +767,73 @@ paths:
summary: 查询工作负载列表(所有集群)
tags:
- deployment
/api/v1/deployment/getMetrics:
get:
consumes:
- application/json
description: 获取部署监控
parameters:
- description: 集群名称
in: query
name: clusterName
required: true
type: string
- description: namespace
in: query
name: namespace
required: true
type: string
- description: 部署名称
in: query
name: deployment
required: true
type: string
- description: 类型
in: query
name: queryType
required: true
type: string
produces:
- application/json
responses:
"200":
description: OK
"500":
description: Internal Server Error
summary: 获取部署监控
tags:
- deployment
/api/v1/deployment/hpa:
get:
consumes:
- application/json
description: 获取弹性伸缩信息
parameters:
- description: 集群名称
in: query
name: clusterName
required: true
type: string
- description: 命名空间
in: query
name: namespace
required: true
type: string
- description: deployName
in: query
name: deployName
required: true
type: string
produces:
- application/json
responses:
"200":
description: OK
"400":
description: Bad Request
summary: 获取弹性伸缩信息
tags:
- deployment
/api/v1/deployment/list:
get:
consumes:
@ -1210,6 +1194,58 @@ paths:
summary: 查询Namespace详情
tags:
- namespace
/api/v1/namespace/getBatchMetrics:
get:
consumes:
- application/json
description: 批量获取namespace监控
parameters:
- description: 集群名
in: query
name: clusterName
required: true
type: string
- description: 逗号分隔多个命名空间名称
in: query
name: namespaces
required: true
type: string
produces:
- application/json
responses:
"200":
description: OK
"400":
description: Bad Request
summary: 批量获取namespace监控
tags:
- namespace
/api/v1/namespace/getMetrics:
get:
consumes:
- application/json
description: namespace监控
parameters:
- description: 集群名
in: query
name: clusterName
required: true
type: string
- description: 命名空间名称
in: query
name: namespace
required: true
type: string
produces:
- application/json
responses:
"200":
description: OK
"400":
description: Bad Request
summary: namespace监控
tags:
- namespace
/api/v1/namespace/list:
get:
consumes:
@ -1310,6 +1346,58 @@ paths:
summary: 查询边缘节点列表
tags:
- node
/api/v1/node/getNodeMetrics1h:
get:
consumes:
- application/json
description: 获取集群节点1h监控
parameters:
- description: 集群名称
in: query
name: clusterName
required: true
type: string
- description: 节点名称
in: query
name: nodeName
required: true
type: string
produces:
- application/json
responses:
"200":
description: OK
"400":
description: Bad Request
summary: 获取集群节点1h监控
tags:
- node
/api/v1/node/getNodeMetrics8h:
get:
consumes:
- application/json
description: 获取集群节点8h监控
parameters:
- description: 集群名称
in: query
name: clusterName
required: true
type: string
- description: 节点名称
in: query
name: nodeName
required: true
type: string
produces:
- application/json
responses:
"200":
description: OK
"400":
description: Bad Request
summary: 获取集群节点8h监控
tags:
- node
/api/v1/node/list/{clusterName}:
get:
consumes:
@ -1374,6 +1462,121 @@ paths:
summary: 查询重写策略列表
tags:
- overridePolicy
/api/v1/overview/getApiServerMetrics:
get:
consumes:
- application/json
description: 获取ApiServer请求数和请求延迟
parameters:
- description: 集群名称
in: query
name: clusterName
required: true
type: string
produces:
- application/json
responses:
"200":
description: OK
"400":
description: Bad Request
summary: 获取ApiServer请求数和请求延迟
tags:
- overview
/api/v1/overview/getClusterMetrics:
get:
consumes:
- application/json
description: 获取容器集群资源监控
parameters:
- description: 集群名称
in: query
name: clusterName
required: true
type: string
produces:
- application/json
responses:
"200":
description: OK
"400":
description: Bad Request
summary: 获取容器集群资源监控
tags:
- overview
/api/v1/overview/getNodeMetrics:
get:
consumes:
- application/json
description: 获取容器节点资源监控
parameters:
- description: 集群名称
in: query
name: clusterName
required: true
type: string
produces:
- application/json
responses:
"200":
description: OK
"400":
description: Bad Request
summary: 获取容器节点资源监控
tags:
- overview
/api/v1/overview/getScheduleMetrics:
get:
consumes:
- application/json
description: 获取容器集群调度器监控
parameters:
- description: 集群名称
in: query
name: clusterName
required: true
type: string
produces:
- application/json
responses:
"200":
description: OK
"400":
description: Bad Request
summary: 获取容器集群调度器监控
tags:
- overview
/api/v1/pod/all:
get:
consumes:
- application/json
description: 根据指定集群查询Pod列表
parameters:
- description: 集群名称
in: query
name: clusterName
required: true
type: string
- description: pageNum
in: query
name: pageNum
required: true
type: integer
- description: pageSize
in: query
name: pageSize
required: true
type: integer
produces:
- application/json
responses:
"200":
description: OK
"500":
description: Internal Server Error
summary: 根据指定集群查询Pod列表
tags:
- pod
/api/v1/pod/create:
post:
consumes:
@ -1480,13 +1683,6 @@ paths:
consumes:
- application/json
description: 根据指定集群查询Pod列表
parameters:
- description: json
in: body
name: param
required: true
schema:
$ref: '#/definitions/app.Pod'
produces:
- application/json
responses:
@ -1497,6 +1693,32 @@ paths:
summary: 根据指定集群查询Pod列表
tags:
- pod
/api/v1/pod/metrics:
get:
consumes:
- application/json
description: 获取容器组监控
parameters:
- description: 集群名称
in: query
name: clusterName
required: true
type: string
- description: 容器组名称
in: query
name: podName
required: true
type: string
produces:
- application/json
responses:
"200":
description: OK
"400":
description: Bad Request
summary: 获取容器组监控
tags:
- pod
/api/v1/pod/metrics/{clusterName}/{namespace}/{name}:
get:
consumes:
@ -1689,13 +1911,6 @@ paths:
consumes:
- application/json
description: 创建服务
parameters:
- description: json
in: body
name: param
required: true
schema:
$ref: '#/definitions/app.ServiceParam1'
produces:
- application/json
responses:
@ -1706,6 +1921,21 @@ paths:
summary: 创建服务
tags:
- service
/api/v1/sphere/getOverallMetrics:
get:
consumes:
- application/json
description: 获取大球监控数据
produces:
- application/json
responses:
"200":
description: OK
"400":
description: Bad Request
summary: 获取大球监控数据
tags:
- namespace
/api/v1/storage/pv:
post:
consumes:
@ -1750,28 +1980,6 @@ paths:
tags:
- storage
/api/v1/storage/pvc:
post:
consumes:
- application/json
description: 创建PVC
parameters:
- description: json
in: body
name: param
required: true
schema:
$ref: '#/definitions/app.PersistentVolumeClaim1'
produces:
- application/json
responses:
"200":
description: OK
"500":
description: Internal Server Error
summary: 创建PVC
tags:
- storage
/api/v1/storage/pvc/{clusterName}/{namespace}:
get:
consumes:
- application/json
@ -1797,4 +2005,25 @@ paths:
summary: 查询PVC列表
tags:
- storage
post:
consumes:
- application/json
description: 创建PVC
parameters:
- description: json
in: body
name: param
required: true
schema:
$ref: '#/definitions/app.PersistentVolumeClaim1'
produces:
- application/json
responses:
"200":
description: OK
"500":
description: Internal Server Error
summary: 创建PVC
tags:
- storage
swagger: "2.0"

View File

@ -1,8 +1,6 @@
package main
import (
"jcc-schedule/app"
)
import "jcc-schedule/app"
// @title jcc调度中心
// @version 1.0