Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(internal/collector): MULTI-1736 implement sysinfo collection on Linux #8

Open
wants to merge 38 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
f8dc390
[Linux] Read Product name and family too
Sploder12 Jan 9, 2025
50fea64
[Linux] Add GPU collection
Sploder12 Jan 10, 2025
de98d8d
[Linux] Add logging
Sploder12 Jan 10, 2025
38f31a5
[Linux] Add CPU collection
Sploder12 Jan 13, 2025
e2822d2
[linux] Add Memory collection
Sploder12 Jan 14, 2025
9dc54f0
Some review changes
Sploder12 Jan 15, 2025
2effe1c
Pairing session on mocking cmds
didrocks Jan 15, 2025
d3c8acf
[linux] Implement tests for missing info
Sploder12 Jan 15, 2025
173cd28
[Linux] Add Block info
Sploder12 Jan 15, 2025
1727f98
Merge branch 'collector_wip' into collector-sysinfo-wip
Sploder12 Jan 16, 2025
0894736
[Linux] Add screen info collection
Sploder12 Jan 16, 2025
753674c
Merge branch 'collector_wip' into collector-sysinfo-wip
Sploder12 Jan 16, 2025
e025b58
Apply style and linting changes
Sploder12 Jan 16, 2025
8960fef
Merge branch 'main' into collector-sysinfo-wip
Sploder12 Jan 21, 2025
b88e18d
Add symlink support to files.CopyDir
Sploder12 Jan 21, 2025
e4cdb91
Add comment to CopySymlink
Sploder12 Jan 22, 2025
f420821
Refactor according to feedback
Sploder12 Jan 22, 2025
7fd6dca
[Linux] Add more tests
Sploder12 Jan 22, 2025
ceb3466
Add GOCOVERDIR to subprocess env
Sploder12 Jan 22, 2025
dfb53cc
[Linux] Add error test cases
Sploder12 Jan 22, 2025
806e3f5
Inherit environment vars for subprocesses
Sploder12 Jan 23, 2025
54c9a79
Address review comments
Sploder12 Jan 27, 2025
8c5ba8c
Separate out common test utilities
Sploder12 Jan 29, 2025
5416721
Remove reliance on environment variable
Sploder12 Jan 29, 2025
5743c20
Use more lenient timeout
Sploder12 Jan 29, 2025
b21a6e7
Merge branch 'main' into collector-sysinfo-wip
Sploder12 Jan 29, 2025
5c35ce6
Add helper for printing logs
Sploder12 Jan 29, 2025
fdcb253
Add test utility to create fake coverage directories for helpers
Sploder12 Jan 30, 2025
6573713
Improve consistency
Sploder12 Feb 3, 2025
87817ff
Separate hardware and software from eachother and sysinfo
Sploder12 Jan 31, 2025
f329f1b
Add test skeleton for sysinfo
Sploder12 Jan 31, 2025
4597dbf
Rename Manager to Collector
Sploder12 Feb 3, 2025
871dfc1
[Linux] Use len check instead of nil check for memory
Sploder12 Feb 3, 2025
6931eee
Merge branch 'main' into collector-sysinfo-wip
Sploder12 Feb 3, 2025
d911c10
[Linux] Cleanup merge
Sploder12 Feb 3, 2025
9f1edd7
Add fileutil tests
Sploder12 Feb 3, 2025
b9be9f7
Add a couple debug logs
Sploder12 Feb 4, 2025
4c3b88e
[Linux] Increase strictness of screen regex output checking
Sploder12 Feb 4, 2025
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
34 changes: 34 additions & 0 deletions internal/cmdutils/cmd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Package cmdutils provides utility functions for running commands.
package cmdutils

import (
"bytes"
"context"
"os"
"os/exec"
"time"
)

// Run executes the command specified by cmd with arguments args using the provided context.
// Returns stdout and stderr output and error code.
func Run(ctx context.Context, cmd string, args ...string) (stdout, stderr *bytes.Buffer, err error) {
stdout = &bytes.Buffer{}
stderr = &bytes.Buffer{}

c := exec.CommandContext(ctx, cmd, args...)
c.Stdout = stdout
c.Stderr = stderr
c.Env = append(c.Env, "LANG=C")
c.Env = append(c.Env, os.Environ()...)
err = c.Run()

return stdout, stderr, err
}

// RunWithTimeout calls Run but a timeout is added to the provided context.
func RunWithTimeout(ctx context.Context, timeout time.Duration, cmd string, args ...string) (stdout, stderr *bytes.Buffer, err error) {
c, cancel := context.WithTimeout(ctx, timeout)
defer cancel()

return Run(c, cmd, args...)
}
27 changes: 24 additions & 3 deletions internal/collector/sysinfo/export_test.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,29 @@
package sysinfo

// WithRoot overrides default root directory of the system.
func WithRoot(root string) Options {
import (
"log/slog"

"github.com/ubuntu/ubuntu-insights/internal/collector/sysinfo/hardware"
"github.com/ubuntu/ubuntu-insights/internal/collector/sysinfo/software"
)

// WithHardwareCollector overrides the default hardware collector.
func WithHardwareCollector(hw CollectorT[hardware.Info]) Options {
return func(o *options) {
o.hw = hw
}
}

// WithSoftwareCollector overrides the default software collector.
func WithSoftwareCollector(sw CollectorT[software.Info]) Options {
return func(o *options) {
o.sw = sw
}
}

// WithLogger overrides the default logger.
func WithLogger(logger slog.Handler) Options {
return func(o *options) {
o.root = root
o.log = slog.New(logger)
}
}
29 changes: 29 additions & 0 deletions internal/collector/sysinfo/hardware/export_linux_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package hardware

// WithRoot overrides default root directory of the system.
func WithRoot(root string) Options {
return func(o *options) {
o.root = root
}
}

// WithCpuInfo overrides default cpu info.
func WithCPUInfo(cmd []string) Options {
return func(o *options) {
o.cpuInfoCmd = cmd
}
}

// WithCpuInfo overrides default blk info.
func WithBlkInfo(cmd []string) Options {
return func(o *options) {
o.lsblkCmd = cmd
}
}

// WithScreenInfo overrides default screen info.
func WithScreenInfo(cmd []string) Options {
return func(o *options) {
o.screenCmd = cmd
}
}
12 changes: 12 additions & 0 deletions internal/collector/sysinfo/hardware/export_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package hardware

import (
"log/slog"
)

// WithLogger overrides the default logger.
func WithLogger(logger slog.Handler) Options {
return func(o *options) {
o.log = slog.New(logger)
}
}
100 changes: 100 additions & 0 deletions internal/collector/sysinfo/hardware/hardware.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
// Package hardware handles collecting "common" hardware information for all insight reports.
package hardware

// Info aggregates hardware info.
type Info struct {
Product product

CPU cpu
GPUs []gpu
Mem memory
Blks []disk
Screens []screen
}

type product map[string]string
type cpu map[string]string
type gpu map[string]string
type memory map[string]int

// DiskInfo contains information of a disk or partition.
type disk struct {
Name string `json:"name"`
Size string `json:"size"`

Partitions []disk `json:"partitions,omitempty"`
}

// Screen contains information for a screen.
type screen struct {
Name string `json:"name"`
PhysicalResolution string `json:"physicalResolution"`
Size string `json:"size"`
Resolution string `json:"resolution"`
RefreshRate string `json:"refreshRate"`
}

// Collector handles dependencies for collecting hardware information.
// Collector implements CollectorT[hardware.Info].
type Collector struct {
opts options
}

// Options are the variadic options available to the Collector.
type Options func(*options)

// New returns a new Collector.
func New(args ...Options) Collector {
// options defaults are platform dependent.
opts := defaultOptions()
for _, opt := range args {
opt(opts)
}

return Collector{
opts: *opts,
}
}

// Collect aggregates the data from all the other hardware collect functions.
func (s Collector) Collect() (info Info, err error) {
s.opts.log.Debug("collecting hardware info")

info.Product, err = s.collectProduct()
if err != nil {
s.opts.log.Warn("failed to collect Product info", "error", err)
info.Product = product{}
}

info.CPU, err = s.collectCPU()
if err != nil {
s.opts.log.Warn("failed to collect CPU info", "error", err)
info.CPU = cpu{}
}

info.GPUs, err = s.collectGPUs()
if err != nil {
s.opts.log.Warn("failed to collect GPU info", "error", err)
info.GPUs = []gpu{}
}

info.Mem, err = s.collectMemory()
if err != nil {
s.opts.log.Warn("failed to collect memory info", "error", err)
info.Mem = memory{}
}

info.Blks, err = s.collectDisks()
if err != nil {
s.opts.log.Warn("failed to collect disk info", "error", err)
info.Blks = []disk{}
}

info.Screens, err = s.collectScreens()
if err != nil {
s.opts.log.Warn("failed to collect screen info", "error", err)
info.Screens = []screen{}
}

return info, nil
}
35 changes: 35 additions & 0 deletions internal/collector/sysinfo/hardware/hardware_darwin.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package hardware

import "log/slog"

type options struct {
log *slog.Logger
}

func defaultOptions() *options {
return &options{}
}

func (s Collector) collectProduct() (product, error) {
return product{}, nil
}

func (s Collector) collectCPU() (cpu, error) {
return cpu{}, nil
}

func (s Collector) collectGPUs() ([]gpu, error) {
return []gpu{}, nil
}

func (s Collector) collectMemory() (memory, error) {
return memory{}, nil
}

func (s Collector) collectDisks() ([]disk, error) {
return []disk{}, nil
}

func (s Collector) collectScreens() ([]screen, error) {
return []screen{}, nil
}
Loading
Loading