Skip to content

Commit

Permalink
[agent] enable basic metric collection and exporter
Browse files Browse the repository at this point in the history
  • Loading branch information
Frostman committed Apr 28, 2024
1 parent 7bd61ff commit dcadc9c
Show file tree
Hide file tree
Showing 12 changed files with 2,974 additions and 116 deletions.
280 changes: 272 additions & 8 deletions api/agent/v1alpha2/agent_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package v1alpha2
import (
"sort"

"github.com/pkg/errors"
"go.githedgehog.com/fabric/api/meta"
vpcapi "go.githedgehog.com/fabric/api/vpc/v1alpha2"
wiringapi "go.githedgehog.com/fabric/api/wiring/v1alpha2"
Expand Down Expand Up @@ -126,16 +127,279 @@ type AgentStatus struct {
LastAppliedTime metav1.Time `json:"lastAppliedTime,omitempty"`
// Generation of the last successful configuration application
LastAppliedGen int64 `json:"lastAppliedGen,omitempty"`
// Information about the switch and NOS
NOSInfo NOSInfo `json:"nosInfo,omitempty"`
// Detailed switch state updated with each heartbeat
State SwitchState `json:"state,omitempty"`
// Status updates from the agent
StatusUpdates []ApplyStatusUpdate `json:"statusUpdates,omitempty"`
// Conditions of the agent, includes readiness marker for use with kubectl wait
Conditions []metav1.Condition `json:"conditions"`
}

// NOSInfo contains information about the switch and NOS received from the switch itself by the agent
type NOSInfo struct {
type SwitchState struct {
// Information about the switch and NOS
NOS SwitchStateNOS `json:"nos,omitempty"`
// Switch interfaces state (incl. physical, management and port channels)
Interfaces map[string]SwitchStateInterface `json:"interfaces,omitempty"`
// Breakout ports state (port -> breakout state)
Breakouts map[string]SwitchStateBreakout `json:"breakouts,omitempty"`
// State of all BGP neighbors (VRF -> neighbor address -> state)
BGPNeighbors map[string]map[string]SwitchStateBGPNeighbor `json:"bgpNeighbors,omitempty"`
// State of the switch platform (fans, PSUs, sensors)
Platform SwitchStatePlatform `json:"platform,omitempty"`
}

type SwitchStateInterface struct {
Enabled bool `json:"enabled,omitempty"`
AdminStatus AdminStatus `json:"adminStatus,omitempty"`
OperStatus OperStatus `json:"operStatus,omitempty"`
MAC string `json:"mac,omitempty"`
LastChange metav1.Time `json:"lastChanged,omitempty"`
Counters *SwitchStateInterfaceCounters `json:"counters,omitempty"`
Transceiver *SwitchStateTransceiver `json:"transceiver,omitempty"`
LLDPNeighbors []SwitchStateLLDPNeighbor `json:"lldpNeighbors,omitempty"`
}

type SwitchStateInterfaceCounters struct {
InBitsPerSecond float64 `json:"inBitsPerSecond,omitempty"`
InDiscards uint64 `json:"inDiscards,omitempty"`
InErrors uint64 `json:"inErrors,omitempty"`
InPktsPerSecond float64 `json:"inPktsPerSecond,omitempty"`
InUtilization uint8 `json:"inUtilization,omitempty"`
LastClear metav1.Time `json:"lastClear,omitempty"`
OutBitsPerSecond float64 `json:"outBitsPerSecond,omitempty"`
OutDiscards uint64 `json:"outDiscards,omitempty"`
OutErrors uint64 `json:"outErrors,omitempty"`
OutPktsPerSecond float64 `json:"outPktsPerSecond,omitempty"`
OutUtilization uint8 `json:"outUtilization,omitempty"`
}

type AdminStatus string

const (
AdminStatusUnset AdminStatus = ""
AdminStatusUp AdminStatus = "up"
AdminStatusDown AdminStatus = "down"
AdminStatusTesting AdminStatus = "testing"
)

func (a AdminStatus) ID() (uint8, error) {
switch a {
case AdminStatusUnset:
return 0, nil
case AdminStatusUp:
return 1, nil
case AdminStatusDown:
return 2, nil
case AdminStatusTesting:
return 3, nil
default:
return 0, errors.Errorf("unknown AdminStatus %s", a)
}
}

type OperStatus string

const (
OperStatusUnset OperStatus = ""
OperStatusUp OperStatus = "up"
OperStatusDown OperStatus = "down"
OperStatusTesting OperStatus = "testing"
OperStatusUnknown OperStatus = "unknown"
OperStatusDormant OperStatus = "dormant"
OperStatusNotPresent OperStatus = "notPresent"
OperStatusLowerLayerDown OperStatus = "lowerLayerDown"
)

func (o OperStatus) ID() (uint8, error) {
switch o {
case OperStatusUnset:
return 0, nil
case OperStatusUp:
return 1, nil
case OperStatusDown:
return 2, nil
case OperStatusTesting:
return 3, nil
case OperStatusUnknown:
return 4, nil
case OperStatusDormant:
return 5, nil
case OperStatusNotPresent:
return 6, nil
case OperStatusLowerLayerDown:
return 7, nil
default:
return 0, errors.Errorf("unknown OperStatus %s", o)
}
}

type SwitchStateTransceiver struct {
Description string `json:"description,omitempty"`
CableClass string `json:"cableClass,omitempty"`
FormFactor string `json:"formFactor,omitempty"`
ConnectorType string `json:"connectorType,omitempty"`
Present string `json:"present,omitempty"`
CableLength float64 `json:"cableLength,omitempty"`
OperStatus string `json:"operStatus,omitempty"`
Temperature float64 `json:"temperature,omitempty"`
Voltage float64 `json:"voltage,omitempty"`
SerialNumber string `json:"serialNumber,omitempty"`
Vendor string `json:"vendor,omitempty"`
VendorPart string `json:"vendorPart,omitempty"`
VendorOUI string `json:"vendorOUI,omitempty"`
VendorRev string `json:"vendorRev,omitempty"`
}

type SwitchStateBreakout struct {
Mode string `json:"mode,omitempty"`
Members []string `json:"members,omitempty"`
Status string `json:"status,omitempty"`
}

type SwitchStateLLDPNeighbor struct {
ChassisID string `json:"chassisID,omitempty"`
SystemName string `json:"systemName,omitempty"`
SystemDescription string `json:"systemDescription,omitempty"`
PortID string `json:"portID,omitempty"`
PortDescription string `json:"portDescription,omitempty"`

// LLDP-MED inventory

Manufacturer string `json:"manufacturer,omitempty"`
Model string `json:"model,omitempty"`
SerialNumber string `json:"serialNumber,omitempty"`
}

type SwitchStateBGPNeighbor struct {
ConnectionsDropped uint64 `json:"connectionsDropped,omitempty"`
Enabled bool `json:"enabled,omitempty"`
EstablishedTransitions uint64 `json:"establishedTransitions,omitempty"`
LastEstablished metav1.Time `json:"lastEstablished,omitempty"`
LastRead metav1.Time `json:"lastRead,omitempty"`
LastResetReason string `json:"lastResetReason,omitempty"`
LastResetTime metav1.Time `json:"lastResetTime,omitempty"`
LastWrite metav1.Time `json:"lastWrite,omitempty"`
LocalAS uint32 `json:"localAS,omitempty"`
Messages BGPMessages `json:"messages,omitempty"`
PeerAS uint32 `json:"peerAS,omitempty"`
PeerGroup string `json:"peerGroup,omitempty"`
PeerPort uint16 `json:"peerPort,omitempty"`
PeerType BGPPeerType `json:"peerType,omitempty"`
RemoteRouterID string `json:"remoteRouterID,omitempty"`
SessionState BGPNeighborSessionState `json:"sessionState,omitempty"`
ShutdownMessage string `json:"shutdownMessage,omitempty"`
Prefixes map[string]SwitchStateBGPNeighborPrefixes `json:"prefixes,omitempty"`
}

type SwitchStateBGPNeighborPrefixes struct {
Received uint32 `json:"received,omitempty"`
ReceivedPrePolicy uint32 `json:"receivedPrePolicy,omitempty"`
Sent uint32 `json:"sent,omitempty"`
}

type BGPNeighborSessionState string

const (
BGPNeighborSessionStateUnset BGPNeighborSessionState = ""
BGPNeighborSessionStateIdle BGPNeighborSessionState = "idle"
BGPNeighborSessionStateConnect BGPNeighborSessionState = "connect"
BGPNeighborSessionStateActive BGPNeighborSessionState = "active"
BGPNeighborSessionStateOpenSent BGPNeighborSessionState = "openSent"
BGPNeighborSessionStateOpenConfirm BGPNeighborSessionState = "openConfirm"
BGPNeighborSessionStateEstablished BGPNeighborSessionState = "established"
)

func (b BGPNeighborSessionState) ID() (uint8, error) {
switch b {
case BGPNeighborSessionStateUnset:
return 0, nil
case BGPNeighborSessionStateIdle:
return 1, nil
case BGPNeighborSessionStateConnect:
return 2, nil
case BGPNeighborSessionStateActive:
return 3, nil
case BGPNeighborSessionStateOpenSent:
return 4, nil
case BGPNeighborSessionStateOpenConfirm:
return 5, nil
case BGPNeighborSessionStateEstablished:
return 6, nil
default:
return 0, errors.Errorf("unknown BGPNeighborSessionState %s", b)
}
}

type BGPPeerType string

const (
BGPPeerTypeUnset BGPPeerType = ""
BGPPeerTypeInternal BGPPeerType = "internal"
BGPPeerTypeExternal BGPPeerType = "external"
)

func (b BGPPeerType) ID() (uint8, error) {
switch b {
case BGPPeerTypeUnset:
return 0, nil
case BGPPeerTypeInternal:
return 1, nil
case BGPPeerTypeExternal:
return 2, nil
default:
return 0, errors.Errorf("unknown BGPPeerType %s", b)
}
}

type BGPMessages struct {
Received BGPMessagesCounters `json:"received,omitempty"`
Sent BGPMessagesCounters `json:"sent,omitempty"`
}

type BGPMessagesCounters struct {
Capability uint64 `json:"capability,omitempty"`
Keepalive uint64 `json:"keepalive,omitempty"`
Notification uint64 `json:"notification,omitempty"`
Open uint64 `json:"open,omitempty"`
RouteRefresh uint64 `json:"routeRefresh,omitempty"`
Update uint64 `json:"update,omitempty"`
}

type SwitchStatePlatform struct {
Fans map[string]SwitchStatePlatformFan `json:"fans,omitempty"`
PSUs map[string]SwitchStatePlatformPSU `json:"psus,omitempty"`
Temperatures map[string]SwitchStatePlatformTemperature `json:"temperature,omitempty"`
}

type SwitchStatePlatformFan struct {
Direction string `json:"direction,omitempty"`
Speed float64 `json:"speed,omitempty"`
Presense bool `json:"presense,omitempty"`
Status bool `json:"status,omitempty"`
}

type SwitchStatePlatformPSU struct {
InputCurrent float64 `json:"inputCurrent,omitempty"`
InputPower float64 `json:"inputPower,omitempty"`
InputVoltage float64 `json:"inputVoltage,omitempty"`
OutputCurrent float64 `json:"outputCurrent,omitempty"`
OutputPower float64 `json:"outputPower,omitempty"`
OutputVoltage float64 `json:"outputVoltage,omitempty"`
Presense bool `json:"presense,omitempty"`
Status bool `json:"status,omitempty"`
}

type SwitchStatePlatformTemperature struct {
Temperature float64 `json:"temperature,omitempty"`
Alarms string `json:"alarms,omitempty"`
HighThreshold float64 `json:"highThreshold,omitempty"`
CriticalHighThreshold float64 `json:"criticalHighThreshold,omitempty"`
LowThreshold float64 `json:"lowThreshold,omitempty"`
CriticalLowThreshold float64 `json:"criticalLowThreshold,omitempty"`
}

// SwitchStateNOS contains information about the switch and NOS received from the switch itself by the agent
type SwitchStateNOS struct {
// ASIC name, such as "broadcom" or "vs"
AsicVersion string `json:"asicVersion,omitempty"`
// NOS build commit
Expand Down Expand Up @@ -167,22 +431,22 @@ type NOSInfo struct {
// NOS software version, such as "4.2.0-Enterprise_Base"
SoftwareVersion string `json:"softwareVersion,omitempty"`
// Switch uptime, such as "21:21:27 up 1 day, 23:26, 0 users, load average: 1.92, 1.99, 2.00 "
UpTime string `json:"upTime,omitempty"`
Uptime string `json:"uptime,omitempty"`
}

// +kubebuilder:object:root=true
// +kubebuilder:subresource:status
// +kubebuilder:resource:categories=hedgehog;fabric,shortName=ag
// +kubebuilder:printcolumn:name="Role",type=string,JSONPath=`.spec.role`,priority=0
// +kubebuilder:printcolumn:name="Descr",type=string,JSONPath=`.spec.description`,priority=0
// +kubebuilder:printcolumn:name="HWSKU",type=string,JSONPath=`.status.nosInfo.hwskuVersion`,priority=1
// +kubebuilder:printcolumn:name="ASIC",type=string,JSONPath=`.status.nosInfo.asicVersion`,priority=1
// +kubebuilder:printcolumn:name="HWSKU",type=string,JSONPath=`.status.state.nos.hwskuVersion`,priority=1
// +kubebuilder:printcolumn:name="ASIC",type=string,JSONPath=`.status.state.nos.asicVersion`,priority=1
// +kubebuilder:printcolumn:name="Heartbeat",type=date,JSONPath=`.status.lastHeartbeat`,priority=1
// +kubebuilder:printcolumn:name="Applied",type=date,JSONPath=`.status.lastAppliedTime`,priority=0
// +kubebuilder:printcolumn:name="AppliedG",type=string,JSONPath=`.status.lastAppliedGen`,priority=0
// +kubebuilder:printcolumn:name="CurrentG",type=string,JSONPath=`.metadata.generation`,priority=0
// +kubebuilder:printcolumn:name="Version",type=string,JSONPath=`.status.version`,priority=0
// +kubebuilder:printcolumn:name="Software",type=string,JSONPath=`.status.nosInfo.softwareVersion`,priority=1
// +kubebuilder:printcolumn:name="Software",type=string,JSONPath=`.status.state.nos.softwareVersion`,priority=1
// +kubebuilder:printcolumn:name="Attempt",type=date,JSONPath=`.status.lastAttemptTime`,priority=2
// +kubebuilder:printcolumn:name="AttemptG",type=string,JSONPath=`.status.lastAttemptGen`,priority=2
// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp`,priority=10
Expand Down
Loading

0 comments on commit dcadc9c

Please sign in to comment.