Skip to content

Commit

Permalink
Merge branch 'master' into patch-2
Browse files Browse the repository at this point in the history
  • Loading branch information
enoch85 authored Jan 5, 2025
2 parents 5523648 + 9b28ac5 commit e1ef8db
Show file tree
Hide file tree
Showing 15 changed files with 176 additions and 19 deletions.
8 changes: 4 additions & 4 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
run: |
make binary-frontend-test-coverage
- name: Upload coverage
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: coverage
path: ${{ github.workspace }}/webapp/frontend/coverage/lcov.info
Expand Down Expand Up @@ -49,7 +49,7 @@ jobs:
run: |
make binary-clean binary-test-coverage
- name: Upload coverage
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: coverage
path: ${{ github.workspace }}/coverage.txt
Expand All @@ -64,7 +64,7 @@ jobs:
- name: Checkout
uses: actions/checkout@v2
- name: Download coverage reports
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4
with:
name: coverage
- name: Upload coverage reports
Expand Down Expand Up @@ -106,7 +106,7 @@ jobs:
run: |
make binary-clean binary-all
- name: Archive
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v4
with:
name: binaries.zip
path: |
Expand Down
10 changes: 5 additions & 5 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ jobs:
with:
version_metadata_path: ${{ github.event.inputs.version_metadata_path }}
- name: Upload workspace
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: workspace
path: ${{ github.workspace }}/**/*
Expand Down Expand Up @@ -91,7 +91,7 @@ jobs:
- { on: windows-latest, goos: windows, goarch: arm64 }
steps:
- name: Download workspace
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4
with:
name: workspace
- uses: actions/setup-go@v3
Expand All @@ -101,7 +101,7 @@ jobs:
run: |
make binary-clean binary-all
- name: Archive
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v4
with:
name: binaries.zip
path: |
Expand All @@ -114,11 +114,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Download workspace
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4
with:
name: workspace
- name: Download binaries
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4
with:
name: binaries.zip
- name: List
Expand Down
17 changes: 10 additions & 7 deletions collector/pkg/collector/metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,19 @@ import (
"bytes"
"encoding/json"
"fmt"
"net/url"
"os"
"os/exec"
"strings"
"time"

"github.com/analogj/scrutiny/collector/pkg/common/shell"
"github.com/analogj/scrutiny/collector/pkg/config"
"github.com/analogj/scrutiny/collector/pkg/detect"
"github.com/analogj/scrutiny/collector/pkg/errors"
"github.com/analogj/scrutiny/collector/pkg/models"
"github.com/samber/lo"
"github.com/sirupsen/logrus"
"net/url"
"os"
"os/exec"
"strings"
)

type MetricsCollector struct {
Expand Down Expand Up @@ -90,8 +92,9 @@ func (mc *MetricsCollector) Run() error {
//go mc.Collect(&wg, device.WWN, device.DeviceName, device.DeviceType)
mc.Collect(device.WWN, device.DeviceName, device.DeviceType)

// TODO: we may need to sleep for between each call to smartctl -a
//time.Sleep(30 * time.Millisecond)
if mc.config.GetInt("commands.metrics_smartctl_wait") > 0 {
time.Sleep(time.Duration(mc.config.GetInt("commands.metrics_smartctl_wait")) * time.Second)
}
}

//mc.logger.Infoln("Main: Waiting for workers to finish")
Expand All @@ -113,7 +116,7 @@ func (mc *MetricsCollector) Validate() error {
return nil
}

//func (mc *MetricsCollector) Collect(wg *sync.WaitGroup, deviceWWN string, deviceName string, deviceType string) {
// func (mc *MetricsCollector) Collect(wg *sync.WaitGroup, deviceWWN string, deviceName string, deviceType string) {
func (mc *MetricsCollector) Collect(deviceWWN string, deviceName string, deviceType string) {
//defer wg.Done()
if len(deviceWWN) == 0 {
Expand Down
20 changes: 19 additions & 1 deletion collector/pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import (
type configuration struct {
*viper.Viper

deviceOverrides []models.ScanOverride
deviceOverrides []models.ScanOverride
}

//Viper uses the following precedence order. Each item takes precedence over the item below it:
Expand All @@ -47,9 +47,12 @@ func (c *configuration) Init() error {
c.SetDefault("commands.metrics_scan_args", "--scan --json")
c.SetDefault("commands.metrics_info_args", "--info --json")
c.SetDefault("commands.metrics_smart_args", "--xall --json")
c.SetDefault("commands.metrics_smartctl_wait", 0)

//c.SetDefault("collect.short.command", "-a -o on -S on")

c.SetDefault("allow_listed_devices", []string{})

//if you want to load a non-standard location system config file (~/drawbridge.yml), use ReadConfig
c.SetConfigType("yaml")
//c.SetConfigName("drawbridge")
Expand Down Expand Up @@ -186,3 +189,18 @@ func (c *configuration) GetCommandMetricsSmartArgs(deviceName string) string {
}
return c.GetString("commands.metrics_smart_args")
}

func (c *configuration) IsAllowlistedDevice(deviceName string) bool {
allowList := c.GetStringSlice("allow_listed_devices")
if len(allowList) == 0 {
return true
}

for _, item := range allowList {
if item == deviceName {
return true
}
}

return false
}
26 changes: 26 additions & 0 deletions collector/pkg/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,3 +144,29 @@ func TestConfiguration_OverrideDeviceCommands_MetricsInfoArgs(t *testing.T) {
require.Equal(t, "--info --json", testConfig.GetCommandMetricsInfoArgs("/dev/sdb"))
//require.Equal(t, []models.ScanOverride{{Device: "/dev/sda", DeviceType: nil, Commands: {MetricsInfoArgs: "--info --json -T "}}}, scanOverrides)
}

func TestConfiguration_DeviceAllowList(t *testing.T) {
t.Parallel()

t.Run("present", func(t *testing.T) {
testConfig, err := config.Create()
require.NoError(t, err)

require.NoError(t, testConfig.ReadConfig(path.Join("testdata", "allow_listed_devices_present.yaml")))

require.True(t, testConfig.IsAllowlistedDevice("/dev/sda"), "/dev/sda should be allow listed")
require.False(t, testConfig.IsAllowlistedDevice("/dev/sdc"), "/dev/sda should not be allow listed")
})

t.Run("missing", func(t *testing.T) {
testConfig, err := config.Create()
require.NoError(t, err)

// Really just any other config where the key is full missing
require.NoError(t, testConfig.ReadConfig(path.Join("testdata", "override_device_commands.yaml")))

// Anything should be allow listed if the key isnt there
require.True(t, testConfig.IsAllowlistedDevice("/dev/sda"), "/dev/sda should be allow listed")
require.True(t, testConfig.IsAllowlistedDevice("/dev/sdc"), "/dev/sda should be allow listed")
})
}
2 changes: 2 additions & 0 deletions collector/pkg/config/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,6 @@ type Interface interface {
GetDeviceOverrides() []models.ScanOverride
GetCommandMetricsInfoArgs(deviceName string) string
GetCommandMetricsSmartArgs(deviceName string) string

IsAllowlistedDevice(deviceName string) bool
}
14 changes: 14 additions & 0 deletions collector/pkg/config/mock/mock_config.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
allow_listed_devices:
- /dev/sda
- /dev/sdb
5 changes: 5 additions & 0 deletions collector/pkg/detect/detect.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,11 @@ func (d *Detect) TransformDetectedDevices(detectedDeviceConns models.Scan) []mod

deviceFile := strings.ToLower(scannedDevice.Name)

// If the user has defined a device allow list, and this device isnt there, then ignore it
if !d.Config.IsAllowlistedDevice(deviceFile) {
continue
}

detectedDevice := models.Device{
HostId: d.Config.GetString("host.id"),
DeviceType: scannedDevice.Type,
Expand Down
48 changes: 48 additions & 0 deletions collector/pkg/detect/detect_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ func TestDetect_SmartctlScan(t *testing.T) {
fakeConfig.EXPECT().GetDeviceOverrides().AnyTimes().Return([]models.ScanOverride{})
fakeConfig.EXPECT().GetString("commands.metrics_smartctl_bin").AnyTimes().Return("smartctl")
fakeConfig.EXPECT().GetString("commands.metrics_scan_args").AnyTimes().Return("--scan --json")
fakeConfig.EXPECT().IsAllowlistedDevice(gomock.Any()).AnyTimes().Return(true)

fakeShell := mock_shell.NewMockInterface(mockCtrl)
testScanResults, err := os.ReadFile("testdata/smartctl_scan_simple.json")
Expand Down Expand Up @@ -53,6 +54,7 @@ func TestDetect_SmartctlScan_Megaraid(t *testing.T) {
fakeConfig.EXPECT().GetDeviceOverrides().AnyTimes().Return([]models.ScanOverride{})
fakeConfig.EXPECT().GetString("commands.metrics_smartctl_bin").AnyTimes().Return("smartctl")
fakeConfig.EXPECT().GetString("commands.metrics_scan_args").AnyTimes().Return("--scan --json")
fakeConfig.EXPECT().IsAllowlistedDevice(gomock.Any()).AnyTimes().Return(true)

fakeShell := mock_shell.NewMockInterface(mockCtrl)
testScanResults, err := os.ReadFile("testdata/smartctl_scan_megaraid.json")
Expand Down Expand Up @@ -85,6 +87,7 @@ func TestDetect_SmartctlScan_Nvme(t *testing.T) {
fakeConfig.EXPECT().GetDeviceOverrides().AnyTimes().Return([]models.ScanOverride{})
fakeConfig.EXPECT().GetString("commands.metrics_smartctl_bin").AnyTimes().Return("smartctl")
fakeConfig.EXPECT().GetString("commands.metrics_scan_args").AnyTimes().Return("--scan --json")
fakeConfig.EXPECT().IsAllowlistedDevice(gomock.Any()).AnyTimes().Return(true)

fakeShell := mock_shell.NewMockInterface(mockCtrl)
testScanResults, err := os.ReadFile("testdata/smartctl_scan_nvme.json")
Expand Down Expand Up @@ -116,6 +119,7 @@ func TestDetect_TransformDetectedDevices_Empty(t *testing.T) {
fakeConfig.EXPECT().GetDeviceOverrides().AnyTimes().Return([]models.ScanOverride{})
fakeConfig.EXPECT().GetString("commands.metrics_smartctl_bin").AnyTimes().Return("smartctl")
fakeConfig.EXPECT().GetString("commands.metrics_scan_args").AnyTimes().Return("--scan --json")
fakeConfig.EXPECT().IsAllowlistedDevice(gomock.Any()).AnyTimes().Return(true)

detectedDevices := models.Scan{
Devices: []models.ScanDevice{
Expand Down Expand Up @@ -149,6 +153,7 @@ func TestDetect_TransformDetectedDevices_Ignore(t *testing.T) {
fakeConfig.EXPECT().GetDeviceOverrides().AnyTimes().Return([]models.ScanOverride{{Device: "/dev/sda", DeviceType: nil, Ignore: true}})
fakeConfig.EXPECT().GetString("commands.metrics_smartctl_bin").AnyTimes().Return("smartctl")
fakeConfig.EXPECT().GetString("commands.metrics_scan_args").AnyTimes().Return("--scan --json")
fakeConfig.EXPECT().IsAllowlistedDevice(gomock.Any()).AnyTimes().Return(true)

detectedDevices := models.Scan{
Devices: []models.ScanDevice{
Expand Down Expand Up @@ -180,6 +185,7 @@ func TestDetect_TransformDetectedDevices_Raid(t *testing.T) {
fakeConfig.EXPECT().GetString("host.id").AnyTimes().Return("")
fakeConfig.EXPECT().GetString("commands.metrics_smartctl_bin").AnyTimes().Return("smartctl")
fakeConfig.EXPECT().GetString("commands.metrics_scan_args").AnyTimes().Return("--scan --json")
fakeConfig.EXPECT().IsAllowlistedDevice(gomock.Any()).AnyTimes().Return(true)
fakeConfig.EXPECT().GetDeviceOverrides().AnyTimes().Return([]models.ScanOverride{
{
Device: "/dev/bus/0",
Expand Down Expand Up @@ -223,6 +229,7 @@ func TestDetect_TransformDetectedDevices_Simple(t *testing.T) {
fakeConfig.EXPECT().GetString("commands.metrics_smartctl_bin").AnyTimes().Return("smartctl")
fakeConfig.EXPECT().GetString("commands.metrics_scan_args").AnyTimes().Return("--scan --json")
fakeConfig.EXPECT().GetDeviceOverrides().AnyTimes().Return([]models.ScanOverride{{Device: "/dev/sda", DeviceType: []string{"sat+megaraid"}}})
fakeConfig.EXPECT().IsAllowlistedDevice(gomock.Any()).AnyTimes().Return(true)
detectedDevices := models.Scan{
Devices: []models.ScanDevice{
{
Expand Down Expand Up @@ -256,6 +263,7 @@ func TestDetect_TransformDetectedDevices_WithoutDeviceTypeOverride(t *testing.T)
fakeConfig.EXPECT().GetString("commands.metrics_smartctl_bin").AnyTimes().Return("smartctl")
fakeConfig.EXPECT().GetString("commands.metrics_scan_args").AnyTimes().Return("--scan --json")
fakeConfig.EXPECT().GetDeviceOverrides().AnyTimes().Return([]models.ScanOverride{{Device: "/dev/sda"}})
fakeConfig.EXPECT().IsAllowlistedDevice(gomock.Any()).AnyTimes().Return(true)
detectedDevices := models.Scan{
Devices: []models.ScanDevice{
{
Expand Down Expand Up @@ -302,6 +310,46 @@ func TestDetect_TransformDetectedDevices_WhenDeviceNotDetected(t *testing.T) {
require.Equal(t, "ata", transformedDevices[0].DeviceType)
}

func TestDetect_TransformDetectedDevices_AllowListFilters(t *testing.T) {
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()

fakeConfig := mock_config.NewMockInterface(mockCtrl)
fakeConfig.EXPECT().GetString("host.id").AnyTimes().Return("")
fakeConfig.EXPECT().GetString("commands.metrics_smartctl_bin").AnyTimes().Return("smartctl")
fakeConfig.EXPECT().GetString("commands.metrics_scan_args").AnyTimes().Return("--scan --json")
fakeConfig.EXPECT().GetDeviceOverrides().AnyTimes().Return([]models.ScanOverride{{Device: "/dev/sda", DeviceType: []string{"sat+megaraid"}}})
fakeConfig.EXPECT().IsAllowlistedDevice("/dev/sda").Return(true)
fakeConfig.EXPECT().IsAllowlistedDevice("/dev/sdb").Return(false)
detectedDevices := models.Scan{
Devices: []models.ScanDevice{
{
Name: "/dev/sda",
InfoName: "/dev/sda",
Protocol: "ata",
Type: "ata",
},
{
Name: "/dev/sdb",
InfoName: "/dev/sdb",
Protocol: "ata",
Type: "ata",
},
},
}

d := detect.Detect{
Config: fakeConfig,
}

// test
transformedDevices := d.TransformDetectedDevices(detectedDevices)

// assert
require.Equal(t, 1, len(transformedDevices))
require.Equal(t, "sda", transformedDevices[0].DeviceName)
}

func TestDetect_SmartCtlInfo(t *testing.T) {
t.Run("should report nvme info", func(t *testing.T) {
ctrl := gomock.NewController(t)
Expand Down
3 changes: 3 additions & 0 deletions docker/example.hubspoke.docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ services:
environment:
COLLECTOR_API_ENDPOINT: 'http://web:8080'
COLLECTOR_HOST_ID: 'scrutiny-collector-hostname'
# If true forces the collector to run on startup (cron will be started after the collector completes)
# see: https://github.com/AnalogJ/scrutiny/blob/master/docs/TROUBLESHOOTING_DEVICE_COLLECTOR.md#collector-trigger-on-startup
COLLECTOR_RUN_STARTUP: false
depends_on:
web:
condition: service_healthy
Expand Down
4 changes: 2 additions & 2 deletions docs/TESTERS.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Thankfully the following users have been gracious enough to test/validate Scruti
| Architecture Name | Binaries | Docker |
| --- | --- | --- |
| linux-amd64 | -- | @feroxy @rshxyz |
| linux-amd64 | @TizzAmmazz | @feroxy @rshxyz |
| linux-arm-5 | -- | |
| linux-arm-6 | -- | |
| linux-arm-7 | @Zorlin | @martini1992 |
Expand All @@ -17,4 +17,4 @@ Thankfully the following users have been gracious enough to test/validate Scruti
| macos-amd64 | -- | -- |
| macos-arm64 | -- | -- |
| windows-amd64 | @gabrielv33 | -- |
| windows-arm64 | -- | -- |
| windows-arm64 | -- | -- |
8 changes: 8 additions & 0 deletions docs/TROUBLESHOOTING_DOCKER.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,11 @@ So changing from `master-omnibus -> latest` will be the same thing for all inten
> NOTE: Previously, there was a `automated cron build` that ran on the `master` and `beta` branches.
They used to trigger a `nightly` build, even if nothing has changed on the branch. This has a couple of benefits, but one is to
ensure that there's no broken external dependencies in our (unchanged) code. This `nightly` build no longer updates the `master-omnibus` tag.

# Running Docker `rootless`

To avoid that the container(s) restart when you installed Docker as `rootless` you need to isssue the following commands to allow the session to stay alive even after you close your (SSH) sesssion:

`sudo loginctl enable-linger $(whoami)`

`systemctl --user enable docker`
Loading

0 comments on commit e1ef8db

Please sign in to comment.