mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-05-01 21:10:13 +00:00
feat: Complete Unified Resource Architecture (Phases 1-3)
This commit implements the Unified Resource Architecture for AI-first
infrastructure management. Key features:
Phase 1 - Backend Unification:
- New unified Resource type with 9 resource types, 7 platforms, 7 statuses
- Resource store with identity-based deduplication (hostname, machineID, IP)
- 8 converter functions (FromNode, FromVM, FromContainer, etc.)
- REST API endpoints: /api/resources, /api/resources/stats, /api/resources/{id}
- 28 comprehensive unit tests
Phase 2 - AI Context Enhancement:
- Unified context builder for AI system prompts
- Cross-platform query methods: GetTopByCPU, GetTopByMemory, GetTopByDisk
- Resource correlation: GetRelated (parent, children, siblings, cluster)
- Infrastructure summary: GetResourceSummary with health status counts
- AI context now includes top consumers and infrastructure overview
Phase 3 - Agent Preference & Hybrid Mode:
- Polling optimization methods in resource store
- ResourceStoreInterface added to Monitor
- SetResourceStore() and shouldSkipNodeMetrics() helper methods
- Store automatically wired into Monitor via Router.SetMonitor()
- Foundation ready for reduced API polling when agents are active
Files added:
- internal/resources/resource.go - Core Resource type
- internal/resources/store.go - Store with deduplication
- internal/resources/converters.go - Type converters
- internal/resources/platform_data.go - Platform-specific data
- internal/resources/store_test.go - 28 tests
- internal/resources/converters_test.go - Converter tests
- internal/api/resource_handlers.go - REST API handlers
- internal/ai/resource_context.go - AI context builder
- .gemini/docs/unified-resource-architecture.md - Architecture docs
All tests pass.
This commit is contained in:
parent
7b1ec9b5f5
commit
f34c28f970
13 changed files with 4872 additions and 10 deletions
287
internal/resources/platform_data.go
Normal file
287
internal/resources/platform_data.go
Normal file
|
|
@ -0,0 +1,287 @@
|
|||
package resources
|
||||
|
||||
import "time"
|
||||
|
||||
// NodePlatformData contains Proxmox VE node-specific fields.
|
||||
// Stored in Resource.PlatformData when Type is ResourceTypeNode.
|
||||
type NodePlatformData struct {
|
||||
Instance string `json:"instance"` // Proxmox instance URL
|
||||
Host string `json:"host"` // Full host URL from config
|
||||
GuestURL string `json:"guestURL"` // Optional guest-accessible URL
|
||||
PVEVersion string `json:"pveVersion"` // Proxmox VE version
|
||||
KernelVersion string `json:"kernelVersion"` // Linux kernel version
|
||||
CPUInfo CPUInfo `json:"cpuInfo"` // CPU details
|
||||
LoadAverage []float64 `json:"loadAverage"` // 1, 5, 15 minute load averages
|
||||
|
||||
// Cluster information
|
||||
IsClusterMember bool `json:"isClusterMember"`
|
||||
ClusterName string `json:"clusterName"`
|
||||
|
||||
// Connection status
|
||||
ConnectionHealth string `json:"connectionHealth"`
|
||||
}
|
||||
|
||||
// CPUInfo contains CPU hardware details.
|
||||
type CPUInfo struct {
|
||||
Model string `json:"model"`
|
||||
Cores int `json:"cores"`
|
||||
Sockets int `json:"sockets"`
|
||||
}
|
||||
|
||||
// VMPlatformData contains Proxmox VM-specific fields.
|
||||
// Stored in Resource.PlatformData when Type is ResourceTypeVM.
|
||||
type VMPlatformData struct {
|
||||
VMID int `json:"vmid"`
|
||||
Node string `json:"node"` // Proxmox node hosting this VM
|
||||
Instance string `json:"instance"` // Proxmox instance URL
|
||||
CPUs int `json:"cpus"` // Number of vCPUs
|
||||
Template bool `json:"template"`
|
||||
Lock string `json:"lock,omitempty"` // Lock status (backup, migrate, etc.)
|
||||
AgentVersion string `json:"agentVersion,omitempty"`
|
||||
OSName string `json:"osName,omitempty"`
|
||||
OSVersion string `json:"osVersion,omitempty"`
|
||||
IPAddresses []string `json:"ipAddresses,omitempty"`
|
||||
|
||||
// I/O stats
|
||||
NetworkIn int64 `json:"networkIn"`
|
||||
NetworkOut int64 `json:"networkOut"`
|
||||
DiskRead int64 `json:"diskRead"`
|
||||
DiskWrite int64 `json:"diskWrite"`
|
||||
|
||||
// Backup info
|
||||
LastBackup *time.Time `json:"lastBackup,omitempty"`
|
||||
}
|
||||
|
||||
// ContainerPlatformData contains Proxmox LXC container-specific fields.
|
||||
// Stored in Resource.PlatformData when Type is ResourceTypeContainer.
|
||||
type ContainerPlatformData struct {
|
||||
VMID int `json:"vmid"`
|
||||
Node string `json:"node"` // Proxmox node hosting this container
|
||||
Instance string `json:"instance"` // Proxmox instance URL
|
||||
CPUs int `json:"cpus"` // Number of vCPUs
|
||||
Template bool `json:"template"`
|
||||
Lock string `json:"lock,omitempty"`
|
||||
OSName string `json:"osName,omitempty"`
|
||||
IPAddresses []string `json:"ipAddresses,omitempty"`
|
||||
|
||||
// I/O stats
|
||||
NetworkIn int64 `json:"networkIn"`
|
||||
NetworkOut int64 `json:"networkOut"`
|
||||
DiskRead int64 `json:"diskRead"`
|
||||
DiskWrite int64 `json:"diskWrite"`
|
||||
|
||||
// Backup info
|
||||
LastBackup *time.Time `json:"lastBackup,omitempty"`
|
||||
}
|
||||
|
||||
// HostPlatformData contains host-agent specific fields.
|
||||
// Stored in Resource.PlatformData when Type is ResourceTypeHost.
|
||||
type HostPlatformData struct {
|
||||
Platform string `json:"platform,omitempty"` // linux, windows, darwin
|
||||
OSName string `json:"osName,omitempty"` // e.g., "Ubuntu 22.04"
|
||||
OSVersion string `json:"osVersion,omitempty"` // OS version string
|
||||
KernelVersion string `json:"kernelVersion,omitempty"` // Kernel version
|
||||
Architecture string `json:"architecture,omitempty"` // amd64, arm64, etc.
|
||||
CPUCount int `json:"cpuCount,omitempty"` // Number of CPUs
|
||||
LoadAverage []float64 `json:"loadAverage,omitempty"` // 1, 5, 15 minute loads
|
||||
AgentVersion string `json:"agentVersion,omitempty"` // Pulse agent version
|
||||
IsLegacy bool `json:"isLegacy,omitempty"` // Legacy agent indicator
|
||||
Sensors HostSensorSummary `json:"sensors,omitempty"` // Temperature/fan sensors
|
||||
RAID []HostRAIDArray `json:"raid,omitempty"` // RAID arrays
|
||||
DiskIO []DiskIOStats `json:"diskIO,omitempty"` // Per-disk I/O stats
|
||||
Disks []DiskInfo `json:"disks,omitempty"` // Disk usage info
|
||||
Interfaces []NetworkInterface `json:"interfaces,omitempty"` // Network interfaces
|
||||
|
||||
// Token information
|
||||
TokenID string `json:"tokenId,omitempty"`
|
||||
TokenName string `json:"tokenName,omitempty"`
|
||||
TokenHint string `json:"tokenHint,omitempty"`
|
||||
TokenLastUsedAt *time.Time `json:"tokenLastUsedAt,omitempty"`
|
||||
}
|
||||
|
||||
// HostSensorSummary captures sensor readings from a host.
|
||||
type HostSensorSummary struct {
|
||||
TemperatureCelsius map[string]float64 `json:"temperatureCelsius,omitempty"`
|
||||
FanRPM map[string]float64 `json:"fanRpm,omitempty"`
|
||||
Additional map[string]float64 `json:"additional,omitempty"`
|
||||
}
|
||||
|
||||
// HostRAIDArray represents an mdadm RAID array.
|
||||
type HostRAIDArray struct {
|
||||
Device string `json:"device"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Level string `json:"level"`
|
||||
State string `json:"state"`
|
||||
TotalDevices int `json:"totalDevices"`
|
||||
ActiveDevices int `json:"activeDevices"`
|
||||
WorkingDevices int `json:"workingDevices"`
|
||||
FailedDevices int `json:"failedDevices"`
|
||||
SpareDevices int `json:"spareDevices"`
|
||||
UUID string `json:"uuid,omitempty"`
|
||||
Devices []HostRAIDDevice `json:"devices"`
|
||||
RebuildPercent float64 `json:"rebuildPercent"`
|
||||
RebuildSpeed string `json:"rebuildSpeed,omitempty"`
|
||||
}
|
||||
|
||||
// HostRAIDDevice represents a device in a RAID array.
|
||||
type HostRAIDDevice struct {
|
||||
Device string `json:"device"`
|
||||
State string `json:"state"`
|
||||
Slot int `json:"slot"`
|
||||
}
|
||||
|
||||
// DiskIOStats captures I/O statistics for a disk device.
|
||||
type DiskIOStats struct {
|
||||
Device string `json:"device"`
|
||||
ReadBytes uint64 `json:"readBytes,omitempty"`
|
||||
WriteBytes uint64 `json:"writeBytes,omitempty"`
|
||||
ReadOps uint64 `json:"readOps,omitempty"`
|
||||
WriteOps uint64 `json:"writeOps,omitempty"`
|
||||
ReadTimeMs uint64 `json:"readTimeMs,omitempty"`
|
||||
WriteTimeMs uint64 `json:"writeTimeMs,omitempty"`
|
||||
IOTimeMs uint64 `json:"ioTimeMs,omitempty"`
|
||||
}
|
||||
|
||||
// DiskInfo represents disk/partition usage.
|
||||
type DiskInfo struct {
|
||||
Mountpoint string `json:"mountpoint,omitempty"`
|
||||
Device string `json:"device,omitempty"`
|
||||
Type string `json:"type,omitempty"`
|
||||
Total int64 `json:"total"`
|
||||
Used int64 `json:"used"`
|
||||
Free int64 `json:"free"`
|
||||
Usage float64 `json:"usage"`
|
||||
}
|
||||
|
||||
// NetworkInterface represents a network interface.
|
||||
type NetworkInterface struct {
|
||||
Name string `json:"name"`
|
||||
MAC string `json:"mac,omitempty"`
|
||||
Addresses []string `json:"addresses,omitempty"`
|
||||
RXBytes uint64 `json:"rxBytes,omitempty"`
|
||||
TXBytes uint64 `json:"txBytes,omitempty"`
|
||||
SpeedMbps *int64 `json:"speedMbps,omitempty"`
|
||||
}
|
||||
|
||||
// DockerHostPlatformData contains Docker host-specific fields.
|
||||
// Stored in Resource.PlatformData when Type is ResourceTypeDockerHost.
|
||||
type DockerHostPlatformData struct {
|
||||
AgentID string `json:"agentId"`
|
||||
MachineID string `json:"machineId,omitempty"`
|
||||
OS string `json:"os,omitempty"`
|
||||
KernelVersion string `json:"kernelVersion,omitempty"`
|
||||
Architecture string `json:"architecture,omitempty"`
|
||||
Runtime string `json:"runtime,omitempty"` // docker, podman
|
||||
RuntimeVersion string `json:"runtimeVersion,omitempty"`
|
||||
DockerVersion string `json:"dockerVersion,omitempty"`
|
||||
LoadAverage []float64 `json:"loadAverage,omitempty"`
|
||||
AgentVersion string `json:"agentVersion,omitempty"`
|
||||
CPUs int `json:"cpus"`
|
||||
IsLegacy bool `json:"isLegacy,omitempty"`
|
||||
Disks []DiskInfo `json:"disks,omitempty"`
|
||||
Interfaces []NetworkInterface `json:"interfaces,omitempty"`
|
||||
CustomDisplayName string `json:"customDisplayName,omitempty"`
|
||||
Hidden bool `json:"hidden"`
|
||||
PendingUninstall bool `json:"pendingUninstall"`
|
||||
|
||||
// Swarm information
|
||||
Swarm *DockerSwarmInfo `json:"swarm,omitempty"`
|
||||
|
||||
// Token information
|
||||
TokenID string `json:"tokenId,omitempty"`
|
||||
TokenName string `json:"tokenName,omitempty"`
|
||||
TokenHint string `json:"tokenHint,omitempty"`
|
||||
TokenLastUsedAt *time.Time `json:"tokenLastUsedAt,omitempty"`
|
||||
}
|
||||
|
||||
// DockerSwarmInfo captures Docker Swarm membership details.
|
||||
type DockerSwarmInfo struct {
|
||||
NodeID string `json:"nodeId,omitempty"`
|
||||
NodeRole string `json:"nodeRole,omitempty"`
|
||||
LocalState string `json:"localState,omitempty"`
|
||||
ControlAvailable bool `json:"controlAvailable,omitempty"`
|
||||
ClusterID string `json:"clusterId,omitempty"`
|
||||
ClusterName string `json:"clusterName,omitempty"`
|
||||
Scope string `json:"scope,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// DockerContainerPlatformData contains Docker container-specific fields.
|
||||
// Stored in Resource.PlatformData when Type is ResourceTypeDockerContainer.
|
||||
type DockerContainerPlatformData struct {
|
||||
HostID string `json:"hostId"` // Parent Docker host ID
|
||||
HostName string `json:"hostName"` // Parent Docker host name
|
||||
Image string `json:"image"` // Container image
|
||||
State string `json:"state"` // created, running, paused, restarting, exited, dead
|
||||
Status string `json:"status"` // Human-readable status
|
||||
Health string `json:"health"` // healthy, unhealthy, starting, none
|
||||
RestartCount int `json:"restartCount"`
|
||||
ExitCode int `json:"exitCode"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
StartedAt *time.Time `json:"startedAt,omitempty"`
|
||||
FinishedAt *time.Time `json:"finishedAt,omitempty"`
|
||||
Labels map[string]string `json:"labels,omitempty"`
|
||||
Ports []ContainerPort `json:"ports,omitempty"`
|
||||
Networks []ContainerNetwork `json:"networks,omitempty"`
|
||||
|
||||
// Podman-specific
|
||||
Podman *PodmanContainerInfo `json:"podman,omitempty"`
|
||||
}
|
||||
|
||||
// ContainerPort describes a port mapping.
|
||||
type ContainerPort struct {
|
||||
PrivatePort int `json:"privatePort"`
|
||||
PublicPort int `json:"publicPort,omitempty"`
|
||||
Protocol string `json:"protocol"`
|
||||
IP string `json:"ip,omitempty"`
|
||||
}
|
||||
|
||||
// ContainerNetwork describes a container's network attachment.
|
||||
type ContainerNetwork struct {
|
||||
Name string `json:"name"`
|
||||
IPv4 string `json:"ipv4,omitempty"`
|
||||
IPv6 string `json:"ipv6,omitempty"`
|
||||
}
|
||||
|
||||
// PodmanContainerInfo captures Podman-specific container info.
|
||||
type PodmanContainerInfo struct {
|
||||
PodName string `json:"podName,omitempty"`
|
||||
PodID string `json:"podId,omitempty"`
|
||||
Infra bool `json:"infra,omitempty"`
|
||||
ComposeProject string `json:"composeProject,omitempty"`
|
||||
ComposeService string `json:"composeService,omitempty"`
|
||||
}
|
||||
|
||||
// PBSPlatformData contains PBS-specific fields.
|
||||
// Stored in Resource.PlatformData when Type is ResourceTypePBS.
|
||||
type PBSPlatformData struct {
|
||||
Host string `json:"host"`
|
||||
Version string `json:"version"`
|
||||
ConnectionHealth string `json:"connectionHealth"`
|
||||
MemoryUsed int64 `json:"memoryUsed"`
|
||||
MemoryTotal int64 `json:"memoryTotal"`
|
||||
NumDatastores int `json:"numDatastores"`
|
||||
}
|
||||
|
||||
// DatastorePlatformData contains PBS datastore-specific fields.
|
||||
// Stored in Resource.PlatformData when Type is ResourceTypeDatastore.
|
||||
type DatastorePlatformData struct {
|
||||
PBSInstanceID string `json:"pbsInstanceId"`
|
||||
PBSInstanceName string `json:"pbsInstanceName"`
|
||||
Content string `json:"content,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
DeduplicationFactor float64 `json:"deduplicationFactor,omitempty"`
|
||||
}
|
||||
|
||||
// StoragePlatformData contains Proxmox storage-specific fields.
|
||||
// Stored in Resource.PlatformData when Type is ResourceTypeStorage.
|
||||
type StoragePlatformData struct {
|
||||
Instance string `json:"instance"`
|
||||
Node string `json:"node"` // Primary node
|
||||
Nodes []string `json:"nodes,omitempty"` // All nodes (for shared storage)
|
||||
Type string `json:"type"` // zfspool, lvmthin, cephfs, etc.
|
||||
Content string `json:"content"`
|
||||
Shared bool `json:"shared"`
|
||||
Enabled bool `json:"enabled"`
|
||||
Active bool `json:"active"`
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue