From 86cc8f8311255cb74af0aa3aa4a4cfecbfe6eb86 Mon Sep 17 00:00:00 2001 From: Michele Costa Date: Tue, 7 Nov 2023 10:59:43 +0000 Subject: [PATCH] Add DPLL Netlink Collector --- pkg/collectors/contexts/contexts.go | 47 +++- .../devices/{dpll.go => dpll_fs.go} | 30 +-- .../devices/{dpll_test.go => dpll_fs_test.go} | 2 +- pkg/collectors/devices/dpll_netlink.go | 209 ++++++++++++++++++ pkg/collectors/dpll_collector.go | 74 +------ pkg/collectors/dpll_collector_fs.go | 89 ++++++++ pkg/collectors/dpll_collector_netlink.go | 109 +++++++++ pkg/runner/runner.go | 1 + 8 files changed, 476 insertions(+), 85 deletions(-) rename pkg/collectors/devices/{dpll.go => dpll_fs.go} (77%) rename pkg/collectors/devices/{dpll_test.go => dpll_fs_test.go} (97%) create mode 100644 pkg/collectors/devices/dpll_netlink.go create mode 100644 pkg/collectors/dpll_collector_fs.go create mode 100644 pkg/collectors/dpll_collector_netlink.go diff --git a/pkg/collectors/contexts/contexts.go b/pkg/collectors/contexts/contexts.go index 3cd4873f..2736bf40 100644 --- a/pkg/collectors/contexts/contexts.go +++ b/pkg/collectors/contexts/contexts.go @@ -5,14 +5,19 @@ package contexts import ( "fmt" + corev1 "k8s.io/api/core/v1" + "github.com/redhat-partner-solutions/vse-sync-collection-tools/pkg/clients" ) const ( - PTPNamespace = "openshift-ptp" - PTPPodNamePrefix = "linuxptp-daemon-" - PTPContainer = "linuxptp-daemon-container" - GPSContainer = "gpsd" + PTPNamespace = "openshift-ptp" + PTPPodNamePrefix = "linuxptp-daemon-" + PTPContainer = "linuxptp-daemon-container" + GPSContainer = "gpsd" + NetlinkDebugPod = "ptp-dpll-netlink-debug-pod" + NetlinkDebugContainer = "ptp-dpll-netlink-debug-container" + NetlinkDebugContainerImage = "quay.io/jnunez/tools:dpll9.2_dev" ) func GetPTPDaemonContext(clientset *clients.Clientset) (clients.ExecContext, error) { @@ -22,3 +27,37 @@ func GetPTPDaemonContext(clientset *clients.Clientset) (clients.ExecContext, err } return ctx, nil } + +func GetNetlinkContext(clientset *clients.Clientset) (*clients.ContainerCreationExecContext, error) { + hpt := corev1.HostPathDirectory + ctx := clients.NewContainerCreationExecContext( + clientset, + PTPNamespace, + NetlinkDebugPod, + NetlinkDebugContainer, + NetlinkDebugContainerImage, + map[string]string{}, + []string{"sleep", "inf"}, + &corev1.SecurityContext{ + Capabilities: &corev1.Capabilities{ + // Requires NET_ADMIN: having (NET_RAW + NET_BIND_SERVICE + NET_BROADCAST) does not work + // Without NET_ADMIN it will not connect to the netlink interface + // Requires SYS_AMDIN: having every other permission does not work. + // Without SYS_ADMIN lspci does not include the Serial number in the comments thefore can not calculate the clockID + Add: []corev1.Capability{ + "SYS_ADMIN", + "NET_ADMIN", + }, + }, + }, + true, + []*clients.Volume{ + { + Name: "modules", + MountPath: "/lib/modules", + VolumeSource: corev1.VolumeSource{HostPath: &corev1.HostPathVolumeSource{Path: "/lib/modules", Type: &hpt}}, + }, + }, + ) + return ctx, nil +} diff --git a/pkg/collectors/devices/dpll.go b/pkg/collectors/devices/dpll_fs.go similarity index 77% rename from pkg/collectors/devices/dpll.go rename to pkg/collectors/devices/dpll_fs.go index f855efcd..4c7695dd 100644 --- a/pkg/collectors/devices/dpll.go +++ b/pkg/collectors/devices/dpll_fs.go @@ -19,7 +19,7 @@ const ( unitConversionFactor = 100 ) -type DevDPLLInfo struct { +type DevFilesystemDPLLInfo struct { Timestamp string `fetcherKey:"date" json:"timestamp"` EECState string `fetcherKey:"dpll_0_state" json:"eecstate"` PPSState string `fetcherKey:"dpll_1_state" json:"state"` @@ -27,7 +27,7 @@ type DevDPLLInfo struct { } // AnalyserJSON returns the json expected by the analysers -func (dpllInfo *DevDPLLInfo) GetAnalyserFormat() ([]*callbacks.AnalyserFormatType, error) { +func (dpllInfo *DevFilesystemDPLLInfo) GetAnalyserFormat() ([]*callbacks.AnalyserFormatType, error) { formatted := callbacks.AnalyserFormatType{ ID: "dpll/time-error", Data: map[string]any{ @@ -41,14 +41,14 @@ func (dpllInfo *DevDPLLInfo) GetAnalyserFormat() ([]*callbacks.AnalyserFormatTyp } var ( - dpllFetcher map[string]*fetcher.Fetcher + dpllFSFetcher map[string]*fetcher.Fetcher ) func init() { - dpllFetcher = make(map[string]*fetcher.Fetcher) + dpllFSFetcher = make(map[string]*fetcher.Fetcher) } -func postProcessDPLL(result map[string]string) (map[string]any, error) { +func postProcessDPLLFilesystem(result map[string]string) (map[string]any, error) { processedResult := make(map[string]any) offset, err := strconv.ParseFloat(result["dpll_1_offset"], 32) if err != nil { @@ -58,9 +58,9 @@ func postProcessDPLL(result map[string]string) (map[string]any, error) { return processedResult, nil } -// BuildDPLLInfoFetcher popluates the fetcher required for +// BuildFilesystemDPLLInfoFetcher popluates the fetcher required for // collecting the DPLLInfo -func BuildDPLLInfoFetcher(interfaceName string) error { //nolint:dupl // Further dedup risks be too abstract or fragile +func BuildFilesystemDPLLInfoFetcher(interfaceName string) error { //nolint:dupl // Further dedup risks be too abstract or fragile fetcherInst, err := fetcher.FetcherFactory( []*clients.Cmd{dateCmd}, []fetcher.AddCommandArgs{ @@ -85,21 +85,21 @@ func BuildDPLLInfoFetcher(interfaceName string) error { //nolint:dupl // Further log.Errorf("failed to create fetcher for dpll: %s", err.Error()) return fmt.Errorf("failed to create fetcher for dpll: %w", err) } - dpllFetcher[interfaceName] = fetcherInst - fetcherInst.SetPostProcessor(postProcessDPLL) + dpllFSFetcher[interfaceName] = fetcherInst + fetcherInst.SetPostProcessor(postProcessDPLLFilesystem) return nil } -// GetDevDPLLInfo returns the device DPLL info for an interface. -func GetDevDPLLInfo(ctx clients.ExecContext, interfaceName string) (DevDPLLInfo, error) { - dpllInfo := DevDPLLInfo{} - fetcherInst, fetchedInstanceOk := dpllFetcher[interfaceName] +// GetDevDPLLFilesystemInfo returns the device DPLL info for an interface. +func GetDevDPLLFilesystemInfo(ctx clients.ExecContext, interfaceName string) (DevFilesystemDPLLInfo, error) { + dpllInfo := DevFilesystemDPLLInfo{} + fetcherInst, fetchedInstanceOk := dpllFSFetcher[interfaceName] if !fetchedInstanceOk { - err := BuildDPLLInfoFetcher(interfaceName) + err := BuildFilesystemDPLLInfoFetcher(interfaceName) if err != nil { return dpllInfo, err } - fetcherInst, fetchedInstanceOk = dpllFetcher[interfaceName] + fetcherInst, fetchedInstanceOk = dpllFSFetcher[interfaceName] if !fetchedInstanceOk { return dpllInfo, errors.New("failed to create fetcher for DPLLInfo") } diff --git a/pkg/collectors/devices/dpll_test.go b/pkg/collectors/devices/dpll_fs_test.go similarity index 97% rename from pkg/collectors/devices/dpll_test.go rename to pkg/collectors/devices/dpll_fs_test.go index f1daa775..9215a72e 100644 --- a/pkg/collectors/devices/dpll_test.go +++ b/pkg/collectors/devices/dpll_fs_test.go @@ -56,7 +56,7 @@ var _ = Describe("NewContainerContext", func() { ctx, err := clients.NewContainerContext(clientset, "TestNamespace", "Test", "TestContainer") Expect(err).NotTo(HaveOccurred()) - info, err := devices.GetDevDPLLInfo(ctx, "aFakeInterface") + info, err := devices.GetDevDPLLFilesystemInfo(ctx, "aFakeInterface") Expect(err).NotTo(HaveOccurred()) Expect(info.Timestamp).To(Equal("2023-06-16T11:49:47.0584Z")) Expect(info.EECState).To(Equal(eecState)) diff --git a/pkg/collectors/devices/dpll_netlink.go b/pkg/collectors/devices/dpll_netlink.go new file mode 100644 index 00000000..7d4675d8 --- /dev/null +++ b/pkg/collectors/devices/dpll_netlink.go @@ -0,0 +1,209 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +package devices + +import ( + "encoding/json" + "errors" + "fmt" + "strconv" + "strings" + + log "github.com/sirupsen/logrus" + + "github.com/redhat-partner-solutions/vse-sync-collection-tools/pkg/callbacks" + "github.com/redhat-partner-solutions/vse-sync-collection-tools/pkg/clients" + "github.com/redhat-partner-solutions/vse-sync-collection-tools/pkg/fetcher" +) + +var states = map[string]string{ + "unknown": "-1", + "invalid": "0", + "freerun": "1", + "locked": "2", + "locked-ho-acq": "3", + "holdover": "4", +} + +type DevNetlinkDPLLInfo struct { + Timestamp string `fetcherKey:"date" json:"timestamp"` + EECState string `fetcherKey:"eec" json:"eecstate"` + PPSState string `fetcherKey:"pps" json:"state"` +} + +// AnalyserJSON returns the json expected by the analysers +func (dpllInfo *DevNetlinkDPLLInfo) GetAnalyserFormat() ([]*callbacks.AnalyserFormatType, error) { + formatted := callbacks.AnalyserFormatType{ + ID: "dpll/states", + Data: map[string]any{ + "timestamp": dpllInfo.Timestamp, + "eecstate": dpllInfo.EECState, + "state": dpllInfo.PPSState, + }, + } + return []*callbacks.AnalyserFormatType{&formatted}, nil +} + +type NetlinkEntry struct { + LockStatus string `json:"lock-status"` //nolint:tagliatelle // not my choice + Driver string `json:"module-name"` //nolint:tagliatelle // not my choice + ClockType string `json:"type"` //nolint:tagliatelle // not my choice + ClockID int64 `json:"clock-id"` //nolint:tagliatelle // not my choice + ID int `json:"id"` //nolint:tagliatelle // not my choice +} + +// # Example output +// [{'clock-id': 5799633565435100136, +// 'id': 0, +// 'lock-status': 'locked-ho-acq', +// 'mode': 'automatic', +// 'mode-supported': ['automatic'], +// 'module-name': 'ice', +// 'type': 'eec'}, +// {'clock-id': 5799633565435100136, +// 'id': 1, +// 'lock-status': 'locked-ho-acq', +// 'mode': 'automatic', +// 'mode-supported': ['automatic'], +// 'module-name': 'ice', +// 'type': 'pps'}] + +var ( + dpllNetlinkFetcher map[int64]*fetcher.Fetcher + dpllClockIDFetcher map[string]*fetcher.Fetcher +) + +func init() { + dpllNetlinkFetcher = make(map[int64]*fetcher.Fetcher) + dpllClockIDFetcher = make(map[string]*fetcher.Fetcher) +} + +func buildPostProcessDPLLNetlink(clockID int64) fetcher.PostProcessFuncType { + return func(result map[string]string) (map[string]any, error) { + processedResult := make(map[string]any) + + entries := make([]NetlinkEntry, 0) + cleaned := strings.ReplaceAll(result["dpll-netlink"], "'", "\"") + err := json.Unmarshal([]byte(cleaned), &entries) + if err != nil { + log.Errorf("Failed to unmarshal netlink output: %s", err.Error()) + } + + log.Debug("entries: ", entries) + for _, entry := range entries { + if entry.ClockID == clockID { + state, ok := states[entry.LockStatus] + if !ok { + log.Errorf("Unknown state: %s", state) + state = "-1" + } + processedResult[entry.ClockType] = state + } + } + return processedResult, nil + } +} + +// BuildDPLLNetlinkInfoFetcher popluates the fetcher required for +// collecting the DPLLInfo +func BuildDPLLNetlinkInfoFetcher(clockID int64) error { //nolint:dupl // Further dedup risks be too abstract or fragile + fetcherInst, err := fetcher.FetcherFactory( + []*clients.Cmd{dateCmd}, + []fetcher.AddCommandArgs{ + { + Key: "dpll-netlink", + Command: "/linux/tools/net/ynl/cli.py --spec /linux/Documentation/netlink/specs/dpll.yaml --dump device-get", + Trim: true, + }, + }, + ) + if err != nil { + log.Errorf("failed to create fetcher for dpll netlink: %s", err.Error()) + return fmt.Errorf("failed to create fetcher for dpll netlink: %w", err) + } + dpllNetlinkFetcher[clockID] = fetcherInst + fetcherInst.SetPostProcessor(buildPostProcessDPLLNetlink(clockID)) + return nil +} + +// GetDevDPLLInfo returns the device DPLL info for an interface. +func GetDevDPLLNetlinkInfo(ctx clients.ExecContext, clockID int64) (DevNetlinkDPLLInfo, error) { + dpllInfo := DevNetlinkDPLLInfo{} + fetcherInst, fetchedInstanceOk := dpllNetlinkFetcher[clockID] + if !fetchedInstanceOk { + err := BuildDPLLNetlinkInfoFetcher(clockID) + if err != nil { + return dpllInfo, err + } + fetcherInst, fetchedInstanceOk = dpllNetlinkFetcher[clockID] + if !fetchedInstanceOk { + return dpllInfo, errors.New("failed to create fetcher for DPLLInfo using netlink interface") + } + } + err := fetcherInst.Fetch(ctx, &dpllInfo) + if err != nil { + log.Debugf("failed to fetch dpllInfo via netlink: %s", err.Error()) + return dpllInfo, fmt.Errorf("failed to fetch dpllInfo via netlink: %w", err) + } + return dpllInfo, nil +} + +func BuildClockIDFetcher(interfaceName string) error { + fetcherInst, err := fetcher.FetcherFactory( + []*clients.Cmd{dateCmd}, + []fetcher.AddCommandArgs{ + { + Key: "dpll-netlink-clock-id", + Command: fmt.Sprintf( + `export IFNAME=%s; export BUSID=$(readlink /sys/class/net/$IFNAME/device | xargs basename | cut -d ':' -f 2,3);`+ + ` echo $(("16#$(lspci -v | grep $BUSID -A 20 |grep 'Serial Number' | awk '{print $NF}' | tr -d '-')"))`, + interfaceName, + ), + Trim: true, + }, + }, + ) + if err != nil { + log.Errorf("failed to create fetcher for dpll clock ID: %s", err.Error()) + return fmt.Errorf("failed to create fetcher for dpll clock ID: %w", err) + } + fetcherInst.SetPostProcessor(postProcessDPLLNetlinkClockID) + dpllClockIDFetcher[interfaceName] = fetcherInst + return nil +} + +func postProcessDPLLNetlinkClockID(result map[string]string) (map[string]any, error) { + processedResult := make(map[string]any) + clockID, err := strconv.ParseInt(result["dpll-netlink-clock-id"], 10, 64) + if err != nil { + return processedResult, fmt.Errorf("failed to parse int for clock id: %w", err) + } + processedResult["clockID"] = clockID + return processedResult, nil +} + +type NetlinkClockID struct { + Timestamp string `fetcherKey:"date" json:"timestamp"` + ClockID int64 `fetcherKey:"clockID" json:"clockId"` +} + +func GetClockID(ctx clients.ExecContext, interfaceName string) (NetlinkClockID, error) { + clockID := NetlinkClockID{} + fetcherInst, fetchedInstanceOk := dpllClockIDFetcher[interfaceName] + if !fetchedInstanceOk { + err := BuildClockIDFetcher(interfaceName) + if err != nil { + return clockID, err + } + fetcherInst, fetchedInstanceOk = dpllClockIDFetcher[interfaceName] + if !fetchedInstanceOk { + return clockID, errors.New("failed to create fetcher for DPLLInfo using netlink interface") + } + } + err := fetcherInst.Fetch(ctx, &clockID) + if err != nil { + log.Debugf("failed to fetch netlink clockID %s", err.Error()) + return clockID, fmt.Errorf("failed to fetch netlink clockID %w", err) + } + return clockID, nil +} diff --git a/pkg/collectors/dpll_collector.go b/pkg/collectors/dpll_collector.go index 0dfa44a4..1503ea44 100644 --- a/pkg/collectors/dpll_collector.go +++ b/pkg/collectors/dpll_collector.go @@ -3,87 +3,31 @@ package collectors import ( - "errors" "fmt" - "github.com/redhat-partner-solutions/vse-sync-collection-tools/pkg/clients" + log "github.com/sirupsen/logrus" + "github.com/redhat-partner-solutions/vse-sync-collection-tools/pkg/collectors/contexts" "github.com/redhat-partner-solutions/vse-sync-collection-tools/pkg/collectors/devices" - "github.com/redhat-partner-solutions/vse-sync-collection-tools/pkg/utils" ) -type DPLLCollector struct { - *baseCollector - ctx clients.ExecContext - interfaceName string -} - const ( DPLLCollectorName = "DPLL" - DPLLInfo = "dpll-info" ) -// polls for the dpll info then passes it to the callback -func (dpll *DPLLCollector) poll() error { - dpllInfo, err := devices.GetDevDPLLInfo(dpll.ctx, dpll.interfaceName) - - if err != nil { - return fmt.Errorf("failed to fetch %s %w", DPLLInfo, err) - } - err = dpll.callback.Call(&dpllInfo, DPLLInfo) - if err != nil { - return fmt.Errorf("callback failed %w", err) - } - return nil -} - -// Poll collects information from the cluster then -// calls the callback.Call to allow that to persist it -func (dpll *DPLLCollector) Poll(resultsChan chan PollResult, wg *utils.WaitGroupCount) { - defer func() { - wg.Done() - }() - errorsToReturn := make([]error, 0) - err := dpll.poll() - if err != nil { - errorsToReturn = append(errorsToReturn, err) - } - resultsChan <- PollResult{ - CollectorName: DPLLCollectorName, - Errors: errorsToReturn, - } -} - // Returns a new DPLLCollector from the CollectionConstuctor Factory func NewDPLLCollector(constructor *CollectionConstructor) (Collector, error) { ctx, err := contexts.GetPTPDaemonContext(constructor.Clientset) if err != nil { - return &DPLLCollector{}, fmt.Errorf("failed to create DPLLCollector: %w", err) + return &DPLLNetlinkCollector{}, fmt.Errorf("failed to create DPLLCollector: %w", err) } - err = devices.BuildDPLLInfoFetcher(constructor.PTPInterface) - if err != nil { - return &DPLLCollector{}, fmt.Errorf("failed to build fetcher for DPLLInfo %w", err) - } - - collector := DPLLCollector{ - baseCollector: newBaseCollector( - constructor.PollInterval, - false, - constructor.Callback, - ), - ctx: ctx, - interfaceName: constructor.PTPInterface, + dpllFSExists, err := devices.IsDPLLFileSystemPresent(ctx, constructor.PTPInterface) + log.Debug("DPLL FS exists: ", dpllFSExists) + if dpllFSExists && err == nil { + return NewDPLLFilesystemCollector(constructor) + } else { + return NewDPLLNetlinkCollector(constructor) } - - dpllFSExists, err := devices.IsDPLLFileSystemPresent(collector.ctx, collector.interfaceName) - if err != nil { - return &collector, utils.NewRequirementsNotMetError(fmt.Errorf("checking for the DPLL filesystem failed: %w", err)) - } - if !dpllFSExists { - return &collector, utils.NewRequirementsNotMetError(errors.New("filesystem with DPLL stats not present")) - } - - return &collector, nil } func init() { diff --git a/pkg/collectors/dpll_collector_fs.go b/pkg/collectors/dpll_collector_fs.go new file mode 100644 index 00000000..c36d83ec --- /dev/null +++ b/pkg/collectors/dpll_collector_fs.go @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +package collectors + +import ( + "fmt" + + "github.com/redhat-partner-solutions/vse-sync-collection-tools/pkg/clients" + "github.com/redhat-partner-solutions/vse-sync-collection-tools/pkg/collectors/contexts" + "github.com/redhat-partner-solutions/vse-sync-collection-tools/pkg/collectors/devices" + "github.com/redhat-partner-solutions/vse-sync-collection-tools/pkg/utils" +) + +type DPLLFilesystemCollector struct { + *baseCollector + ctx clients.ExecContext + interfaceName string +} + +const ( + DPLLFilesystemCollectorName = "DPLL-Filesystem" + DPLLInfo = "dpll-info-fs" +) + +// Start sets up the collector so it is ready to be polled +func (dpll *DPLLFilesystemCollector) Start() error { + dpll.running = true + return nil +} + +// polls for the dpll info then passes it to the callback +func (dpll *DPLLFilesystemCollector) poll() error { + dpllInfo, err := devices.GetDevDPLLFilesystemInfo(dpll.ctx, dpll.interfaceName) + + if err != nil { + return fmt.Errorf("failed to fetch %s %w", DPLLInfo, err) + } + err = dpll.callback.Call(&dpllInfo, DPLLInfo) + if err != nil { + return fmt.Errorf("callback failed %w", err) + } + return nil +} + +// Poll collects information from the cluster then +// calls the callback.Call to allow that to persist it +func (dpll *DPLLFilesystemCollector) Poll(resultsChan chan PollResult, wg *utils.WaitGroupCount) { + defer func() { + wg.Done() + }() + errorsToReturn := make([]error, 0) + err := dpll.poll() + if err != nil { + errorsToReturn = append(errorsToReturn, err) + } + resultsChan <- PollResult{ + CollectorName: DPLLFilesystemCollectorName, + Errors: errorsToReturn, + } +} + +// CleanUp stops a running collector +func (dpll *DPLLFilesystemCollector) CleanUp() error { + dpll.running = false + return nil +} + +// Returns a new DPLLFilesystemCollector from the CollectionConstuctor Factory +func NewDPLLFilesystemCollector(constructor *CollectionConstructor) (Collector, error) { + ctx, err := contexts.GetPTPDaemonContext(constructor.Clientset) + if err != nil { + return &DPLLFilesystemCollector{}, fmt.Errorf("failed to create DPLLFilesystemCollector: %w", err) + } + err = devices.BuildFilesystemDPLLInfoFetcher(constructor.PTPInterface) + if err != nil { + return &DPLLFilesystemCollector{}, fmt.Errorf("failed to build fetcher for DPLLInfo %w", err) + } + + collector := DPLLFilesystemCollector{ + baseCollector: newBaseCollector( + constructor.PollInterval, + false, + constructor.Callback, + ), + interfaceName: constructor.PTPInterface, + ctx: ctx, + } + return &collector, nil +} diff --git a/pkg/collectors/dpll_collector_netlink.go b/pkg/collectors/dpll_collector_netlink.go new file mode 100644 index 00000000..ffe4ce96 --- /dev/null +++ b/pkg/collectors/dpll_collector_netlink.go @@ -0,0 +1,109 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +package collectors + +import ( + "fmt" + + log "github.com/sirupsen/logrus" + + "github.com/redhat-partner-solutions/vse-sync-collection-tools/pkg/clients" + "github.com/redhat-partner-solutions/vse-sync-collection-tools/pkg/collectors/contexts" + "github.com/redhat-partner-solutions/vse-sync-collection-tools/pkg/collectors/devices" + "github.com/redhat-partner-solutions/vse-sync-collection-tools/pkg/utils" +) + +type DPLLNetlinkCollector struct { + *baseCollector + ctx *clients.ContainerCreationExecContext + interfaceName string + clockID int64 +} + +const ( + DPLLNetlinkCollectorName = "DPLL-Netlink" + DPLLNetlinkInfo = "dpll-info-nl" +) + +// Start sets up the collector so it is ready to be polled +func (dpll *DPLLNetlinkCollector) Start() error { + dpll.running = true + err := dpll.ctx.CreatePodAndWaitForStart() + if err != nil { + return fmt.Errorf("dpll netlink collector failed to start pod: %w", err) + } + log.Debug("dpll.interfaceName: ", dpll.interfaceName) + log.Debug("dpll.ctx: ", dpll.ctx) + clockIDStuct, err := devices.GetClockID(dpll.ctx, dpll.interfaceName) + if err != nil { + return fmt.Errorf("dpll netlink collector failed to find clock id: %w", err) + } + log.Debug("clockIDStuct.ClockID: ", clockIDStuct.ClockID) + err = devices.BuildDPLLNetlinkInfoFetcher(clockIDStuct.ClockID) + if err != nil { + return fmt.Errorf("failed to build fetcher for DPLLNetlinkInfo %w", err) + } + dpll.clockID = clockIDStuct.ClockID + return nil +} + +// polls for the dpll info then passes it to the callback +func (dpll *DPLLNetlinkCollector) poll() error { + dpllInfo, err := devices.GetDevDPLLNetlinkInfo(dpll.ctx, dpll.clockID) + + if err != nil { + return fmt.Errorf("failed to fetch %s %w", DPLLNetlinkInfo, err) + } + err = dpll.callback.Call(&dpllInfo, DPLLNetlinkInfo) + if err != nil { + return fmt.Errorf("callback failed %w", err) + } + return nil +} + +// Poll collects information from the cluster then +// calls the callback.Call to allow that to persist it +func (dpll *DPLLNetlinkCollector) Poll(resultsChan chan PollResult, wg *utils.WaitGroupCount) { + defer func() { + wg.Done() + }() + errorsToReturn := make([]error, 0) + err := dpll.poll() + if err != nil { + errorsToReturn = append(errorsToReturn, err) + } + resultsChan <- PollResult{ + CollectorName: DPLLNetlinkCollectorName, + Errors: errorsToReturn, + } +} + +// CleanUp stops a running collector +func (dpll *DPLLNetlinkCollector) CleanUp() error { + dpll.running = false + err := dpll.ctx.DeletePodAndWait() + if err != nil { + return fmt.Errorf("dpll netlink collector failed to clean up: %w", err) + } + return nil +} + +// Returns a new DPLLNetlinkCollector from the CollectionConstuctor Factory +func NewDPLLNetlinkCollector(constructor *CollectionConstructor) (Collector, error) { + ctx, err := contexts.GetNetlinkContext(constructor.Clientset) + if err != nil { + return &DPLLNetlinkCollector{}, fmt.Errorf("failed to create DPLLNetlinkCollector: %w", err) + } + + collector := DPLLNetlinkCollector{ + baseCollector: newBaseCollector( + constructor.PollInterval, + false, + constructor.Callback, + ), + interfaceName: constructor.PTPInterface, + ctx: ctx, + } + + return &collector, nil +} diff --git a/pkg/runner/runner.go b/pkg/runner/runner.go index cc5d8e9a..e9b5c4b9 100644 --- a/pkg/runner/runner.go +++ b/pkg/runner/runner.go @@ -186,6 +186,7 @@ func (runner *CollectorRunner) start() { for collectorName, collector := range runner.collectorInstances { log.Debugf("start collector %v", collector) err := collector.Start() + log.Info("collector:", collectorName, " start error: ", err) utils.IfErrorExitOrPanic(err) log.Debugf("Spawning collector: %v", collector)