Skip to content

Commit 0e16f52

Browse files
committed
Add collector to get pci and lsmod data
and some debug to wrapper
1 parent a98647f commit 0e16f52

File tree

12 files changed

+554
-26
lines changed

12 files changed

+554
-26
lines changed

build/packaging/suseconnect-ng.spec

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ Requires: ca-certificates
5656
%endif
5757

5858
Requires: coreutils
59+
Requires: pciutils
5960
Requires: zypper
6061
Requires: util-linux
6162
Recommends: systemd

cmd/suseconnect/suseconnect.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ func main() {
118118
flag.BoolVar(&info, "i", false, "")
119119

120120
flag.Parse()
121+
121122
if version {
122123
fmt.Println(connect.GetShortenedVersion())
123124
os.Exit(0)
@@ -263,6 +264,9 @@ func main() {
263264
fmt.Println(output)
264265
os.Exit(0)
265266
} else if deRegister {
267+
// Need to clear ProfileCache on deregister
268+
// even if dereg does not succeed.
269+
util.DeleteProfileCache()
266270
err := connect.Deregister(api, opts)
267271
if jsonFlag && err != nil {
268272
out := connect.RegisterOut{Success: false, Message: err.Error()}
@@ -276,6 +280,9 @@ func main() {
276280
if jsonFlag {
277281
exitOnError(errors.New("cannot use the json option with the 'cleanup' command"), api, opts)
278282
}
283+
// Need to clear ProfileCache on cleanup
284+
// even if cleanup does not succeed.
285+
util.DeleteProfileCache()
279286
err := connect.Cleanup(opts.BaseURL, opts.FsRoot)
280287
exitOnError(err, api, opts)
281288
} else if rollback {
@@ -285,7 +292,7 @@ func main() {
285292
err := connect.Rollback(api.GetConnection(), opts)
286293
exitOnError(err, api, opts)
287294
} else if info {
288-
sysInfo, err := connect.FetchSystemInformation()
295+
sysInfo, err := connect.FetchSystemInformation("")
289296
exitOnError(err, api, opts)
290297

291298
out, err := json.Marshal(sysInfo)
@@ -348,6 +355,10 @@ func exitOnError(err error, api connect.WrappedAPI, opts *connect.Options) {
348355
if err == nil {
349356
return
350357
}
358+
// If we take an error exit, delete the profile cache
359+
// the worst thing that happens is we will send profile
360+
// data when we don't need to, but that is OK.
361+
util.DeleteProfileCache()
351362
if ze, ok := err.(zypper.ZypperError); ok {
352363
fmt.Println(ze)
353364
os.Exit(ze.ExitCode)

internal/collectors/collectors.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import (
2424
"github.com/SUSE/connect-ng/internal/util"
2525
)
2626

27-
type Result = map[string]interface{}
27+
type Result = util.Result
2828

2929
const (
3030
ARCHITECTURE_X86_64 = "x86_64"

internal/collectors/lsmod.go

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package collectors
2+
3+
import (
4+
"bufio"
5+
"bytes"
6+
"sort"
7+
"strings"
8+
9+
"github.com/SUSE/connect-ng/internal/util"
10+
)
11+
12+
type LSMOD struct {
13+
UpdateDataIDs bool
14+
}
15+
16+
const kernModChecksumFile = "kern-modules.txt"
17+
const lsmodTag = "mod_list"
18+
19+
// process output from lsmod to remove dups and get sorted list of kernel mods.
20+
func getKernelMods(inputStream []byte) ([]string, error) {
21+
scanner := bufio.NewScanner(bytes.NewReader(inputStream))
22+
23+
// Iterate through each line get module name
24+
itemMap := make(map[string]bool)
25+
// Skip header line
26+
scanner.Scan()
27+
for scanner.Scan() {
28+
item := strings.Fields(scanner.Text())[0]
29+
itemMap[item] = true // update item map
30+
}
31+
// Return nil and erroe if errors in scanning
32+
if err := scanner.Err(); err != nil {
33+
return nil, err
34+
}
35+
36+
// Run through module list removing duplicates
37+
var sortedList []string
38+
for module := range itemMap {
39+
sortedList = append(sortedList, module)
40+
}
41+
42+
// Sort the list,
43+
sort.Strings(sortedList)
44+
return sortedList, nil
45+
}
46+
47+
func (lsmod LSMOD) run(arch string) (Result, error) {
48+
util.Debug.Print("lsmod.UpdateDataIDs: ", lsmod.UpdateDataIDs)
49+
modInfo, err := util.Execute([]string{"lsmod"}, nil)
50+
// Should not happen, but if command fails
51+
// send nil Result if module data was unavailable.
52+
if err != nil {
53+
return Result{}, err
54+
}
55+
56+
sortedMods, err := getKernelMods(modInfo)
57+
result, err := util.UpdateCache(lsmod.UpdateDataIDs, lsmodTag, kernModChecksumFile, sortedMods)
58+
59+
return result, err
60+
}

internal/collectors/lsmod_test.go

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
package collectors
2+
3+
import (
4+
"fmt"
5+
"os"
6+
"testing"
7+
8+
"github.com/SUSE/connect-ng/internal/util"
9+
"github.com/stretchr/testify/assert"
10+
)
11+
12+
var lsmodDataBlob util.Profile
13+
var kernModTestData string
14+
15+
func setupLSMODTestData() {
16+
testProfilePath, _ := os.MkdirTemp("/tmp/", "__suseconnect")
17+
util.SetProfileFilePath(testProfilePath + "/")
18+
19+
lsmodDataBlob.ProfileID = "a27b6fd9514de9b56319922c0af28783ceec4d36230e16a32d35b060fa733c33"
20+
21+
lsmodDataBlob.ProfileData = []string{"acpi_tad", "autofs4", "ccp", "dmi_sysfs", "efi_pstore", "hid_generic", "i2c_algo_bit", "i2c_piix4", "i2c_smbus", "input_leds", "ip_tables", "joydev", "k10temp", "lp", "mac_hid", "mc", "msr", "nfnetlink", "nvme", "nvme_core", "parport", "parport_pc", "ppdev", "psmouse", "r8169", "rc_core", "realtek", "sch_fq_codel", "snd_pci_acp3x", "snd_soc_acpi", "soundcore", "usbhid", "x_tables"}
22+
23+
kernModTestData = `Module Size Used by
24+
rc_core 73728 1 cec
25+
snd_soc_acpi 16384 3 snd_sof_amd_acp,snd_acp_config,snd_pci_ps
26+
i2c_piix4 32768 0
27+
mc 81920 5 videodev,snd_usb_audio,videobuf2_v4l2,uvcvideo,videobuf2_common
28+
k10temp 16384 0
29+
i2c_algo_bit 16384 1 amdgpu
30+
i2c_smbus 20480 1 i2c_piix4
31+
soundcore 16384 1 snd
32+
ccp 155648 1 kvm_amd
33+
snd_pci_acp3x 16384 0
34+
input_leds 12288 0
35+
joydev 32768 0
36+
acpi_tad 20480 0
37+
mac_hid 12288 0
38+
sch_fq_codel 24576 4
39+
msr 12288 0
40+
parport_pc 53248 0
41+
ppdev 24576 0
42+
lp 28672 0
43+
parport 73728 3 parport_pc,lp,ppdev
44+
efi_pstore 12288 0
45+
nfnetlink 20480 5 nft_compat,nf_tables,ip_set
46+
dmi_sysfs 24576 0
47+
ip_tables 32768 0
48+
x_tables 65536 9 xt_conntrack,nft_compat,xt_tcpudp,xt_addrtype,xt_CHECKSU,Mxt_set,ipt_REJECT,ip_tables,xt_MASQUERADE
49+
autofs4 57344 2
50+
hid_generic 12288 0
51+
usbhid 77824 0
52+
nvme 61440 2
53+
psmouse 217088 0
54+
r8169 126976 0
55+
nvme_core 225280 3 nvme
56+
realtek 49152 2
57+
`
58+
}
59+
60+
func TestLSMODRunSuccessNoUPdate(t *testing.T) {
61+
assert := assert.New(t)
62+
setupLSMODTestData()
63+
64+
mockUtilExecute(kernModTestData, nil)
65+
expected := Result{lsmodTag: lsmodDataBlob}
66+
67+
collector := LSMOD{UpdateDataIDs: false}
68+
result, err := collector.run(ARCHITECTURE_X86_64)
69+
70+
assert.Equal(expected, result)
71+
assert.Nil(err)
72+
}
73+
74+
func TestLSMODRunSuccessUpdate(t *testing.T) {
75+
assert := assert.New(t)
76+
77+
mockUtilExecute(kernModTestData, nil)
78+
expected := Result{lsmodTag: lsmodDataBlob}
79+
80+
collector := LSMOD{UpdateDataIDs: true}
81+
result, err := collector.run(ARCHITECTURE_X86_64)
82+
83+
assert.Equal(expected, result)
84+
assert.Nil(err)
85+
}
86+
87+
func TestLSMODRunSumsMatch(t *testing.T) {
88+
assert := assert.New(t)
89+
90+
mockUtilExecute(kernModTestData, nil)
91+
92+
collector := LSMOD{UpdateDataIDs: true}
93+
result, err := collector.run(ARCHITECTURE_X86_64)
94+
95+
var expectedDataBlob util.Profile
96+
expectedDataBlob.ProfileID = lsmodDataBlob.ProfileID
97+
expected := Result{lsmodTag: expectedDataBlob}
98+
99+
assert.Equal(expected, result)
100+
assert.Nil(err)
101+
}
102+
103+
func TestLSMODRunFail(t *testing.T) {
104+
assert := assert.New(t)
105+
106+
mockUtilExecute("", fmt.Errorf("forced error"))
107+
expected := Result{}
108+
109+
collector := LSMOD{}
110+
result, err := collector.run(ARCHITECTURE_X86_64)
111+
util.DeleteProfileCache()
112+
113+
assert.Equal(expected, result)
114+
assert.ErrorContains(err, "forced error")
115+
}

internal/collectors/pci.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package collectors
2+
3+
import (
4+
"github.com/SUSE/connect-ng/internal/util"
5+
)
6+
7+
const pciChecksumFile = "pci-devices.txt"
8+
const pciTag = "pci_data"
9+
10+
type PCI struct {
11+
UpdateDataIDs bool
12+
}
13+
14+
func (pci PCI) run(arch string) (Result, error) {
15+
util.Debug.Print("pci.UpdateDataIDs: ", pci.UpdateDataIDs)
16+
output, err := util.Execute([]string{"lspci", "-s", ".0"}, nil)
17+
// Some systems may not have lspci command, so
18+
// if the execute fails,
19+
// returb nil Resukt if PCI data was unavailable.
20+
if err != nil {
21+
return Result{}, err
22+
}
23+
stringOutput := string(output)
24+
result, err := util.UpdateCache(pci.UpdateDataIDs, pciTag, pciChecksumFile, stringOutput)
25+
26+
return result, err
27+
}

internal/collectors/pci_test.go

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
package collectors
2+
3+
import (
4+
"fmt"
5+
"os"
6+
"testing"
7+
8+
"github.com/SUSE/connect-ng/internal/util"
9+
"github.com/stretchr/testify/assert"
10+
)
11+
12+
var pciDataBlob util.Profile
13+
14+
func setupPciTestData() {
15+
testProfilePath, _ := os.MkdirTemp("/tmp/", "__suseconnect")
16+
util.SetProfileFilePath(testProfilePath + "/")
17+
18+
pciDataBlob.ProfileID = "de5b2af84042cbe8298be6864362a99bae3e087fea4efcdad9e33f58fa323185"
19+
20+
pciDataBlob.ProfileData = "00:00.0 Host bridge: Advanced Micro Devices, Inc. [AMD] Family 17h-19h PCIe Root Complex (rev 01)\n00:01.0 Host bridge: Advanced Micro Devices, Inc. [AMD] Family 17h-19h PCIe Dummy Host Bridge (rev 01)\n00:02.0 Host bridge: Advanced Micro Devices, Inc. [AMD] Family 17h-19h PCIe Dummy Host Bridge (rev 01)\n00:03.0 Host bridge: Advanced Micro Devices, Inc. [AMD] Family 17h-19h PCIe Dummy Host Bridge (rev 01)\n00:04.0 Host bridge: Advanced Micro Devices, Inc. [AMD] Family 17h-19h PCIe Dummy Host Bridge (rev 01)\n00:08.0 Host bridge: Advanced Micro Devices, Inc. [AMD] Family 17h-19h PCIe Dummy Host Bridge (rev 01)\n00:14.0 SMBus: Advanced Micro Devices, Inc. [AMD] FCH SMBus Controller (rev 71)\n00:18.0 Host bridge: Advanced Micro Devices, Inc. [AMD] Rembrandt Data Fabric: Device 18h; Function 0\n01:00.0 Non-Volatile memory controller: Micron/Crucial Technology Device 5426 (rev 01)\n02:00.0 Network controller: Intel Corporation Wi-Fi 6 AX200 (rev 1a)\n03:00.0 Ethernet controller: Realtek Semiconductor Co., Ltd. RTL8111/8168/8211/8411 PCI Express Gigabit Ethernet Controller (rev 15)\n04:00.0 Ethernet controller: Realtek Semiconductor Co., Ltd. RTL8111/8168/8211/8411 PCI Express Gigabit Ethernet Controller (rev 15)\n05:00.0 VGA compatible controller: Advanced Micro Devices, Inc. [AMD/ATI] Rembrandt [Radeon 680M] (rev c7)\n06:00.0 USB controller: Advanced Micro Devices, Inc. [AMD] Rembrandt USB4 XHCI controller #8"
21+
}
22+
23+
func TestPCIRunSuccessNoUpdate(t *testing.T) {
24+
assert := assert.New(t)
25+
setupPciTestData()
26+
mockUtilExecute(pciDataBlob.ProfileData.(string), nil)
27+
expected := Result{pciTag: pciDataBlob}
28+
29+
collector := PCI{UpdateDataIDs: false}
30+
result, err := collector.run(ARCHITECTURE_X86_64)
31+
assert.Equal(expected, result)
32+
assert.Nil(err)
33+
}
34+
35+
func TestPCIRunSuccessUpdate(t *testing.T) {
36+
assert := assert.New(t)
37+
38+
mockUtilExecute(pciDataBlob.ProfileData.(string), nil)
39+
expected := Result{pciTag: pciDataBlob}
40+
41+
collector := PCI{UpdateDataIDs: true}
42+
result, err := collector.run(ARCHITECTURE_X86_64)
43+
44+
assert.Equal(expected, result)
45+
assert.Nil(err)
46+
}
47+
48+
func TestPCIRunSumsMatch(t *testing.T) {
49+
assert := assert.New(t)
50+
51+
mockUtilExecute(pciDataBlob.ProfileData.(string), nil)
52+
53+
collector := PCI{UpdateDataIDs: true}
54+
result, err := collector.run(ARCHITECTURE_X86_64)
55+
fmt.Println(result)
56+
57+
var expectedDataBlob util.Profile
58+
expectedDataBlob.ProfileID = pciDataBlob.ProfileID
59+
expected := Result{pciTag: expectedDataBlob}
60+
61+
assert.Equal(expected, result)
62+
assert.Nil(err)
63+
}
64+
65+
func TestPCIRunFail(t *testing.T) {
66+
assert := assert.New(t)
67+
68+
mockUtilExecute("", fmt.Errorf("forced error"))
69+
expected := Result{}
70+
71+
collector := PCI{}
72+
result, err := collector.run(ARCHITECTURE_X86_64)
73+
74+
util.DeleteProfileCache()
75+
assert.Equal(expected, result)
76+
assert.ErrorContains(err, "forced error")
77+
}

0 commit comments

Comments
 (0)