diff --git a/.github/workflows/fmtcheck.yml b/.github/workflows/fmtcheck.yml index 623863a9..4af89409 100644 --- a/.github/workflows/fmtcheck.yml +++ b/.github/workflows/fmtcheck.yml @@ -20,11 +20,16 @@ jobs: disable-sudo: true allowed-endpoints: > github.com:443 + api.github.com:443 + proxy.github.com:443 + raw.githubusercontent.com:443 + objects.githubusercontent.com:443 + proxy.golang.org:443 - name: checkout code uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 - name: setup go uses: actions/setup-go@fac708d6674e30b6ba41289acaab6d4b75aa0753 # v4.0.1 with: - go-version: 1.19 + go-version: 1.21 - name: check fmt run: 'bash -c "diff -u <(echo -n) <(gofmt -d .)"' diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index e8488e9a..dcb6451e 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -22,14 +22,16 @@ jobs: allowed-endpoints: > github.com:443 api.github.com:443 + proxy.github.com:443 raw.githubusercontent.com:443 objects.githubusercontent.com:443 + proxy.golang.org:443 - name: checkout code uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 - name: setup go uses: actions/setup-go@fac708d6674e30b6ba41289acaab6d4b75aa0753 # v4.0.1 with: - go-version: 1.19 + go-version: 1.21 - name: lint uses: golangci/golangci-lint-action@639cd343e1d3b897ff35927a75193d57cfcba299 # v3.6.0 with: diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 977703ea..cd4e9fc3 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -17,7 +17,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - go: [ '1.19', '1.20'] + go: [ '1.19', '1.20', '1.21'] steps: - name: harden runner uses: step-security/harden-runner@55d479fb1c5bcad5a4f9099a5d9f37c8857b2845 # v2.4.1 @@ -26,6 +26,11 @@ jobs: disable-sudo: true allowed-endpoints: > github.com:443 + api.github.com:443 + proxy.github.com:443 + raw.githubusercontent.com:443 + objects.githubusercontent.com:443 + proxy.golang.org:443 - name: checkout code uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 - name: setup go @@ -51,6 +56,11 @@ jobs: disable-sudo: true allowed-endpoints: > github.com:443 + api.github.com:443 + proxy.github.com:443 + raw.githubusercontent.com:443 + objects.githubusercontent.com:443 + proxy.golang.org:443 - name: checkout code uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 - name: setup go @@ -67,7 +77,7 @@ jobs: runs-on: windows-2022 strategy: matrix: - go: [ '1.19' ] + go: [ '1.20', '1.21' ] steps: - name: harden runner uses: step-security/harden-runner@55d479fb1c5bcad5a4f9099a5d9f37c8857b2845 # v2.4.1 @@ -76,6 +86,11 @@ jobs: disable-sudo: true allowed-endpoints: > github.com:443 + api.github.com:443 + proxy.github.com:443 + raw.githubusercontent.com:443 + objects.githubusercontent.com:443 + proxy.golang.org:443 - name: checkout code uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 - name: setup go @@ -98,7 +113,7 @@ jobs: runs-on: windows-2019 strategy: matrix: - go: [ '1.18' ] + go: [ '1.19' ] steps: - name: harden runner uses: step-security/harden-runner@55d479fb1c5bcad5a4f9099a5d9f37c8857b2845 # v2.4.1 @@ -107,6 +122,11 @@ jobs: disable-sudo: true allowed-endpoints: > github.com:443 + api.github.com:443 + proxy.github.com:443 + raw.githubusercontent.com:443 + objects.githubusercontent.com:443 + proxy.golang.org:443 - name: checkout code uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 - name: setup go @@ -145,6 +165,11 @@ jobs: disable-sudo: true allowed-endpoints: > github.com:443 + api.github.com:443 + proxy.github.com:443 + raw.githubusercontent.com:443 + objects.githubusercontent.com:443 + proxy.golang.org:443 - name: checkout code uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 - name: setup go diff --git a/pkg/block/block.go b/pkg/block/block.go index 7a0dbde1..5e75eea6 100644 --- a/pkg/block/block.go +++ b/pkg/block/block.go @@ -233,9 +233,13 @@ type Disk struct { Model string `json:"model"` // SerialNumber is the serial number of the disk. SerialNumber string `json:"serial_number"` - // WWN is the World-wide Number of the disk. + // WWN is the World-wide Name of the disk. // See: https://en.wikipedia.org/wiki/World_Wide_Name WWN string `json:"wwn"` + // WWNNoExtension is the World-wide Name of the disk with any vendor + // extensions excluded. + // See: https://en.wikipedia.org/wiki/World_Wide_Name + WWNNoExtension string `json:"wwnNoExtension"` // Partitions contains an array of pointers to `Partition` structs, one for // each partition on the disk. Partitions []*Partition `json:"partitions"` diff --git a/pkg/block/block_darwin.go b/pkg/block/block_darwin.go index 9b026253..c6b6c266 100644 --- a/pkg/block/block_darwin.go +++ b/pkg/block/block_darwin.go @@ -258,6 +258,7 @@ func (info *Info) load() error { Model: ioregPlist.ModelNumber, SerialNumber: ioregPlist.SerialNumber, WWN: "", + WWNNoExtension: "", Partitions: make([]*Partition, 0, len(disk.Partitions)+len(disk.APFSVolumes)), } diff --git a/pkg/block/block_linux.go b/pkg/block/block_linux.go index 3c24cf86..376b5ff5 100644 --- a/pkg/block/block_linux.go +++ b/pkg/block/block_linux.go @@ -183,6 +183,18 @@ func diskBusPath(paths *linuxpath.Paths, disk string) string { return util.UNKNOWN } +func diskWWNNoExtension(paths *linuxpath.Paths, disk string) string { + info, err := udevInfoDisk(paths, disk) + if err != nil { + return util.UNKNOWN + } + + if wwn, ok := info["ID_WWN"]; ok { + return wwn + } + return util.UNKNOWN +} + func diskWWN(paths *linuxpath.Paths, disk string) string { info, err := udevInfoDisk(paths, disk) if err != nil { @@ -326,6 +338,7 @@ func disks(ctx *context.Context, paths *linuxpath.Paths) []*Disk { model := diskModel(paths, dname) serialNo := diskSerialNumber(paths, dname) wwn := diskWWN(paths, dname) + wwnNoExtension := diskWWNNoExtension(paths, dname) removable := diskIsRemovable(paths, dname) if storageController == STORAGE_CONTROLLER_LOOP && size == 0 { @@ -345,6 +358,7 @@ func disks(ctx *context.Context, paths *linuxpath.Paths) []*Disk { Model: model, SerialNumber: serialNo, WWN: wwn, + WWNNoExtension: wwnNoExtension, } parts := diskPartitions(ctx, paths, dname) diff --git a/pkg/block/block_windows.go b/pkg/block/block_windows.go index be39f6c0..270e19f9 100644 --- a/pkg/block/block_windows.go +++ b/pkg/block/block_windows.go @@ -155,6 +155,7 @@ func (i *Info) load() error { Model: strings.TrimSpace(*diskdrive.Caption), SerialNumber: strings.TrimSpace(*diskdrive.SerialNumber), WWN: util.UNKNOWN, // TODO: add information + WWNNoExtension: util.UNKNOWN, // TODO: add information Partitions: make([]*Partition, 0), } for _, diskpartition := range win32DiskPartitionDescriptions { diff --git a/pkg/cpu/cpu_linux.go b/pkg/cpu/cpu_linux.go index 7ff48741..3ec2e847 100644 --- a/pkg/cpu/cpu_linux.go +++ b/pkg/cpu/cpu_linux.go @@ -22,6 +22,7 @@ import ( var ( regexForCpulCore = regexp.MustCompile("^cpu([0-9]+)$") + onlineFile = "online" ) func (i *Info) load() error { @@ -64,6 +65,10 @@ func processorsGet(ctx *context.Context) []*Processor { continue } + onlineFilePath := filepath.Join(paths.SysDevicesSystemCPU, fmt.Sprintf("cpu%d", lpID), onlineFile) + if util.SafeIntFromFile(ctx, onlineFilePath) == 0 { + continue + } procID := processorIDFromLogicalProcessorID(ctx, lpID) proc, found := procs[procID] if !found { @@ -201,6 +206,10 @@ func CoresForNode(ctx *context.Context, nodeID int) ([]*ProcessorCore, error) { ) continue } + onlineFilePath := filepath.Join(cpuPath, onlineFile) + if util.SafeIntFromFile(ctx, onlineFilePath) == 0 { + continue + } coreIDPath := filepath.Join(cpuPath, "topology", "core_id") coreID := util.SafeIntFromFile(ctx, coreIDPath) core := findCoreByID(coreID) diff --git a/pkg/cpu/cpu_linux_test.go b/pkg/cpu/cpu_linux_test.go index 3c334b57..46b05781 100644 --- a/pkg/cpu/cpu_linux_test.go +++ b/pkg/cpu/cpu_linux_test.go @@ -7,12 +7,16 @@ package cpu_test import ( + "bytes" + "io" "os" "path/filepath" + "strings" "testing" "github.com/jaypipes/ghw/pkg/cpu" "github.com/jaypipes/ghw/pkg/option" + "github.com/jaypipes/ghw/pkg/topology" "github.com/jaypipes/ghw/testdata" ) @@ -71,3 +75,88 @@ func TestArmCPU(t *testing.T) { } } } + +func TestCheckCPUTopologyFilesForOfflineCPU(t *testing.T) { + if _, ok := os.LookupEnv("GHW_TESTING_SKIP_CPU"); ok { + t.Skip("Skipping CPU tests.") + } + + testdataPath, err := testdata.SnapshotsDirectory() + if err != nil { + t.Fatalf("Expected nil err, but got %v", err) + } + + offlineCPUSnapshot := filepath.Join(testdataPath, "linux-amd64-offlineCPUs.tar.gz") + + // Capture stderr + rErr, wErr, err := os.Pipe() + if err != nil { + t.Fatalf("Cannot pipe StdErr. %v", err) + } + os.Stderr = wErr + + info, err := cpu.New(option.WithSnapshot(option.SnapshotOptions{ + Path: offlineCPUSnapshot, + })) + if err != nil { + t.Fatalf("Expected nil err, but got %v", err) + } + if info == nil { + t.Fatalf("Expected non-nil CPUInfo, but got nil") + } + + if len(info.Processors) == 0 { + t.Fatalf("Expected >0 processors but got 0.") + } + wErr.Close() + var bufErr bytes.Buffer + if _, err := io.Copy(&bufErr, rErr); err != nil { + t.Fatalf("Failed to copy data to buffer: %v", err) + } + errorOutput := bufErr.String() + if strings.Contains(errorOutput, "WARNING: failed to read int from file:") { + t.Fatalf("Unexpected warning related to missing files under topology directory was reported") + } +} +func TestNumCoresAmongOfflineCPUs(t *testing.T) { + if _, ok := os.LookupEnv("GHW_TESTING_SKIP_CPU"); ok { + t.Skip("Skipping CPU tests.") + } + + testdataPath, err := testdata.SnapshotsDirectory() + if err != nil { + t.Fatalf("Expected nil err, but got %v", err) + } + + offlineCPUSnapshot := filepath.Join(testdataPath, "linux-amd64-offlineCPUs.tar.gz") + + // Capture stderr + rErr, wErr, err := os.Pipe() + if err != nil { + t.Fatalf("Cannot pipe the StdErr. %v", err) + } + info, err := topology.New(option.WithSnapshot(option.SnapshotOptions{ + Path: offlineCPUSnapshot, + })) + if err != nil { + t.Fatalf("Error determining node topology. %v", err) + } + + if len(info.Nodes) < 1 { + t.Fatal("No nodes found. Must contain one or more nodes") + } + for _, node := range info.Nodes { + if len(node.Cores) < 1 { + t.Fatal("No cores found. Must contain one or more cores") + } + } + wErr.Close() + var bufErr bytes.Buffer + if _, err := io.Copy(&bufErr, rErr); err != nil { + t.Fatalf("Failed to copy data to buffer: %v", err) + } + errorOutput := bufErr.String() + if strings.Contains(errorOutput, "WARNING: failed to read int from file:") { + t.Fatalf("Unexpected warnings related to missing files under topology directory was raised") + } +} diff --git a/testdata/snapshots/linux-amd64-offlineCPUs.tar.gz b/testdata/snapshots/linux-amd64-offlineCPUs.tar.gz new file mode 100644 index 00000000..7e71fa09 Binary files /dev/null and b/testdata/snapshots/linux-amd64-offlineCPUs.tar.gz differ