Skip to content

Commit 42fd423

Browse files
committed
Implement basic structures and testing over ssh connection
Signed-off-by: Christopher Meis <christopher.meis@9elements.com>
1 parent a787c39 commit 42fd423

File tree

24 files changed

+1267
-99
lines changed

24 files changed

+1267
-99
lines changed

Taskfile.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ tasks:
1212
matrix:
1313
OS: ['linux']
1414
ARCH: ['amd64', 'arm', 'arm64']
15-
cmd: GOOS="{{.ITEM.OS}}" GOARCH="{{.ITEM.ARCH}}" go build -ldflags="-s -w" -o "bin/bmc-test-go-{{.ITEM.OS}}-{{.ITEM.ARCH}}-{{.SEMVER}}"
15+
cmd: GOOS="{{.ITEM.OS}}" GOARCH="{{.ITEM.ARCH}}" go build -ldflags="-s -w" -o "bin/bmc-test-go-{{.ITEM.OS}}-{{.ITEM.ARCH}}-{{.SEMVER}}" ./cmds/openbmc-tests
1616

1717
lint:
1818
desc: Run linters

cmds/openbmc-tests/cmdline.go

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package main
2+
3+
import (
4+
"flag"
5+
)
6+
7+
var (
8+
runSingleCmd string = "single"
9+
runSuiteCmd string = "suite"
10+
runAllCmd string = "run-all"
11+
cfgCheckCmd string = "cfg-check"
12+
)
13+
14+
type flags struct {
15+
cmd string
16+
configPath string
17+
execEnv string
18+
testName string
19+
}
20+
21+
func parseFlags(args []string) (*flags, error) {
22+
f := &flags{
23+
cmd: args[0],
24+
}
25+
26+
cfgCheckFS := flag.NewFlagSet(cfgCheckCmd, flag.ExitOnError)
27+
cfgCheckFS.StringVar(&f.configPath, "config", "contrib/example_config.yaml", "Path to device specific test case configuration file")
28+
29+
runSingleFS := flag.NewFlagSet("run-single", flag.ExitOnError)
30+
runSingleFS.StringVar(&f.testName, "testname", "", "Run a single test with 'testname'. No default")
31+
runSingleFS.StringVar(&f.execEnv, "exec-env", "remote", "Run the test locally or remotely '<local, remote>'. Default: remote")
32+
runSingleFS.StringVar(&f.configPath, "config", "contrib/example_config.yaml", "Path to device specific test case configuration file")
33+
34+
runSuiteFS := flag.NewFlagSet("suite", flag.ExitOnError)
35+
runSuiteFS.StringVar(&f.execEnv, "exec-env", "remote", "Run the test locally or remotely '<local, remote>'. Default: remote")
36+
runSuiteFS.StringVar(&f.configPath, "config", "contrib/example_config.yaml", "Path to device specific test case configuration file")
37+
38+
runAllFS := flag.NewFlagSet("run-all", flag.ExitOnError)
39+
runAllFS.StringVar(&f.execEnv, "exec-env", "remote", "Run the test locally or remotely '<local, remote>'. Default: remote")
40+
runAllFS.StringVar(&f.configPath, "config", "contrib/example_config.yaml", "Path to device specific test case configuration file")
41+
42+
var err error
43+
switch args[0] {
44+
case cfgCheckCmd:
45+
err = cfgCheckFS.Parse(args[1:])
46+
case runSingleCmd:
47+
err = runSingleFS.Parse(args[1:])
48+
case runSuiteCmd:
49+
err = runSuiteFS.Parse(args[1:])
50+
case runAllCmd:
51+
err = runAllFS.Parse(args[1:])
52+
default:
53+
cfgCheckFS.Usage()
54+
runSingleFS.Usage()
55+
runSuiteFS.Usage()
56+
runAllFS.Usage()
57+
}
58+
if err != nil {
59+
return nil, err
60+
}
61+
62+
return f, nil
63+
}

cmds/openbmc-tests/main.go

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
// SPDX-License-Identifier: BSD-3-Clause
2+
3+
// Package main implements the core logic
4+
package main
5+
6+
import (
7+
"fmt"
8+
"log"
9+
"os"
10+
11+
"github.com/9elements/bmc-test-go/pkg/bmc"
12+
"github.com/9elements/bmc-test-go/pkg/configuration"
13+
"github.com/9elements/bmc-test-go/pkg/tests"
14+
"github.com/9elements/bmc-test-go/pkg/tests/ipmi"
15+
)
16+
17+
func runAll(bmc *bmc.BMC, cfg *configuration.Config) error {
18+
ipmiPre := &ipmi.IPMISDRPrecondition{}
19+
if err := ipmiPre.Run(bmc); err != nil {
20+
return err
21+
}
22+
23+
tests := tests.AllTests()
24+
if len(tests) < 1 {
25+
return fmt.Errorf("no tests to execute")
26+
}
27+
28+
for _, test := range tests {
29+
log.Printf("Running: %s", test.Name())
30+
if !test.Run(bmc, cfg, ipmiPre) {
31+
log.Printf("test: %s failed: %s", test.Name(), test.ErrorText())
32+
continue
33+
}
34+
}
35+
return nil
36+
}
37+
38+
func runSingle(testname string, bmc *bmc.BMC, cfg *configuration.Config) error {
39+
ipmiPre := &ipmi.IPMISDRPrecondition{}
40+
if err := ipmiPre.Run(bmc); err != nil {
41+
return err
42+
}
43+
44+
tests := tests.AllTests()
45+
if len(tests) < 1 {
46+
return fmt.Errorf("no tests to execute")
47+
}
48+
49+
for _, test := range tests {
50+
if test.Name() == testname {
51+
if !test.Run(bmc, cfg, ipmiPre) {
52+
return fmt.Errorf("%s", test.ErrorText())
53+
}
54+
}
55+
}
56+
57+
return nil
58+
}
59+
60+
func runSuite(suite string, bmc *bmc.BMC, cfg *configuration.Config) error {
61+
ipmiPre := &ipmi.IPMISDRPrecondition{}
62+
if err := ipmiPre.Run(bmc); err != nil {
63+
return err
64+
}
65+
66+
tests := tests.GetSuite(suite)
67+
if len(tests) < 1 {
68+
return fmt.Errorf("no tests to execute")
69+
}
70+
71+
for _, test := range tests {
72+
if !test.Run(bmc, cfg, ipmiPre) {
73+
return fmt.Errorf("%s", test.ErrorText())
74+
}
75+
}
76+
return nil
77+
}
78+
79+
func run() error {
80+
flags, err := parseFlags(os.Args[1:])
81+
if err != nil {
82+
return err
83+
}
84+
85+
cfg, err := configuration.LoadConfig(flags.configPath)
86+
if err != nil {
87+
return err
88+
}
89+
90+
fmt.Printf("%v\n", cfg)
91+
92+
switch flags.cmd {
93+
case runSingleCmd:
94+
bmc, err := bmc.NewBMC(flags.execEnv, cfg)
95+
if err != nil {
96+
return err
97+
}
98+
defer func() {
99+
if err := bmc.Close(); err != nil {
100+
log.Print(err)
101+
}
102+
}()
103+
return runSingle(flags.testName, bmc, cfg)
104+
case runSuiteCmd:
105+
bmc, err := bmc.NewBMC(flags.execEnv, cfg)
106+
if err != nil {
107+
return err
108+
}
109+
defer func() {
110+
if err := bmc.Close(); err != nil {
111+
log.Print(err)
112+
}
113+
}()
114+
return runSuite(flags.testName, bmc, cfg)
115+
case runAllCmd:
116+
bmc, err := bmc.NewBMC(flags.execEnv, cfg)
117+
if err != nil {
118+
return err
119+
}
120+
defer func() {
121+
if err := bmc.Close(); err != nil {
122+
log.Print(err)
123+
}
124+
}()
125+
return runAll(bmc, cfg)
126+
case cfgCheckCmd:
127+
return configuration.Validate(cfg)
128+
default:
129+
return fmt.Errorf("unknown command: %s", flags.cmd)
130+
}
131+
}
132+
133+
func main() {
134+
if err := run(); err != nil {
135+
log.Print(err)
136+
os.Exit(1)
137+
}
138+
}

contrib/example_config.yaml

Lines changed: 35 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,43 @@
11
---
22
version: 0
33
name: ExampleServer
4-
requirements:
5-
redfish:
6-
general:
7-
cpuvendor: "TestVendor"
8-
cpumodel: TestModel
9-
psucount: 0
10-
voltage:
11-
- TestString 1
12-
- TestString 2
13-
temperatures:
14-
- Test Temp 1
15-
- Test Temp 2
16-
fans:
17-
- Test Fans 1
18-
- Test Fans 2
19-
dimms:
4+
bm_config:
5+
bmc_host: bmcIP
6+
bmc_user: root
7+
bmc_password: 0penBmc
8+
ssh_port: "22"
9+
numHosts: 1
10+
hosts:
11+
- host1:
12+
ip: hostIP1
13+
user: hostUser1
14+
password: hostPassword1
15+
- host2:
16+
ip: hostIP2
17+
user: hostUser2
18+
password: hostPassword2
19+
testdata:
20+
system:
21+
guid: guid-string
22+
cpu:
23+
cpuvendor: ""
24+
cpumodel: ""
25+
voltage:
26+
- TestString 1
27+
- TestString 2
28+
temperatures:
29+
- Test Temp 1
30+
- Test Temp 2
31+
fans:
32+
- Test Fans 1
33+
- Test Fans 2
34+
dimms:
2035
count: 0
2136
partNo: 0123
2237
vendor: TestDimmmVendor
2338
capacity: 1336
2439
fru:
25-
fruExpected:
26-
vendor: TestFruVendor
27-
name: TestFruName
28-
serial: TestSerial001
40+
- productManufacturer: TestVal
41+
productName: 'testName'
42+
productSerial: 'testSerial'
43+
boardManufacturer: testManufacturer

go.mod

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
module github.com/9elements/bmc-test-go
22

3-
go 1.23
3+
go 1.24.0
4+
5+
toolchain go1.24.12
46

57
require gopkg.in/yaml.v3 v3.0.1
8+
9+
require (
10+
github.com/stmcginnis/gofish v0.20.0 // indirect
11+
golang.org/x/crypto v0.47.0 // indirect
12+
golang.org/x/sys v0.40.0 // indirect
13+
)

go.sum

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
github.com/stmcginnis/gofish v0.20.0 h1:hH2V2Qe898F2wWT1loApnkDUrXXiLKqbSlMaH3Y1n08=
2+
github.com/stmcginnis/gofish v0.20.0/go.mod h1:PzF5i8ecRG9A2ol8XT64npKUunyraJ+7t0kYMpQAtqU=
3+
golang.org/x/crypto v0.47.0 h1:V6e3FRj+n4dbpw86FJ8Fv7XVOql7TEwpHapKoMJ/GO8=
4+
golang.org/x/crypto v0.47.0/go.mod h1:ff3Y9VzzKbwSSEzWqJsJVBnWmRwRSHt/6Op5n9bQc4A=
5+
golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ=
6+
golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
17
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
28
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
39
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=

main.go

Lines changed: 0 additions & 34 deletions
This file was deleted.

pkg/bmc/bmc.go

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package bmc
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/9elements/bmc-test-go/pkg/configuration"
7+
"github.com/stmcginnis/gofish"
8+
)
9+
10+
type BMC struct {
11+
con BMCConnection
12+
redfishService *gofish.Service
13+
}
14+
15+
func makeGofishConfig(config *configuration.Config) gofish.ClientConfig {
16+
return gofish.ClientConfig{
17+
Endpoint: "https://" + config.BMCHost,
18+
Username: config.BMCUser,
19+
Password: config.BMCPassword,
20+
Insecure: true,
21+
}
22+
}
23+
24+
func NewBMC(execEnv string, cfg *configuration.Config) (*BMC, error) {
25+
ret := &BMC{}
26+
switch execEnv {
27+
case "local":
28+
ret.con = &LocalConn{}
29+
case "remote":
30+
hostport := fmt.Sprintf("%s:%s", cfg.BMCHost, cfg.SSHPort)
31+
remoteConn, err := NewRemoteConn(hostport, cfg.BMCUser, cfg.BMCPassword)
32+
if err != nil {
33+
return nil, err
34+
}
35+
ret.con = remoteConn
36+
default:
37+
return nil, fmt.Errorf("unknown connection type: %s", execEnv)
38+
}
39+
40+
conn, err := gofish.Connect(makeGofishConfig(cfg))
41+
if err != nil {
42+
return nil, err
43+
}
44+
45+
ret.redfishService = conn.Service
46+
47+
return ret, nil
48+
}
49+
50+
func (b *BMC) Close() error {
51+
return b.con.Close()
52+
}
53+
54+
func (b *BMC) ExecuteCommandLine(cmd string) ([]byte, error) {
55+
return b.con.ExecuteCmdline(cmd)
56+
}
57+
58+
func (b *BMC) RedfishService() *gofish.Service {
59+
return b.redfishService
60+
}

0 commit comments

Comments
 (0)