mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-05-07 00:37:36 +00:00
131 lines
4.2 KiB
Go
131 lines
4.2 KiB
Go
package unifiedresources
|
|
|
|
import (
|
|
"crypto/sha1"
|
|
"encoding/hex"
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
const (
|
|
MetadataActivityType = "activity_type"
|
|
MetadataActivityNativeID = "activity_native_id"
|
|
MetadataActivityTitle = "activity_title"
|
|
MetadataActivityState = "activity_state"
|
|
MetadataActivityMessage = "activity_message"
|
|
)
|
|
|
|
// PlatformActivityChange captures read-only provider activity that should be
|
|
// preserved on the canonical resource timeline as investigation context.
|
|
type PlatformActivityChange struct {
|
|
SourceAdapter ChangeSourceAdapter
|
|
ActivityType string
|
|
NativeID string
|
|
Title string
|
|
State string
|
|
Message string
|
|
Actor string
|
|
OccurredAt time.Time
|
|
RelatedResources []string
|
|
Metadata map[string]any
|
|
}
|
|
|
|
// BuildPlatformActivityChange constructs a canonical timeline change for
|
|
// provider-emitted read-side activity such as VMware tasks or events.
|
|
func BuildPlatformActivityChange(resourceID string, activity PlatformActivityChange) *ResourceChange {
|
|
resourceID = CanonicalResourceID(resourceID)
|
|
if resourceID == "" {
|
|
return nil
|
|
}
|
|
|
|
sourceAdapter := ChangeSourceAdapter(strings.TrimSpace(string(activity.SourceAdapter)))
|
|
if sourceAdapter == "" {
|
|
return nil
|
|
}
|
|
|
|
activityType := strings.TrimSpace(activity.ActivityType)
|
|
nativeID := strings.TrimSpace(activity.NativeID)
|
|
title := strings.TrimSpace(activity.Title)
|
|
state := strings.TrimSpace(activity.State)
|
|
message := strings.TrimSpace(activity.Message)
|
|
if activityType == "" || (nativeID == "" && title == "" && message == "") {
|
|
return nil
|
|
}
|
|
|
|
observedAt := activity.OccurredAt.UTC()
|
|
if observedAt.IsZero() {
|
|
observedAt = time.Now().UTC()
|
|
}
|
|
|
|
change := &ResourceChange{
|
|
ID: platformActivityChangeID(resourceID, sourceAdapter, activityType, nativeID, observedAt, title, message),
|
|
ObservedAt: observedAt,
|
|
ResourceID: resourceID,
|
|
Kind: ChangeActivity,
|
|
SourceType: SourcePlatformEvent,
|
|
SourceAdapter: sourceAdapter,
|
|
Confidence: ConfidenceHigh,
|
|
Actor: strings.TrimSpace(activity.Actor),
|
|
Reason: platformActivityReason(activityType, title, state, message),
|
|
Metadata: cloneChangeMetadata(activity.Metadata),
|
|
}
|
|
if !activity.OccurredAt.IsZero() {
|
|
occurredAt := activity.OccurredAt.UTC()
|
|
change.OccurredAt = &occurredAt
|
|
}
|
|
|
|
if _, exists := change.Metadata[MetadataActivityType]; !exists && activityType != "" {
|
|
change.Metadata[MetadataActivityType] = activityType
|
|
}
|
|
if _, exists := change.Metadata[MetadataActivityNativeID]; !exists && nativeID != "" {
|
|
change.Metadata[MetadataActivityNativeID] = nativeID
|
|
}
|
|
if _, exists := change.Metadata[MetadataActivityTitle]; !exists && title != "" {
|
|
change.Metadata[MetadataActivityTitle] = title
|
|
}
|
|
if _, exists := change.Metadata[MetadataActivityState]; !exists && state != "" {
|
|
change.Metadata[MetadataActivityState] = state
|
|
}
|
|
if _, exists := change.Metadata[MetadataActivityMessage]; !exists && message != "" {
|
|
change.Metadata[MetadataActivityMessage] = message
|
|
}
|
|
|
|
change.RelatedResources = uniqueTrimmed(activity.RelatedResources...)
|
|
return change
|
|
}
|
|
|
|
func platformActivityChangeID(resourceID string, sourceAdapter ChangeSourceAdapter, activityType, nativeID string, occurredAt time.Time, title, message string) string {
|
|
base := nativeID
|
|
if strings.TrimSpace(base) == "" {
|
|
base = fmt.Sprintf("%s|%s|%s", occurredAt.UTC().Format(time.RFC3339Nano), strings.TrimSpace(title), strings.TrimSpace(message))
|
|
}
|
|
sum := sha1.Sum([]byte(strings.Join([]string{
|
|
CanonicalResourceID(resourceID),
|
|
strings.TrimSpace(string(sourceAdapter)),
|
|
strings.TrimSpace(activityType),
|
|
base,
|
|
}, "|")))
|
|
return "activity-" + hex.EncodeToString(sum[:])
|
|
}
|
|
|
|
func platformActivityReason(activityType, title, state, message string) string {
|
|
activityType = strings.TrimSpace(strings.ReplaceAll(activityType, "_", " "))
|
|
title = strings.TrimSpace(title)
|
|
state = strings.TrimSpace(state)
|
|
message = strings.TrimSpace(message)
|
|
|
|
if title != "" && state != "" {
|
|
return fmt.Sprintf("%s (%s)", title, state)
|
|
}
|
|
if title != "" {
|
|
return title
|
|
}
|
|
if message != "" {
|
|
return message
|
|
}
|
|
if activityType == "" {
|
|
return "Provider activity recorded"
|
|
}
|
|
return fmt.Sprintf("%s recorded", strings.ToUpper(activityType[:1])+activityType[1:])
|
|
}
|