Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 40 additions & 2 deletions pkg/model/enum/parent_relationship.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,14 @@ const (
RelationshipContainer ParentRelationship = 4
RelationshipNodeComponent ParentRelationship = 5
RelationshipOwnerReference ParentRelationship = 6
RelationshipPodBinding ParentRelationship = 7
RelationshipPodBinding ParentRelationship = 7 // Deprecated and replaced by PodPhase
RelationshipNetworkEndpointGroup ParentRelationship = 8
RelationshipManagedInstanceGroup ParentRelationship = 9
RelationshipControlPlaneComponent ParentRelationship = 10
RelationshipSerialPort ParentRelationship = 11
RelationshipAirflowTaskInstance ParentRelationship = 12
RelationshipCSMAccessLog ParentRelationship = 13 // Added since 0.49
RelationshipPodPhase ParentRelationship = 14 // Added since 0.50
relationshipUnusedEnd // Add items above. This field is used for counting items in this enum to test.
)

Expand Down Expand Up @@ -238,7 +239,7 @@ var ParentRelationships = map[ParentRelationship]ParentRelationshipFrontendMetad
RelationshipEndpointSlice: {
Visible: true,
EnumKeyName: "RelationshipEndpointSlice",
Label: "endpointslice",
Label: "endpoint", // renamed from "endpointslice" in 0.50.0
LongName: "Endpoint serving state timeline",
LabelColor: "#FFFFFF",
LabelBackgroundColor: "#008000",
Expand Down Expand Up @@ -537,4 +538,41 @@ var ParentRelationships = map[ParentRelationship]ParentRelationshipFrontendMetad
},
},
},
RelationshipPodPhase: {
Visible: true,
EnumKeyName: "RelationshipPodPhase",
Label: "pod",
LongName: "Pod phase",
LabelColor: "#FFFFFF",
LabelBackgroundColor: "#FF8855",
Hint: "Pod phase running on the node",
SortPriority: 8000, // just under container logs
GeneratableRevisions: []GeneratableRevisionInfo{
{
State: RevisionStatePodPhasePending,
SourceLogType: LogTypeAudit,
Description: "Pod is pending",
},
{
State: RevisionStatePodPhaseRunning,
SourceLogType: LogTypeAudit,
Description: "Pod is running",
},
{
State: RevisionStatePodPhaseSucceeded,
SourceLogType: LogTypeAudit,
Description: "Pod is succeeded",
},
{
State: RevisionStatePodPhaseFailed,
SourceLogType: LogTypeAudit,
Description: "Pod is failed",
},
{
State: RevisionStatePodPhaseUnknown,
SourceLogType: LogTypeAudit,
Description: "Pod phase is unknown",
},
},
},
}
73 changes: 73 additions & 0 deletions pkg/model/enum/revision_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,19 @@ const (
RevisionAutoscalerNoError RevisionState = 30 // Added since 0.49
RevisionAutoscalerHasErrors RevisionState = 31

RevisionStateConditionNotGiven RevisionState = 32 // Added since 0.50
RevisionStateConditionNoAvailableInfo RevisionState = 33 // Added since 0.50

RevisionStatePodPhasePending RevisionState = 34 // Added since 0.50
RevisionStatePodPhaseScheduled RevisionState = 35 // Added since 0.50
RevisionStatePodPhaseRunning RevisionState = 36 // Added since 0.50
RevisionStatePodPhaseSucceeded RevisionState = 37 // Added since 0.50
RevisionStatePodPhaseFailed RevisionState = 38 // Added since 0.50
RevisionStatePodPhaseUnknown RevisionState = 39 // Added since 0.50

RevisionStateContainerStatusNotAvailable RevisionState = 40 // Added since 0.50
RevisionStateContainerStarted RevisionState = 41 // Added since 0.50

revisionStateUnusedEnd // Adds items above. This value is used for counting items in this enum to test.
)

Expand Down Expand Up @@ -269,4 +282,64 @@ var RevisionStates = map[RevisionState]RevisionStateFrontendMetadata{
CSSSelector: "autoscaler_has_errors",
Label: "Autoscaler has errors",
},
RevisionStateConditionNotGiven: {
EnumKeyName: "RevisionStateConditionNotGiven",
BackgroundColor: "#666666",
CSSSelector: "condition_not_given",
Label: "Condition is not defined at this moment",
},
RevisionStateConditionNoAvailableInfo: {
EnumKeyName: "RevisionStateConditionNoAvailableInfo",
BackgroundColor: "#997700",
CSSSelector: "condition_no_available_info",
Label: "No enough information to show condition",
},
RevisionStatePodPhasePending: {
EnumKeyName: "RevisionStatePodPhasePending",
BackgroundColor: "#666666",
CSSSelector: "pod_phase_pending",
Label: "Pod is pending",
},
RevisionStatePodPhaseScheduled: {
EnumKeyName: "RevisionStatePodPhaseScheduled",
BackgroundColor: "#4444ff",
CSSSelector: "pod_phase_scheduled",
Label: "Pod is scheduled",
},
RevisionStatePodPhaseRunning: {
EnumKeyName: "RevisionStatePodPhaseRunning",
BackgroundColor: "#004400",
CSSSelector: "pod_phase_running",
Label: "Pod is running",
},
RevisionStatePodPhaseSucceeded: {
EnumKeyName: "RevisionStatePodPhaseSucceeded",
BackgroundColor: "#113333",
CSSSelector: "pod_phase_succeeded",
Label: "Pod is succeeded",
},
RevisionStatePodPhaseFailed: {
EnumKeyName: "RevisionStatePodPhaseFailed",
BackgroundColor: "#331111",
CSSSelector: "pod_phase_failed",
Label: "Pod is failed",
},
RevisionStatePodPhaseUnknown: {
EnumKeyName: "RevisionStatePodPhaseUnknown",
BackgroundColor: "#000000",
CSSSelector: "pod_phase_unknown",
Label: "Pod status is not available from current log range",
},
RevisionStateContainerStatusNotAvailable: {
EnumKeyName: "RevisionStateContainerStatusNotAvailable",
BackgroundColor: "#666666",
CSSSelector: "container_status_not_available",
Label: "Container status is not available",
},
RevisionStateContainerStarted: {
EnumKeyName: "RevisionStateContainerStarted",
BackgroundColor: "#997700",
CSSSelector: "container_started",
Label: "Container is started but readiness info is not available",
},
}
27 changes: 25 additions & 2 deletions pkg/model/history/resourcepath/pseudo.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,18 @@ func NodeBinding(nodeName string, podNamespace string, podName string) ResourceP
return node
}

func EndpointSliceChildPod(endpointSliceNamespace string, endpointSliceName string, podNamespace string, podName string) ResourcePath {
eps := EndpointSlice(endpointSliceNamespace, endpointSliceName)
if podNamespace != endpointSliceNamespace {
podNamespace = fmt.Sprintf("(%s)", podNamespace)
} else {
podNamespace = ""
}
eps.Path = fmt.Sprintf("%s#%s%s[pod]", eps.Path, podName, podNamespace)
eps.ParentRelationship = enum.RelationshipEndpointSlice
return eps
}

// PodEndpointSlice returns a ResourcePath for the pseudo endpointslice timeline under pods.
func PodEndpointSlice(endpointSliceNamespace string, endpointSliceName string, podNamespace string, podName string) ResourcePath {
if endpointSliceName == "" {
Expand Down Expand Up @@ -128,8 +140,8 @@ func Operation(operationOwner ResourcePath, operationMethod string, operationId
}
}

// Status returns a ResourcePath for the pseudo status timeline under the given name layer resource.
func Status(statusOwner ResourcePath, statusName string) ResourcePath {
// Condition returns a ResourcePath for the pseudo status timeline under the given name layer resource.
func Condition(statusOwner ResourcePath, statusName string) ResourcePath {
if statusName == "" {
statusName = nonSpecifiedPlaceholder
}
Expand Down Expand Up @@ -166,3 +178,14 @@ func OwnerSubresource(ownerPath ResourcePath, ownedResourceName string, ownedRes
ParentRelationship: enum.RelationshipOwnerReference,
}
}

func PodPhase(nodeName string, podNamespace, podName, uid string) ResourcePath {
if uid == "" {
uid = nonSpecifiedPlaceholder
}
node := Node(nodeName)
return ResourcePath{
Path: fmt.Sprintf("%s#%s/%s[%s]", node.Path, podNamespace, podName, uid),
ParentRelationship: enum.RelationshipPodPhase,
}
}
8 changes: 4 additions & 4 deletions pkg/model/history/resourcepath/pseudo_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@ func TestOperation(t *testing.T) {
}
}

func TestStatus(t *testing.T) {
func TestCondition(t *testing.T) {
expectedParentRelationship := enum.RelationshipResourceCondition
testCases := []struct {
name string
Expand All @@ -315,12 +315,12 @@ func TestStatus(t *testing.T) {

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
result := Status(tc.statusOwner, tc.statusName)
result := Condition(tc.statusOwner, tc.statusName)
if result.Path != tc.expected {
t.Errorf("Status(%v,%v).Path = %v, want %v", tc.statusOwner, tc.statusName, result.Path, tc.expected)
t.Errorf("Condition(%v,%v).Path = %v, want %v", tc.statusOwner, tc.statusName, result.Path, tc.expected)
}
if result.ParentRelationship != expectedParentRelationship {
t.Errorf("Status(%v,%v).ParentRelationship = %v, want %v", tc.statusOwner, tc.statusName, result.ParentRelationship, expectedParentRelationship)
t.Errorf("Condition(%v,%v).ParentRelationship = %v, want %v", tc.statusOwner, tc.statusName, result.ParentRelationship, expectedParentRelationship)
}
})
}
Expand Down
10 changes: 10 additions & 0 deletions pkg/model/history/resourcepath/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,13 @@ func Node(name string) ResourcePath {
}
return NameLayerGeneralItem("core/v1", "node", "cluster-scope", name)
}

func EndpointSlice(namespace string, name string) ResourcePath {
if namespace == "" {
namespace = nonSpecifiedPlaceholder
}
if name == "" {
name = nonSpecifiedPlaceholder
}
return NameLayerGeneralItem("discovery.k8s.io/v1", "endpointslice", namespace, name)
}
2 changes: 1 addition & 1 deletion pkg/model/history/timeline_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ func (b *TimelineBuilder) sortWithoutLock() {
return b.timeDiffOfLogIndicces(x.Log, y.Log)
})
slices.SortStableFunc(b.timeline.Revisions, func(x, y *ResourceRevision) int {
return b.timeDiffOfLogIndicces(x.Log, y.Log)
return int(x.ChangeTime.Sub(y.ChangeTime))
})
b.sorted = true
}
Expand Down
41 changes: 41 additions & 0 deletions pkg/model/k8s.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@

package model

import (
"fmt"
"time"
)

// A kubernetes resource `.status` field
type K8sResourceContainingStatus struct {
Status *K8sResourceStatus `yaml:"status"`
Expand Down Expand Up @@ -67,6 +72,42 @@ type K8sResourceStatusCondition struct {
Reason string `yaml:"reason"`
}

func (c *K8sResourceStatusCondition) ToMap() map[string]any {
result := map[string]any{}
if c.Type != "" {
result["type"] = c.Type
}
if c.LastTransitionTime != "" {
result["lastTransitionTime"] = c.LastTransitionTime
}
if c.LastHeartbeatTime != "" {
result["lastHeartbeatTime"] = c.LastHeartbeatTime
}
if c.LastProbeTime != "" {
result["lastProbeTime"] = c.LastProbeTime
}
if c.Message != "" {
result["message"] = c.Message
}
if c.Status != "" {
result["status"] = c.Status
}
if c.Reason != "" {
result["reason"] = c.Reason
}
return result
}

func (c *K8sResourceStatusCondition) ProbeLikeTime() (time.Time, error) {
if c.LastProbeTime != "" {
return time.Parse(time.RFC3339, c.LastProbeTime)
}
if c.LastHeartbeatTime != "" {
return time.Parse(time.RFC3339, c.LastHeartbeatTime)
}
return time.Time{}, fmt.Errorf("lastProbeTime and lastHeartbeatTime are both empty")
}

type K8sTargetRef struct {
Kind string `yaml:"kind"`
Name string `yaml:"name"`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ func recordChangeSetForLog(ctx context.Context, resourcePath string, l *commonlo
commonField, _ := log.GetFieldSet(l.Log, &log.CommonFieldSet{})
target := l.ResourceBodyReader.ReadStringOrDefault("target.name", "unknown")

podScheduledStatusPath := resourcepath.Status(resourcepath.Pod(l.Operation.Namespace, l.Operation.Name), "PodScheduled")
podScheduledStatusPath := resourcepath.Condition(resourcepath.Pod(l.Operation.Namespace, l.Operation.Name), "PodScheduled")
nodeBindingResourcePath := resourcepath.NodeBinding(target, l.Operation.Namespace, l.Operation.Name)
if l.Operation.Verb == enum.RevisionVerbCreate {
cs.AddRevision(nodeBindingResourcePath, &history.StagingResourceRevision{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ func recordChangeSetForLog(ctx context.Context, resourcePath string, l *commonlo
conditionTime = lastProbeTime
}
// Ignore if the transition time was older than the last revision
statusPath := resourcepath.Status(resourcepath.FromK8sOperation(*l.Operation), condition.Type)
statusPath := resourcepath.Condition(resourcepath.FromK8sOperation(*l.Operation), condition.Type)
if l.Operation.SubResourceName != "" {
parentOp := model.KubernetesObjectOperation{
APIVersion: l.Operation.APIVersion,
Expand All @@ -82,7 +82,7 @@ func recordChangeSetForLog(ctx context.Context, resourcePath string, l *commonlo
Name: l.Operation.Name,
Verb: l.Operation.Verb,
}
statusPath = resourcepath.Status(resourcepath.FromK8sOperation(parentOp), condition.Type)
statusPath = resourcepath.Condition(resourcepath.FromK8sOperation(parentOp), condition.Type)
}
tb := builder.GetTimelineBuilder(statusPath.Path)
latest := tb.GetLatestRevision()
Expand Down
Loading
Loading