package service import ( "context" "encoding/json" "errors" "github.com/wonderivan/logger" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/intstr" "strconv" "time" ) var Deployment deployment type deployment struct{} type DeploymentsResp struct { Items []appsv1.Deployment `json:"items"` Total int `json:"total"` } type DeployCreate struct { Name string `json:"name"` Namespace string `json:"namespace"` Replicas int32 `json:"replicas"` Image string `json:"image"` Label map[string]string `json:"label"` Cpu string `json:"cpu"` Memory string `json:"memory"` ContainerPort int32 `json:"container_port"` HealthCheck bool `json:"health_check"` HealthPath string `json:"health_path"` } type DeploysNp struct { Namespace string `json:"namespace"` DeployNum int `json:"deployment_num"` } func (d *deployment) GetDeployments(filterName, namespace string, limit, page int) (deploymentsResp *DeploymentsResp, err error) { deploymentList, err := K8s.ClientSet.AppsV1().Deployments(namespace).List(context.TODO(), metav1.ListOptions{}) if err != nil { logger.Error(errors.New("获取Deployment列表失败, " + err.Error())) return nil, errors.New("获取Deployment列表失败, " + err.Error()) } selectableData := &dataSelector{ GenericDataList: d.toCells(deploymentList.Items), DataSelect: &DataSelectQuery{ Filter: &FilterQuery{Name: filterName}, Paginate: &PaginateQuery{ Limit: limit, Page: page, }, }, } filtered := selectableData.Filter() total := len(filtered.GenericDataList) data := filtered.Sort().Paginate() deployments := d.fromCells(data.GenericDataList) return &DeploymentsResp{ Items: deployments, Total: total, }, nil } func (d *deployment) GetDeploymentDetail(deploymentName, namespace string) (deployment *appsv1.Deployment, err error) { deployment, err = K8s.ClientSet.AppsV1().Deployments(namespace).Get(context.TODO(), deploymentName, metav1.GetOptions{}) if err != nil { logger.Error(errors.New("获取Deployment详情失败, " + err.Error())) return nil, errors.New("获取Deployment详情失败, " + err.Error()) } return deployment, nil } func (d *deployment) ScaleDeployment(deploymentName, namespace string, scaleNum int) (replica int32, err error) { scale, err := K8s.ClientSet.AppsV1().Deployments(namespace).GetScale(context.TODO(), deploymentName, metav1.GetOptions{}) if err != nil { logger.Error(errors.New("获取Deployment副本数信息失败, " + err.Error())) return 0, errors.New("获取Deployment副本数信息失败, " + err.Error()) } scale.Spec.Replicas = int32(scaleNum) newScale, err := K8s.ClientSet.AppsV1().Deployments(namespace).UpdateScale(context.TODO(), deploymentName, scale, metav1.UpdateOptions{}) if err != nil { logger.Error(errors.New("更新Deployment副本数信息失败, " + err.Error())) return 0, errors.New("更新Deployment副本数信息失败, " + err.Error()) } return newScale.Spec.Replicas, nil } func (d *deployment) CreateDeployment(data *DeployCreate) (err error) { deployment := &appsv1.Deployment{ ObjectMeta: metav1.ObjectMeta{ Name: data.Name, Namespace: data.Namespace, Labels: data.Label, }, Spec: appsv1.DeploymentSpec{ Replicas: &data.Replicas, Selector: &metav1.LabelSelector{ MatchLabels: data.Label, }, Template: corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ Name: data.Name, Labels: data.Label, }, Spec: corev1.PodSpec{ Containers: []corev1.Container{ { Name: data.Name, Image: data.Image, Ports: []corev1.ContainerPort{ { Name: "http", Protocol: corev1.ProtocolTCP, ContainerPort: data.ContainerPort, }, }, }, }, }, }, }, Status: appsv1.DeploymentStatus{}, } if data.HealthCheck { deployment.Spec.Template.Spec.Containers[0].ReadinessProbe = &corev1.Probe{ ProbeHandler: corev1.ProbeHandler{ HTTPGet: &corev1.HTTPGetAction{ Path: data.HealthPath, Port: intstr.IntOrString{ Type: 0, IntVal: data.ContainerPort, }, }, }, InitialDelaySeconds: 5, TimeoutSeconds: 5, PeriodSeconds: 5, } deployment.Spec.Template.Spec.Containers[0].LivenessProbe = &corev1.Probe{ ProbeHandler: corev1.ProbeHandler{ HTTPGet: &corev1.HTTPGetAction{ Path: data.HealthPath, Port: intstr.IntOrString{ Type: 0, IntVal: data.ContainerPort, }, }, }, InitialDelaySeconds: 15, TimeoutSeconds: 5, PeriodSeconds: 5, } } deployment.Spec.Template.Spec.Containers[0].Resources.Limits = map[corev1.ResourceName]resource.Quantity{ corev1.ResourceCPU: resource.MustParse(data.Cpu), corev1.ResourceMemory: resource.MustParse(data.Memory), } deployment.Spec.Template.Spec.Containers[0].Resources.Requests = map[corev1.ResourceName]resource.Quantity{ corev1.ResourceCPU: resource.MustParse(data.Cpu), corev1.ResourceMemory: resource.MustParse(data.Memory), } _, err = K8s.ClientSet.AppsV1().Deployments(data.Namespace). Create(context.TODO(), deployment, metav1.CreateOptions{}) if err != nil { logger.Error(errors.New("创建Deployment失败, " + err.Error())) return errors.New("创建Deployment失败, " + err.Error()) } return nil } func (d *deployment) DeleteDeployment(deploymentName, namespace string) (err error) { err = K8s.ClientSet.AppsV1().Deployments(namespace).Delete(context.TODO(), deploymentName, metav1.DeleteOptions{}) if err != nil { logger.Error(errors.New("删除Deployment失败, " + err.Error())) return errors.New("删除Deployment失败, " + err.Error()) } return nil } func (d *deployment) RestartDeployment(deploymentName, namespace string) (err error) { patchData := map[string]interface{}{ "spec": map[string]interface{}{ "template": map[string]interface{}{ "spec": map[string]interface{}{ "containers": []map[string]interface{}{ {"name": deploymentName, "env": []map[string]string{{ "name": "RESTART_", "value": strconv.FormatInt(time.Now().Unix(), 10), }}, }, }, }, }, }, } patchByte, err := json.Marshal(patchData) if err != nil { logger.Error(errors.New("json序列化失败, " + err.Error())) return errors.New("json序列化失败, " + err.Error()) } _, err = K8s.ClientSet.AppsV1().Deployments(namespace).Patch(context.TODO(), deploymentName, "application/strategic-merge-patch+json", patchByte, metav1.PatchOptions{}) if err != nil { logger.Error(errors.New("重启Deployment失败, " + err.Error())) return errors.New("重启Deployment失败, " + err.Error()) } return nil } func (d *deployment) UpdateDeployment(namespace, content string) (err error) { var deploy = &appsv1.Deployment{} err = json.Unmarshal([]byte(content), deploy) if err != nil { logger.Error(errors.New("反序列化失败, " + err.Error())) return errors.New("反序列化失败, " + err.Error()) } _, err = K8s.ClientSet.AppsV1().Deployments(namespace).Update(context.TODO(), deploy, metav1.UpdateOptions{}) if err != nil { logger.Error(errors.New("更新Deployment失败, " + err.Error())) return errors.New("更新Deployment失败, " + err.Error()) } return nil } func (d *deployment) GetDeployNumPerNp() (deploysNps []*DeploysNp, err error) { namespaceList, err := K8s.ClientSet.CoreV1().Namespaces().List(context.TODO(), metav1.ListOptions{}) if err != nil { return nil, err } for _, namespace := range namespaceList.Items { deploymentList, err := K8s.ClientSet.AppsV1().Deployments(namespace.Name).List(context.TODO(), metav1.ListOptions{}) if err != nil { return nil, err } deploysNp := &DeploysNp{ Namespace: namespace.Name, DeployNum: len(deploymentList.Items), } deploysNps = append(deploysNps, deploysNp) } return deploysNps, nil } func (d *deployment) toCells(deployments []appsv1.Deployment) []DataCell { cells := make([]DataCell, len(deployments)) for i := range deployments { cells[i] = deploymentCell(deployments[i]) } return cells } func (d *deployment) fromCells(cells []DataCell) []appsv1.Deployment { deployments := make([]appsv1.Deployment, len(cells)) for i := range cells { deployments[i] = appsv1.Deployment(cells[i].(deploymentCell)) } return deployments }