Files
PandaX/apps/devops/services/k8s/statefulset/statefulset.go
2022-01-26 14:13:23 +08:00

237 lines
8.2 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package statefulset
import (
"context"
"fmt"
"pandax/base/global"
"go.uber.org/zap"
apps "k8s.io/api/apps/v1"
autoscalingv1 "k8s.io/api/autoscaling/v1"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/kubernetes"
"pandax/apps/devops/entity/k8s"
k8scommon "pandax/apps/devops/services/k8s/common"
"pandax/apps/devops/services/k8s/dataselect"
"pandax/apps/devops/services/k8s/event"
"time"
)
// StatefulSetList contains a list of Stateful Sets in the cluster.
type StatefulSetList struct {
ListMeta k8s.ListMeta `json:"listMeta"`
Status k8scommon.ResourceStatus `json:"status"`
StatefulSets []StatefulSet `json:"statefulSets"`
}
// StatusInfo is the status information of the statefulSet
type StatusInfo struct {
// replicas is the number of Pods created by the StatefulSet controller.
Replicas int32 `json:"replicas"`
// Number of non-terminated pods that have the desired template spec
Updated int32 `json:"updated"`
// readyReplicas is the number of Pods created by the StatefulSet controller that have a Ready Condition.
ReadyReplicas int32 `json:"readyReplicas,omitempty"`
// currentReplicas is the number of Pods created by the StatefulSet controller from the StatefulSet version
// indicated by currentRevision.
CurrentReplicas int32 `json:"currentReplicas,omitempty"`
// updatedReplicas is the number of Pods created by the StatefulSet controller from the StatefulSet version
// indicated by updateRevision.
UpdatedReplicas int32 `json:"updatedReplicas,omitempty"`
// Total number of available pods (ready for at least minReadySeconds) targeted by this statefulset.
// This is an alpha field and requires enabling StatefulSetMinReadySeconds feature gate.
// Remove omitempty when graduating to beta
// +optional
AvailableReplicas int32 `json:"availableReplicas,omitempty"`
}
// StatefulSet is a presentation layer view of Kubernetes Stateful Set resource.
type StatefulSet struct {
ObjectMeta k8s.ObjectMeta `json:"objectMeta"`
TypeMeta k8s.TypeMeta `json:"typeMeta"`
Pods k8scommon.PodInfo `json:"podInfo"`
// Status information on the statefulSet
StatusInfo `json:"statusInfo"`
// Label selector
Selector *metav1.LabelSelector `json:"selector"`
// The statefulset strategy to use to replace existing pods with new ones.
// Valid options: Recreate, RollingUpdate
Strategy apps.StatefulSetUpdateStrategy `json:"strategy"`
ContainerImages []string `json:"containerImages"`
InitContainerImages []string `json:"initContainerImages"`
}
// GetStatefulSetList returns a list of all Stateful Sets in the cluster.
func GetStatefulSetList(client *kubernetes.Clientset, nsQuery *k8scommon.NamespaceQuery, dsQuery *dataselect.DataSelectQuery) (*StatefulSetList, error) {
global.Log.Info("Getting list of all pet sets in the cluster")
channels := &k8scommon.ResourceChannels{
StatefulSetList: k8scommon.GetStatefulSetListChannel(client, nsQuery, 1),
PodList: k8scommon.GetPodListChannel(client, nsQuery, 1),
EventList: k8scommon.GetEventListChannel(client, nsQuery, 1),
}
return GetStatefulSetListFromChannels(channels, dsQuery)
}
// GetStatefulSetListFromChannels returns a list of all Stateful Sets in the cluster reading
// required resource list once from the channels.
func GetStatefulSetListFromChannels(channels *k8scommon.ResourceChannels, dsQuery *dataselect.DataSelectQuery) (*StatefulSetList, error) {
statefulSets := <-channels.StatefulSetList.List
err := <-channels.StatefulSetList.Error
if err != nil {
return nil, err
}
pods := <-channels.PodList.List
err = <-channels.PodList.Error
if err != nil {
return nil, err
}
events := <-channels.EventList.List
err = <-channels.EventList.Error
if err != nil {
return nil, err
}
ssList := toStatefulSetList(statefulSets.Items, pods.Items, events.Items, dsQuery)
ssList.Status = getStatus(statefulSets, pods.Items, events.Items)
return ssList, nil
}
func toStatefulSetList(statefulSets []apps.StatefulSet, pods []v1.Pod, events []v1.Event, dsQuery *dataselect.DataSelectQuery) *StatefulSetList {
statefulSetList := &StatefulSetList{
StatefulSets: make([]StatefulSet, 0),
ListMeta: k8s.ListMeta{TotalItems: len(statefulSets)},
}
ssCells, filteredTotal := dataselect.GenericDataSelectWithFilter(toCells(statefulSets), dsQuery)
statefulSets = fromCells(ssCells)
statefulSetList.ListMeta = k8s.ListMeta{TotalItems: filteredTotal}
for _, statefulSet := range statefulSets {
matchingPods := k8scommon.FilterPodsByControllerRef(&statefulSet, pods)
podInfo := k8scommon.GetPodInfo(statefulSet.Status.Replicas, statefulSet.Spec.Replicas, matchingPods)
podInfo.Warnings = event.GetPodsEventWarnings(events, matchingPods)
statefulSetList.StatefulSets = append(statefulSetList.StatefulSets, toStatefulSet(&statefulSet, &podInfo))
}
return statefulSetList
}
func toStatefulSet(statefulSet *apps.StatefulSet, podInfo *k8scommon.PodInfo) StatefulSet {
return StatefulSet{
ObjectMeta: k8s.NewObjectMeta(statefulSet.ObjectMeta),
TypeMeta: k8s.NewTypeMeta(k8s.ResourceKindStatefulSet),
StatusInfo: GetStatusInfo(&statefulSet.Status),
Selector: statefulSet.Spec.Selector,
Strategy: statefulSet.Spec.UpdateStrategy,
ContainerImages: k8scommon.GetContainerImages(&statefulSet.Spec.Template.Spec),
InitContainerImages: k8scommon.GetInitContainerImages(&statefulSet.Spec.Template.Spec),
Pods: *podInfo,
}
}
func DeleteCollectionStatefulSet(client *kubernetes.Clientset, statefulSetList []k8s.StatefulSetData) (err error) {
global.Log.Info("批量删除statefulset开始")
for _, v := range statefulSetList {
global.Log.Info(fmt.Sprintf("delete statefulset%v, ns: %v", v.Name, v.Namespace))
err := client.AppsV1().StatefulSets(v.Namespace).Delete(
context.TODO(),
v.Name,
metav1.DeleteOptions{},
)
if err != nil {
global.Log.Error(err.Error())
return err
}
}
global.Log.Info("删除statefulset已完成")
return nil
}
func DeleteStatefulSet(client *kubernetes.Clientset, ns string, name string) (err error) {
global.Log.Info(fmt.Sprintf("请求删除单个statefulset%v, namespace: %v", name, ns))
return client.AppsV1().StatefulSets(ns).Delete(
context.TODO(),
name,
metav1.DeleteOptions{},
)
}
func RestartStatefulSet(client *kubernetes.Clientset, name string, namespace string) (err error) {
global.Log.Info(fmt.Sprintf("下发应用重启指令, 名称空间:%v, 有状态应用:%v", namespace, name))
data := fmt.Sprintf(`{"spec":{"template":{"metadata":{"annotations":{"kubectl.kubernetes.io/restartedAt":"%s"}}}}}`, time.Now().String())
_, err = client.AppsV1().StatefulSets(namespace).Patch(
context.Background(),
name,
types.StrategicMergePatchType,
[]byte(data),
metav1.PatchOptions{
FieldManager: "kubectl-rollout",
})
if err != nil {
global.Log.Error("应用重启失败", zap.Any("err: ", err))
return err
}
return nil
}
func ScaleStatefulSet(client *kubernetes.Clientset, ns string, name string, scaleNumber int32) (err error) {
global.Log.Info(fmt.Sprintf("start scale of %v statefulset in %v namespace", name, ns))
scaleData, err := client.AppsV1().StatefulSets(ns).GetScale(
context.TODO(),
name,
metav1.GetOptions{},
)
global.Log.Info(fmt.Sprintf("The statefulset has changed from %v to %v", scaleData.Spec.Replicas, scaleNumber))
scale := autoscalingv1.Scale{
TypeMeta: scaleData.TypeMeta,
ObjectMeta: scaleData.ObjectMeta,
Spec: autoscalingv1.ScaleSpec{Replicas: scaleNumber},
Status: scaleData.Status,
}
_, err = client.AppsV1().StatefulSets(ns).UpdateScale(
context.TODO(),
name,
&scale,
metav1.UpdateOptions{},
)
if err != nil {
global.Log.Error("扩缩容出现异常", zap.Any("err: ", err))
return err
}
return nil
}
// GetStatusInfo is used to get the status information from the *apps.StatefulSetStatus
func GetStatusInfo(statefulSetStatus *apps.StatefulSetStatus) StatusInfo {
return StatusInfo{
Replicas: statefulSetStatus.Replicas,
Updated: statefulSetStatus.UpdatedReplicas,
//AvailableReplicas: statefulSetStatus.AvailableReplicas,
ReadyReplicas: statefulSetStatus.ReadyReplicas,
CurrentReplicas: statefulSetStatus.CurrentReplicas,
}
}