Skip to content
This repository was archived by the owner on Jul 18, 2024. It is now read-only.

Commit d347051

Browse files
committed
identify bad component
1 parent 6338e71 commit d347051

File tree

4 files changed

+126
-20
lines changed

4 files changed

+126
-20
lines changed

internal/inventoryconverter/inventoryconverter.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@ func (ic *InventoryConverter) ToRivetsServer(serverID, facility string, device *
2626
return nil, err
2727
}
2828

29+
deviceState := ""
30+
if device.Status != nil {
31+
deviceState = device.Status.State
32+
}
33+
2934
return &rivets.Server{
3035
BIOSCfg: biosCfg,
3136
ID: serverID,
@@ -34,7 +39,7 @@ func (ic *InventoryConverter) ToRivetsServer(serverID, facility string, device *
3439
Vendor: device.Vendor,
3540
Model: device.Model,
3641
Serial: device.Serial,
37-
Status: device.Status.State,
42+
Status: deviceState,
3843
Components: components,
3944
}, nil
4045
}

pkg/api/routes/components.go

Lines changed: 78 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,13 @@ import (
1515

1616
var fleetDBTimeout = 3 * time.Minute
1717

18-
type cmpResult int
18+
type componentCompareResult int
1919

2020
const (
21-
NOT_FOUND cmpResult = iota
21+
NOT_FOUND componentCompareResult = iota
2222
ERROR_FETCH
23-
GAP
24-
SAME
23+
DIFFERENT
24+
EQUAL
2525
)
2626

2727
// this is a map of "component_type_name" to the actual inventory data for each component
@@ -58,7 +58,7 @@ func fetchServerComponents(client internalfleetdb.Client, srvid uuid.UUID, l *za
5858
return comps, nil
5959
}
6060

61-
func verifyComponent(c internalfleetdb.Client, server *fleetdb.Server, dev *rivets.Server, log *zap.Logger) cmpResult {
61+
func verifyComponent(c internalfleetdb.Client, server *fleetdb.Server, dev *rivets.Server, log *zap.Logger) componentCompareResult {
6262
fleetComponentsMap, err := fetchServerComponents(c, server.UUID, log)
6363
if err != nil {
6464
if strings.Contains(err.Error(), "404") {
@@ -68,6 +68,10 @@ func verifyComponent(c internalfleetdb.Client, server *fleetdb.Server, dev *rive
6868
return ERROR_FETCH
6969
}
7070

71+
if len(fleetComponentsMap) == 0 {
72+
return NOT_FOUND
73+
}
74+
7175
alloyComponentsMap := make(map[string][]*rivets.Component)
7276
for _, component := range dev.Components {
7377
slug := component.Name
@@ -77,24 +81,83 @@ func verifyComponent(c internalfleetdb.Client, server *fleetdb.Server, dev *rive
7781
alloyComponentsMap[slug] = append(alloyComponentsMap[slug], component)
7882
}
7983

80-
var diff strings.Builder
81-
for slug, fleetComponents := range fleetComponentsMap {
82-
if alloyComponents, ok := alloyComponentsMap[slug]; ok {
83-
compareComponents(fleetComponents, alloyComponents, &diff)
84-
continue
84+
serverID := server.UUID.String()
85+
var cmpResult componentCompareResult
86+
87+
for slug, alloyComponents := range alloyComponentsMap {
88+
fleetComponents, _ := fleetComponentsMap[slug]
89+
// if fleetComponents is nil, we will print logs for
90+
// each component in alloyComponents.
91+
if changed := compareComponents(alloyComponents, fleetComponents, slug, serverID, log); changed {
92+
cmpResult = DIFFERENT
8593
}
86-
// diff.WriteString("-", fleetComponents)
8794
}
8895

89-
for slug, alloyComponents := range alloyComponentsMap {
96+
for slug, fleetComponents := range fleetComponentsMap {
9097
if _, ok := alloyComponentsMap[slug]; ok {
98+
// We have already compared this slug in the previous for loog.
9199
continue
92100
}
93-
// diff.WriteString("+", fleetComponents)
101+
cmpResult = DIFFERENT
102+
compareComponents(nil, fleetComponents, slug, serverID, log)
94103
}
95104

96-
return SAME
105+
return cmpResult
97106
}
98107

99-
func compareComponents(src []*rivets.Component, tgt []*rivets.Component, diff *strings.Builder) {
108+
func compareComponents(expected []*rivets.Component, current []*rivets.Component, slug string, serverID string, log *zap.Logger) bool {
109+
var hasGap bool
110+
expectedMap := make(map[string]string)
111+
currentMap := make(map[string]string)
112+
for _, component := range expected {
113+
expectedMap[component.Vendor+component.Model] = component.Firmware.Installed
114+
}
115+
for _, component := range current {
116+
currentMap[component.Vendor+component.Model] = component.Firmware.Installed
117+
}
118+
119+
for key, expectedFirmwareVersion := range expectedMap {
120+
currentFirmwareVersion, exist := currentMap[key]
121+
if !exist {
122+
hasGap = true
123+
fields := []zap.Field{
124+
zap.String("device.id", serverID),
125+
zap.String("component", slug),
126+
zap.String("expected(alloy)", expectedFirmwareVersion),
127+
zap.String("current(fleetdb)", "fleetdb firmware does not exist"),
128+
}
129+
log.Warn("alloy has component but not in fleetdb", fields...)
130+
continue
131+
}
132+
133+
if expectedFirmwareVersion != currentFirmwareVersion {
134+
hasGap = true
135+
fields := []zap.Field{
136+
zap.String("device.id", serverID),
137+
zap.String("component", slug),
138+
zap.String("expected(alloy)", currentFirmwareVersion),
139+
zap.String("current(fleetdb)", expectedFirmwareVersion),
140+
}
141+
log.Warn("component firmware needs update", fields...)
142+
}
143+
}
144+
145+
for key, currentFirmwareVersion := range currentMap {
146+
_, exist := expectedMap[key]
147+
if exist {
148+
// Already been compared in the previous for loop.
149+
continue
150+
}
151+
152+
hasGap = true
153+
fields := []zap.Field{
154+
zap.String("device.id", serverID),
155+
zap.String("component", slug),
156+
zap.String("expected(alloy)", "alloy firmware does not exist"),
157+
zap.String("current(fleetdb)", currentFirmwareVersion),
158+
}
159+
log.Warn("fleetdb component has component but not in alloy", fields...)
160+
}
161+
162+
return hasGap
100163
}

pkg/api/routes/components_test.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,11 @@ import (
1212
"github.com/metal-toolbox/component-inventory/internal/app"
1313
"github.com/stretchr/testify/require"
1414

15+
common "github.com/bmc-toolbox/common"
1516
internalfleetdb "github.com/metal-toolbox/component-inventory/internal/fleetdb"
1617
fleetdb "github.com/metal-toolbox/fleetdb/pkg/api/v1"
18+
rivets "github.com/metal-toolbox/rivets/types"
19+
"go.uber.org/zap"
1720
)
1821

1922
var serverUUID = uuid.New()
@@ -174,3 +177,37 @@ func TestFetchServerComponents(t *testing.T) {
174177
require.Equal(t, 500, srvErr.StatusCode)
175178
})
176179
}
180+
181+
func TestCompareComponents(t *testing.T) {
182+
testCases := []struct {
183+
desc string
184+
installed []*rivets.Component
185+
current []*rivets.Component
186+
expectDiff bool
187+
}{
188+
{
189+
"2 nil slice",
190+
nil,
191+
nil,
192+
false,
193+
},
194+
{
195+
"installed nil slice",
196+
nil,
197+
[]*rivets.Component{
198+
{
199+
Firmware: &common.Firmware{Installed: "2.6.6"},
200+
Status: &common.Status{State: "Enabled"},
201+
},
202+
},
203+
true,
204+
},
205+
}
206+
207+
for _, tc := range testCases {
208+
if got := compareComponents(tc.installed, tc.current, "fakeSlug", "fakeID", zap.NewNop()); got != tc.expectDiff {
209+
t.Errorf("test %v got compare result %v, expect %v", tc.desc, got, tc.expectDiff)
210+
}
211+
}
212+
213+
}

pkg/api/routes/inventory.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package routes
33
import (
44
"context"
55
"fmt"
6+
"strconv"
67

78
"github.com/metal-toolbox/alloy/types"
89
internalfleetdb "github.com/metal-toolbox/component-inventory/internal/fleetdb"
@@ -18,8 +19,8 @@ func processInband(ctx context.Context, c internalfleetdb.Client, server *fleetd
1819
return err
1920
}
2021

21-
if cmp := verifyComponent(c, server, rivetsServer, log); cmp == SAME || cmp == ERROR_FETCH {
22-
log.Error("verify component", zap.String("server", server.Name), zap.String("err", cmp))
22+
if cmp := verifyComponent(c, server, rivetsServer, log); cmp == EQUAL || cmp == ERROR_FETCH {
23+
log.Error("verify component", zap.String("server", server.Name), zap.String("err", strconv.Itoa(int(cmp))))
2324
return fmt.Errorf("failed to verify components %v", cmp)
2425
}
2526
return c.UpdateServerInventory(ctx, server, rivetsServer, log, true)
@@ -32,8 +33,8 @@ func processOutofband(ctx context.Context, c internalfleetdb.Client, server *fle
3233
log.Error("convert inventory fail", zap.String("server", server.Name), zap.String("err", err.Error()))
3334
return err
3435
}
35-
if cmp := verifyComponent(c, server, rivetsServer, log); cmp == SAME || cmp == ERROR_FETCH {
36-
log.Error("verify component", zap.String("server", server.Name), zap.String("err", cmp))
36+
if cmp := verifyComponent(c, server, rivetsServer, log); cmp == EQUAL || cmp == ERROR_FETCH {
37+
log.Error("verify component", zap.String("server", server.Name), zap.String("err", strconv.Itoa(int(cmp))))
3738
return err
3839
}
3940
return c.UpdateServerInventory(ctx, server, rivetsServer, log, false)

0 commit comments

Comments
 (0)