mirror of
https://gitee.com/XM-GO/PandaX.git
synced 2026-04-25 20:58:34 +08:00
【修改】k8s 配置
This commit is contained in:
237
apps/devops/services/k8s/event/event_common.go
Normal file
237
apps/devops/services/k8s/event/event_common.go
Normal file
@@ -0,0 +1,237 @@
|
||||
package event
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/fields"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"pandax/apps/devops/entity/k8s"
|
||||
k8scommon "pandax/apps/devops/services/k8s/common"
|
||||
"pandax/apps/devops/services/k8s/dataselect"
|
||||
)
|
||||
|
||||
// EmptyEventList is a empty list of events.
|
||||
var EmptyEventList = &k8scommon.EventList{
|
||||
Events: make([]k8scommon.Event, 0),
|
||||
ListMeta: k8s.ListMeta{
|
||||
TotalItems: 0,
|
||||
},
|
||||
}
|
||||
|
||||
// ToEvent converts event api Event to Event model object.
|
||||
func ToEvent(event v1.Event) k8scommon.Event {
|
||||
result := k8scommon.Event{
|
||||
ObjectMeta: k8s.NewObjectMeta(event.ObjectMeta),
|
||||
TypeMeta: k8s.NewTypeMeta(k8s.ResourceKindEvent),
|
||||
Message: event.Message,
|
||||
SourceComponent: event.Source.Component,
|
||||
SourceHost: event.Source.Host,
|
||||
SubObject: event.InvolvedObject.FieldPath,
|
||||
SubObjectKind: event.InvolvedObject.Kind,
|
||||
SubObjectName: event.InvolvedObject.Name,
|
||||
SubObjectNamespace: event.InvolvedObject.Namespace,
|
||||
Count: event.Count,
|
||||
FirstSeen: event.FirstTimestamp,
|
||||
LastSeen: event.LastTimestamp,
|
||||
Reason: event.Reason,
|
||||
Type: event.Type,
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// FailedReasonPartials is an array of partial strings to correctly filter warning events.
|
||||
// Have to be lower case for correct case insensitive comparison.
|
||||
// Based on k8s official events reason file:
|
||||
// https://github.com/kubernetes/kubernetes/blob/886e04f1fffbb04faf8a9f9ee141143b2684ae68/pkg/kubelet/events/event.go
|
||||
// Partial strings that are not in event.go file are added in order to support
|
||||
// older versions of k8s which contained additional event reason messages.
|
||||
var FailedReasonPartials = []string{"failed", "err", "exceeded", "invalid", "unhealthy",
|
||||
"mismatch", "insufficient", "conflict", "outof", "nil", "backoff"}
|
||||
|
||||
// GetNodeEvents gets events associated to node with given name.
|
||||
func GetNodeEvents(client *kubernetes.Clientset, nodeName string) (*v1.EventList, error) {
|
||||
|
||||
//scheme := runtime.NewScheme()
|
||||
//groupVersion := schema.GroupVersion{Group: "", Version: "v1"}
|
||||
//scheme.AddKnownTypes(groupVersion, &v1.Node{})
|
||||
//
|
||||
//node, err := client.CoreV1().Nodes().Get(context.TODO(), nodeName, metaV1.GetOptions{})
|
||||
//
|
||||
//if err != nil {
|
||||
// return nil, err
|
||||
//}
|
||||
events, err := client.CoreV1().Events(v1.NamespaceAll).List(context.TODO(),
|
||||
metaV1.ListOptions{FieldSelector: fmt.Sprintf("involvedObject.name=%v", nodeName)})
|
||||
|
||||
//events, err := client.CoreV1().Events(v1.NamespaceAll).Search(scheme, node)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return events, nil
|
||||
}
|
||||
|
||||
// FillEventsType is based on event Reason fills event Type in order to allow correct filtering by Type.
|
||||
func FillEventsType(events []v1.Event) []v1.Event {
|
||||
for i := range events {
|
||||
// Fill in only events with empty type.
|
||||
if len(events[i].Type) == 0 {
|
||||
if isFailedReason(events[i].Reason, FailedReasonPartials...) {
|
||||
events[i].Type = v1.EventTypeWarning
|
||||
} else {
|
||||
events[i].Type = v1.EventTypeNormal
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return events
|
||||
}
|
||||
|
||||
// GetResourceEvents gets events associated to specified resource.
|
||||
func GetResourceEvents(client *kubernetes.Clientset, dsQuery *dataselect.DataSelectQuery, namespace, name string) (*k8scommon.EventList, error) {
|
||||
resourceEvents, err := GetEvents(client, namespace, name)
|
||||
|
||||
if err != nil {
|
||||
return EmptyEventList, err
|
||||
}
|
||||
|
||||
events := CreateEventList(resourceEvents, dsQuery)
|
||||
return &events, nil
|
||||
}
|
||||
|
||||
// CreateEventList converts array of api events to common EventList structure
|
||||
func CreateEventList(events []v1.Event, dsQuery *dataselect.DataSelectQuery) k8scommon.EventList {
|
||||
eventList := k8scommon.EventList{
|
||||
Events: make([]k8scommon.Event, 0),
|
||||
ListMeta: k8s.ListMeta{TotalItems: len(events)},
|
||||
}
|
||||
|
||||
events = fromCells(dataselect.GenericDataSelect(toCells(events), dsQuery))
|
||||
for _, event := range events {
|
||||
eventDetail := ToEvent(event)
|
||||
eventList.Events = append(eventList.Events, eventDetail)
|
||||
}
|
||||
|
||||
return eventList
|
||||
}
|
||||
|
||||
// The code below allows to perform complex data section on []api.Event
|
||||
|
||||
type EventCell v1.Event
|
||||
|
||||
func (self EventCell) GetProperty(name dataselect.PropertyName) dataselect.ComparableValue {
|
||||
switch name {
|
||||
case dataselect.NameProperty:
|
||||
return dataselect.StdComparableString(self.ObjectMeta.Name)
|
||||
case dataselect.CreationTimestampProperty:
|
||||
return dataselect.StdComparableTime(self.ObjectMeta.CreationTimestamp.Time)
|
||||
case dataselect.FirstSeenProperty:
|
||||
return dataselect.StdComparableTime(self.FirstTimestamp.Time)
|
||||
case dataselect.LastSeenProperty:
|
||||
return dataselect.StdComparableTime(self.LastTimestamp.Time)
|
||||
case dataselect.NamespaceProperty:
|
||||
return dataselect.StdComparableString(self.ObjectMeta.Namespace)
|
||||
case dataselect.ReasonProperty:
|
||||
return dataselect.StdComparableString(self.Reason)
|
||||
default:
|
||||
// if name is not supported then just return a constant dummy value, sort will have no effect.
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func toCells(std []v1.Event) []dataselect.DataCell {
|
||||
cells := make([]dataselect.DataCell, len(std))
|
||||
for i := range std {
|
||||
cells[i] = EventCell(std[i])
|
||||
}
|
||||
return cells
|
||||
}
|
||||
|
||||
func fromCells(cells []dataselect.DataCell) []v1.Event {
|
||||
std := make([]v1.Event, len(cells))
|
||||
for i := range std {
|
||||
std[i] = v1.Event(cells[i].(EventCell))
|
||||
}
|
||||
return std
|
||||
}
|
||||
|
||||
// GetEvents gets events associated to resource with given name.
|
||||
func GetEvents(client *kubernetes.Clientset, namespace, resourceName string) ([]v1.Event, error) {
|
||||
fieldSelector, err := fields.ParseSelector("involvedObject.name" + "=" + resourceName)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
channels := &k8scommon.ResourceChannels{
|
||||
EventList: k8scommon.GetEventListChannelWithOptions(client, k8scommon.NewSameNamespaceQuery(namespace),
|
||||
metaV1.ListOptions{
|
||||
LabelSelector: labels.Everything().String(),
|
||||
FieldSelector: fieldSelector.String(),
|
||||
},
|
||||
1),
|
||||
}
|
||||
|
||||
eventList := <-channels.EventList.List
|
||||
if err := <-channels.EventList.Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return FillEventsType(eventList.Items), nil
|
||||
}
|
||||
|
||||
// GetPodEvents gets pods events associated to pod name and namespace
|
||||
func GetPodEvents(client *kubernetes.Clientset, namespace, podName string) ([]v1.Event, error) {
|
||||
|
||||
channels := &k8scommon.ResourceChannels{
|
||||
PodList: k8scommon.GetPodListChannel(client, k8scommon.NewSameNamespaceQuery(namespace), 1),
|
||||
EventList: k8scommon.GetEventListChannel(client, k8scommon.NewSameNamespaceQuery(namespace), 1),
|
||||
}
|
||||
|
||||
podList := <-channels.PodList.List
|
||||
if err := <-channels.PodList.Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
eventList := <-channels.EventList.List
|
||||
if err := <-channels.EventList.Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
l := make([]v1.Pod, 0)
|
||||
for _, pi := range podList.Items {
|
||||
if pi.Name == podName {
|
||||
l = append(l, pi)
|
||||
}
|
||||
}
|
||||
|
||||
events := filterEventsByPodsUID(eventList.Items, l)
|
||||
return FillEventsType(events), nil
|
||||
}
|
||||
|
||||
// GetPodsEvents gets events targeting given list of pods.
|
||||
func GetPodsEvents(client *kubernetes.Clientset, namespace string, pods []v1.Pod) ([]v1.Event, error) {
|
||||
|
||||
nsQuery := k8scommon.NewSameNamespaceQuery(namespace)
|
||||
if namespace == v1.NamespaceAll {
|
||||
nsQuery = k8scommon.NewNamespaceQuery([]string{})
|
||||
}
|
||||
|
||||
channels := &k8scommon.ResourceChannels{
|
||||
EventList: k8scommon.GetEventListChannel(client, nsQuery, 1),
|
||||
}
|
||||
|
||||
eventList := <-channels.EventList.List
|
||||
if err := <-channels.EventList.Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
events := filterEventsByPodsUID(eventList.Items, pods)
|
||||
|
||||
return events, nil
|
||||
}
|
||||
147
apps/devops/services/k8s/event/events.go
Normal file
147
apps/devops/services/k8s/event/events.go
Normal file
@@ -0,0 +1,147 @@
|
||||
package event
|
||||
|
||||
import (
|
||||
"context"
|
||||
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/services/k8s/common"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func GetClusterNodeEvent(client *kubernetes.Clientset, namespace string, field string) (*v1.EventList, error) {
|
||||
|
||||
events, err := client.CoreV1().Events(namespace).List(context.TODO(),
|
||||
metav1.ListOptions{
|
||||
FieldSelector: field,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return events, nil
|
||||
}
|
||||
|
||||
// GetPodsEventWarnings returns warning pod events by filtering out events targeting only given pods
|
||||
func GetPodsEventWarnings(events []v1.Event, pods []v1.Pod) []common.Event {
|
||||
result := make([]common.Event, 0)
|
||||
|
||||
// Filter out only warning events
|
||||
events = getWarningEvents(events)
|
||||
failedPods := make([]v1.Pod, 0)
|
||||
|
||||
// Filter out ready and successful pods
|
||||
for _, pod := range pods {
|
||||
if !isReadyOrSucceeded(pod) {
|
||||
failedPods = append(failedPods, pod)
|
||||
}
|
||||
}
|
||||
|
||||
// Filter events by failed pods UID
|
||||
events = filterEventsByPodsUID(events, failedPods)
|
||||
events = removeDuplicates(events)
|
||||
|
||||
for _, event := range events {
|
||||
result = append(result, common.Event{
|
||||
Message: event.Message,
|
||||
Reason: event.Reason,
|
||||
Type: event.Type,
|
||||
})
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// Returns filtered list of event objects.
|
||||
// Event list object is filtered to get only warning events.
|
||||
func getWarningEvents(events []v1.Event) []v1.Event {
|
||||
return filterEventsByType(FillEventsType(events), v1.EventTypeWarning)
|
||||
}
|
||||
|
||||
// Returns true if given pod is in state ready or succeeded, false otherwise
|
||||
func isReadyOrSucceeded(pod v1.Pod) bool {
|
||||
if pod.Status.Phase == v1.PodSucceeded {
|
||||
return true
|
||||
}
|
||||
if pod.Status.Phase == v1.PodRunning {
|
||||
for _, c := range pod.Status.Conditions {
|
||||
if c.Type == v1.PodReady {
|
||||
if c.Status == v1.ConditionFalse {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// Returns filtered list of event objects. Events list is filtered to get only events targeting
|
||||
// pods on the list.
|
||||
func filterEventsByPodsUID(events []v1.Event, pods []v1.Pod) []v1.Event {
|
||||
result := make([]v1.Event, 0)
|
||||
podEventMap := make(map[types.UID]bool, 0)
|
||||
|
||||
if len(pods) == 0 || len(events) == 0 {
|
||||
return result
|
||||
}
|
||||
|
||||
for _, pod := range pods {
|
||||
podEventMap[pod.UID] = true
|
||||
}
|
||||
|
||||
for _, event := range events {
|
||||
if _, exists := podEventMap[event.InvolvedObject.UID]; exists {
|
||||
result = append(result, event)
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// Removes duplicate strings from the slice
|
||||
func removeDuplicates(slice []v1.Event) []v1.Event {
|
||||
visited := make(map[string]bool, 0)
|
||||
result := make([]v1.Event, 0)
|
||||
|
||||
for _, elem := range slice {
|
||||
if !visited[elem.Reason] {
|
||||
visited[elem.Reason] = true
|
||||
result = append(result, elem)
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// Filters kubernetes API event objects based on event type.
|
||||
// Empty string will return all events.
|
||||
func filterEventsByType(events []v1.Event, eventType string) []v1.Event {
|
||||
if len(eventType) == 0 || len(events) == 0 {
|
||||
return events
|
||||
}
|
||||
|
||||
result := make([]v1.Event, 0)
|
||||
for _, event := range events {
|
||||
if event.Type == eventType {
|
||||
result = append(result, event)
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// Returns true if reason string contains any partial string indicating that this may be a
|
||||
// warning, false otherwise
|
||||
func isFailedReason(reason string, partials ...string) bool {
|
||||
for _, partial := range partials {
|
||||
if strings.Contains(strings.ToLower(reason), partial) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
Reference in New Issue
Block a user