From 101e1ca4d575e918bec47b72b4f4baa4c9d218fd Mon Sep 17 00:00:00 2001 From: Alva8756 Date: Mon, 22 Apr 2024 19:48:59 -0700 Subject: [PATCH] forward inventory to fleetdb --- go.mod | 6 ++- go.sum | 4 +- internal/fleetdb/attributes.go | 52 ------------------ internal/fleetdb/fleetdb.go | 87 ++++++++----------------------- pkg/api/routes/components_test.go | 6 ++- pkg/api/routes/inventory.go | 28 ++++++++-- pkg/api/routes/routes.go | 5 +- 7 files changed, 59 insertions(+), 129 deletions(-) delete mode 100644 internal/fleetdb/attributes.go diff --git a/go.mod b/go.mod index ccd2d21..1ca5259 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,8 @@ module github.com/metal-toolbox/component-inventory -go 1.21 +go 1.22 + +toolchain go1.22.2 require ( github.com/bmc-toolbox/common v0.0.0-20240416132216-a56a09c16f4e @@ -8,7 +10,7 @@ require ( github.com/gin-gonic/gin v1.9.1 github.com/google/uuid v1.6.0 github.com/metal-toolbox/alloy v0.3.3-0.20240320183632-05dfbd5e9110 - github.com/metal-toolbox/fleetdb v0.17.1 + github.com/metal-toolbox/fleetdb v0.17.2-0.20240419204835-60c421433f0a github.com/metal-toolbox/rivets v1.0.3 github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.19.0 diff --git a/go.sum b/go.sum index 1ec88f9..221f425 100644 --- a/go.sum +++ b/go.sum @@ -506,8 +506,8 @@ github.com/mattn/go-sqlite3 v2.0.1+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/metal-toolbox/alloy v0.3.3-0.20240320183632-05dfbd5e9110 h1:v3PTHUK9KIF/mEmctQ5mgsBtG8dtdfboHI/7QQg/Ft0= github.com/metal-toolbox/alloy v0.3.3-0.20240320183632-05dfbd5e9110/go.mod h1:NcVZtbVhBCcpyTHew0TJ8yzon69vMf+rGMLoGb9jTa0= -github.com/metal-toolbox/fleetdb v0.17.1 h1:eyaCg4yGQnbXIjiBMZPsLqmEpxbltlEUNDG+Mn27Fsc= -github.com/metal-toolbox/fleetdb v0.17.1/go.mod h1:TbRbU+ppHIknqiAONR7JDQfzKij30uiPkehgxlA1Hv0= +github.com/metal-toolbox/fleetdb v0.17.2-0.20240419204835-60c421433f0a h1:Jrjbk0M8EiljlgxeLso232AizQzuaQ4Bnqf8L9ITkug= +github.com/metal-toolbox/fleetdb v0.17.2-0.20240419204835-60c421433f0a/go.mod h1:U9YArAdibILSBJzNbmtJAz6m+Cljce6a7pL0JkOckqQ= github.com/metal-toolbox/rivets v1.0.3 h1:ZW9q8V3vz6VxAczC4eR1YJdl+kapHF3ebVc+4r3NmR8= github.com/metal-toolbox/rivets v1.0.3/go.mod h1:EMQJRT1mjIyFRXxvKNaBlz7Z4Sp88rTaGO8W18olN2I= github.com/microsoft/go-mssqldb v0.17.0/go.mod h1:OkoNGhGEs8EZqchVTtochlXruEhEOaO4S0d2sB5aeGQ= diff --git a/internal/fleetdb/attributes.go b/internal/fleetdb/attributes.go deleted file mode 100644 index f3d1a38..0000000 --- a/internal/fleetdb/attributes.go +++ /dev/null @@ -1,52 +0,0 @@ -package internalfleetdb - -import ( - "encoding/json" - - "github.com/metal-toolbox/alloy/types" - "github.com/metal-toolbox/component-inventory/pkg/api/constants" - fleetdb "github.com/metal-toolbox/fleetdb/pkg/api/v1" -) - -func deviceVendorAttributes(cid *types.InventoryDevice) (map[string]string, *fleetdb.Attributes, error) { - deviceVendorData := map[string]string{ - constants.ServerSerialAttributeKey: "unknown", - constants.ServerVendorAttributeKey: "unknown", - constants.ServerModelAttributeKey: "unknown", - } - - if cid.Inv != nil { - if cid.Inv.Serial != "" { - deviceVendorData[constants.ServerSerialAttributeKey] = cid.Inv.Serial - } - - if cid.Inv.Model != "" { - deviceVendorData[constants.ServerModelAttributeKey] = cid.Inv.Model - } - - if cid.Inv.Vendor != "" { - deviceVendorData[constants.ServerVendorAttributeKey] = cid.Inv.Vendor - } - } - - deviceVendorDataBytes, err := json.Marshal(deviceVendorData) - if err != nil { - return nil, nil, err - } - - return deviceVendorData, &fleetdb.Attributes{ - Namespace: constants.ServerVendorAttributeNS, - Data: deviceVendorDataBytes, - }, nil -} - -// attributeByNamespace returns the attribute in the slice that matches the namespace -func attributeByNamespace(ns string, attributes []fleetdb.Attributes) *fleetdb.Attributes { - for _, attribute := range attributes { - if attribute.Namespace == ns { - return &attribute - } - } - - return nil -} diff --git a/internal/fleetdb/fleetdb.go b/internal/fleetdb/fleetdb.go index 327eab2..a5ab89a 100644 --- a/internal/fleetdb/fleetdb.go +++ b/internal/fleetdb/fleetdb.go @@ -2,13 +2,12 @@ package internalfleetdb import ( "context" - "encoding/json" "fmt" "github.com/google/uuid" "github.com/metal-toolbox/alloy/types" "github.com/metal-toolbox/component-inventory/internal/app" - "github.com/metal-toolbox/component-inventory/pkg/api/constants" + "github.com/metal-toolbox/component-inventory/internal/inventoryconverter" fleetdb "github.com/metal-toolbox/fleetdb/pkg/api/v1" "go.uber.org/zap" ) @@ -16,12 +15,11 @@ import ( type Client interface { GetServer(context.Context, uuid.UUID) (*fleetdb.Server, *fleetdb.ServerResponse, error) GetComponents(context.Context, uuid.UUID, *fleetdb.PaginationParams) (fleetdb.ServerComponentSlice, *fleetdb.ServerResponse, error) - UpdateAttributes(context.Context, *fleetdb.Server, *types.InventoryDevice, *zap.Logger) error - UpdateServerBIOSConfig() error + UpdateServerInventory(context.Context, *fleetdb.Server, *types.InventoryDevice, *zap.Logger, bool) error } // Creates a new Client, with reasonable defaults -func NewFleetDBClient(cfg *app.Configuration) (Client, error) { +func NewFleetDBClient(ctx context.Context, cfg *app.Configuration) (Client, error) { client, err := fleetdb.NewClient(cfg.FleetDBAddress, nil) if err != nil { return nil, err @@ -31,13 +29,27 @@ func NewFleetDBClient(cfg *app.Configuration) (Client, error) { client.SetToken(cfg.FleetDBToken) } + slugs := make(map[string]*fleetdb.ServerComponentType) + serverComponentTypes, _, err := client.ListServerComponentTypes(ctx, nil) + if err != nil { + return nil, fmt.Errorf("failed to get server component types: %w", err) + } + for _, ct := range serverComponentTypes { + slugs[ct.Slug] = ct + } + return &fleetDBClient{ - client: client, + client: client, + slugs: slugs, + inventoryConverterInstance: inventoryconverter.NewInventoryConverter(slugs), }, nil } type fleetDBClient struct { client *fleetdb.Client + // We may want to support slug refresh. + slugs map[string]*fleetdb.ServerComponentType + inventoryConverterInstance *inventoryconverter.InventoryConverter } func (fc fleetDBClient) GetServer(ctx context.Context, id uuid.UUID) (*fleetdb.Server, *fleetdb.ServerResponse, error) { @@ -48,69 +60,14 @@ func (fc fleetDBClient) GetComponents(ctx context.Context, id uuid.UUID, params return fc.client.GetComponents(ctx, id, params) } -func (fc fleetDBClient) UpdateAttributes(ctx context.Context, server *fleetdb.Server, dev *types.InventoryDevice, log *zap.Logger) error { - return createUpdateServerAttributes(ctx, fc.client, server, dev, log) -} - -// Functions below may be refactored in the near future. -func createUpdateServerAttributes(ctx context.Context, c *fleetdb.Client, server *fleetdb.Server, dev *types.InventoryDevice, log *zap.Logger) error { - newVendorData, newVendorAttrs, err := deviceVendorAttributes(dev) +func (fc fleetDBClient) UpdateServerInventory(ctx context.Context, server *fleetdb.Server, dev *types.InventoryDevice, _ *zap.Logger, inband bool) error { + typeServer, err := fc.inventoryConverterInstance.ToRivetsServer(server.UUID.String(), server.FacilityCode, dev.Inv, *dev.BiosCfg) if err != nil { return err } - - // identify current vendor data in the inventory - existingVendorAttrs := attributeByNamespace(constants.ServerVendorAttributeNS, server.Attributes) - if existingVendorAttrs == nil { - // create if none exists - _, err = c.CreateAttributes(ctx, server.UUID, *newVendorAttrs) - return err - } - - // unpack vendor data from inventory - existingVendorData := map[string]string{} - if err := json.Unmarshal(existingVendorAttrs.Data, &existingVendorData); err != nil { - // update vendor data since it seems to be invalid - log.Warn("server vendor attributes data invalid, updating..") - - _, err = c.UpdateAttributes(ctx, server.UUID, constants.ServerVendorAttributeNS, newVendorAttrs.Data) - - return err - } - - updatedVendorData := existingVendorData - var changes bool - for key := range newVendorData { - if updatedVendorData[key] == "" || updatedVendorData[key] == "unknown" { - if newVendorData[key] != "unknown" { - changes = true - updatedVendorData[key] = newVendorData[key] - } - } - } - - if !changes { - return nil - } - - if len(updatedVendorData) > 0 { - updateBytes, err := json.Marshal(updatedVendorData) - if err != nil { - return err - } - - _, err = c.UpdateAttributes(ctx, server.UUID, constants.ServerVendorAttributeNS, updateBytes) - + _, err = fc.client.SetServerInventory(ctx, server.UUID, typeServer, inband) + if err != nil { return err } - return nil } - -func (fc fleetDBClient) UpdateServerBIOSConfig() error { - return createUpdateServerBIOSConfig() -} - -func createUpdateServerBIOSConfig() error { - return fmt.Errorf("unimplemented") -} diff --git a/pkg/api/routes/components_test.go b/pkg/api/routes/components_test.go index c250943..682a637 100644 --- a/pkg/api/routes/components_test.go +++ b/pkg/api/routes/components_test.go @@ -1,6 +1,8 @@ package routes import ( + "context" + "github.com/metal-toolbox/component-inventory/internal/app" internalfleetdb "github.com/metal-toolbox/component-inventory/internal/fleetdb" @@ -91,7 +93,7 @@ func TestFetchServerComponents(t *testing.T) { logger := app.GetLogger(true) - client, err := internalfleetdb.NewFleetDBClient(&app.Configuration{ + client, err := internalfleetdb.NewFleetDBClient(context.Background(), &app.Configuration{ FleetDBAddress: ts.URL, }) require.NoError(t, err) @@ -120,7 +122,7 @@ func TestFetchServerComponents(t *testing.T) { logger := app.GetLogger(true) - client, err := internalfleetdb.NewFleetDBClient(&app.Configuration{ + client, err := internalfleetdb.NewFleetDBClient(context.Background(), &app.Configuration{ FleetDBAddress: ts.URL, }) require.NoError(t, err) diff --git a/pkg/api/routes/inventory.go b/pkg/api/routes/inventory.go index 1390db0..b7de9fe 100644 --- a/pkg/api/routes/inventory.go +++ b/pkg/api/routes/inventory.go @@ -2,7 +2,8 @@ package routes import ( "context" - "errors" + "fmt" + "strings" "github.com/metal-toolbox/alloy/types" internalfleetdb "github.com/metal-toolbox/component-inventory/internal/fleetdb" @@ -12,13 +13,32 @@ import ( func processInband(ctx context.Context, c internalfleetdb.Client, server *fleetdb.Server, dev *types.InventoryDevice, log *zap.Logger) error { //nolint log.Info("processing", zap.String("server", server.Name), zap.String("device", dev.Inv.Serial)) - if err := c.UpdateAttributes(ctx, server, dev, log); err != nil { + if err := verifyComponent(c, server, dev, log); err != nil { return err } - return errors.New("not implemented") + return c.UpdateServerInventory(ctx, server, dev, log, true) } func processOutofband(ctx context.Context, c internalfleetdb.Client, server *fleetdb.Server, dev *types.InventoryDevice, log *zap.Logger) error { //nolint log.Info("processing", zap.String("server", server.Name), zap.String("device", dev.Inv.Serial)) - return errors.New("not implemented") + if err := verifyComponent(c, server, dev, log); err != nil { + return err + } + return c.UpdateServerInventory(ctx, server, dev, log, false) +} + +func verifyComponent(c internalfleetdb.Client, server *fleetdb.Server, dev *types.InventoryDevice, log *zap.Logger) error { + components, err := fetchServerComponents(c, server.UUID, log) + if err != nil { + if strings.Contains(err.Error(), "404") { + // The server doesn't have components, we can create it. + return nil + } + return err + } + return isBadComponents(components, dev) +} + +func isBadComponents(_ serverComponents, _ *types.InventoryDevice) error { + return fmt.Errorf("unimplement") } diff --git a/pkg/api/routes/routes.go b/pkg/api/routes/routes.go index ac08f4a..0d45c3d 100644 --- a/pkg/api/routes/routes.go +++ b/pkg/api/routes/routes.go @@ -132,7 +132,7 @@ func ComposeHTTPServer(theApp *app.App) *http.Server { return } - client, err := internalfleetdb.NewFleetDBClient(theApp.Cfg) + client, err := internalfleetdb.NewFleetDBClient(ctx, theApp.Cfg) if err != nil { ctx.JSON(http.StatusInternalServerError, map[string]any{ "message": "failed to connect to fleetdb", @@ -224,7 +224,7 @@ func composeInventoryHandler(theApp *app.App, fn inventoryHandler) gin.HandlerFu return } - fleetDBClient, err := internalfleetdb.NewFleetDBClient(theApp.Cfg) + fleetDBClient, err := internalfleetdb.NewFleetDBClient(ctx, theApp.Cfg) if err != nil { ctx.JSON(http.StatusInternalServerError, map[string]any{ "message": "failed to connect to fleetdb", @@ -236,6 +236,7 @@ func composeInventoryHandler(theApp *app.App, fn inventoryHandler) gin.HandlerFu server, _, err := fleetDBClient.GetServer(ctx, serverID) if err != nil { reject(ctx, http.StatusBadRequest, "server not exisit", err.Error()) + return } if err := fn(