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

Commit

Permalink
internal fleetdb outline
Browse files Browse the repository at this point in the history
  • Loading branch information
Alva8756 committed Mar 18, 2024
1 parent 87e1a1a commit 916fac5
Show file tree
Hide file tree
Showing 8 changed files with 267 additions and 36 deletions.
52 changes: 52 additions & 0 deletions internal/fleetdb/attributes.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package internalfleetdb

import (
"encoding/json"

"github.com/metal-toolbox/component-inventory/pkg/api/constants"
"github.com/metal-toolbox/component-inventory/pkg/api/types"
fleetdb "github.com/metal-toolbox/fleetdb/pkg/api/v1"
)

func deviceVendorAttributes(cid *types.ComponentInventoryDevice) (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
}
116 changes: 116 additions & 0 deletions internal/fleetdb/fleetdb.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package internalfleetdb

import (
"context"
"encoding/json"
"fmt"

"github.com/google/uuid"
"github.com/metal-toolbox/component-inventory/internal/app"
"github.com/metal-toolbox/component-inventory/pkg/api/constants"
"github.com/metal-toolbox/component-inventory/pkg/api/types"
fleetdb "github.com/metal-toolbox/fleetdb/pkg/api/v1"
"go.uber.org/zap"
)

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.ComponentInventoryDevice, *zap.Logger) error
UpdateServerBIOSConfig() error
}

// Creates a new Client, with reasonable defaults
func NewFleetDBClient(cfg *app.Configuration) (Client, error) {
client, err := fleetdb.NewClient(cfg.FleetDBAddress, nil)
if err != nil {
return nil, err
}

if cfg.FleetDBToken != "" {
client.SetToken(cfg.FleetDBToken)
}

return &fleetDBClient{
client: client,
}, nil
}

type fleetDBClient struct {
client *fleetdb.Client
}

func (fc fleetDBClient) GetServer(ctx context.Context, id uuid.UUID) (*fleetdb.Server, *fleetdb.ServerResponse, error) {
return fc.client.Get(ctx, id)
}

func (fc fleetDBClient) GetComponents(ctx context.Context, id uuid.UUID, params *fleetdb.PaginationParams) (fleetdb.ServerComponentSlice, *fleetdb.ServerResponse, error) {
return fc.client.GetComponents(ctx, id, params)
}

func (fc fleetDBClient) UpdateAttributes(ctx context.Context, server *fleetdb.Server, dev *types.ComponentInventoryDevice, 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.ComponentInventoryDevice, log *zap.Logger) error {
newVendorData, newVendorAttrs, err := deviceVendorAttributes(dev)
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)

return err
}

return nil
}

func (fc fleetDBClient) UpdateServerBIOSConfig() error {
return createUpdateServerBIOSConfig()
}

func createUpdateServerBIOSConfig() error {
return fmt.Errorf("unimplemented")
}
36 changes: 36 additions & 0 deletions pkg/api/constants/constants.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package constants

const (
LivenessEndpoint = "/_health/liveness"
VersionEndpoint = "/api/version"
ComponentsEndpoint = "/components"
InbandInventoryEndpoint = "/inventory/in-band"
OutofbandInventoryEndpoint = "/inventory/out-of-band"

// server service attribute to look up the BMC IP Address in
BmcAttributeNamespace = "sh.hollow.bmc_info"

// server server service BMC address attribute key found under the bmcAttributeNamespace
BmcIPAddressAttributeKey = "address"

// serverservice namespace prefix the data is stored in.
ServerServiceNSPrefix = "sh.hollow.alloy"

// server vendor, model attributes are stored in this namespace.
ServerVendorAttributeNS = ServerServiceNSPrefix + ".server_vendor_attributes"

// additional server metadata are stored in this namespace.
ServerMetadataAttributeNS = ServerServiceNSPrefix + ".server_metadata_attributes"

// errors that occurred when connecting/collecting inventory from the bmc are stored here.
ServerBMCErrorsAttributeNS = ServerServiceNSPrefix + ".server_bmc_errors"

// server service server serial attribute key
ServerSerialAttributeKey = "serial"

// server service server model attribute key
ServerModelAttributeKey = "model"

// server service server vendor attribute key
ServerVendorAttributeKey = "vendor"
)
3 changes: 2 additions & 1 deletion pkg/api/routes/components.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"time"

"github.com/google/uuid"
internalfleetdb "github.com/metal-toolbox/component-inventory/internal/fleetdb"
fleetdb "github.com/metal-toolbox/fleetdb/pkg/api/v1"
rdb "github.com/metal-toolbox/rivets/fleetdb"
rivets "github.com/metal-toolbox/rivets/types"
Expand All @@ -16,7 +17,7 @@ var fleetDBTimeout = 3 * time.Minute
// this is a map of "component_type_name" to the actual inventory data for each component
type serverComponents map[string][]*rivets.Component

func fetchServerComponents(client *fleetdb.Client, srvid uuid.UUID, l *zap.Logger) (serverComponents, error) {
func fetchServerComponents(client internalfleetdb.Client, srvid uuid.UUID, l *zap.Logger) (serverComponents, error) {
ctx, cancel := context.WithTimeout(context.Background(), fleetDBTimeout)
defer cancel()

Expand Down
9 changes: 0 additions & 9 deletions pkg/api/routes/endpoints.go

This file was deleted.

16 changes: 10 additions & 6 deletions pkg/api/routes/inventory.go
Original file line number Diff line number Diff line change
@@ -1,20 +1,24 @@
package routes

import (
"context"
"errors"

"github.com/bmc-toolbox/common"
"github.com/google/uuid"
internalfleetdb "github.com/metal-toolbox/component-inventory/internal/fleetdb"
"github.com/metal-toolbox/component-inventory/pkg/api/types"
fleetdb "github.com/metal-toolbox/fleetdb/pkg/api/v1"
"go.uber.org/zap"
)

func processInband(c *fleetdb.Client, srvID uuid.UUID, dev *common.Device, log *zap.Logger) error { //nolint
log.Info("processing", zap.String("server id", srvID.String()), zap.String("device", dev.Serial))
func processInband(ctx context.Context, c internalfleetdb.Client, server *fleetdb.Server, dev *types.ComponentInventoryDevice, 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 {
return err
}
return errors.New("not implemented")
}

func processOutofband(c *fleetdb.Client, srvID uuid.UUID, dev *common.Device, log *zap.Logger) error { //nolint
log.Info("processing", zap.String("server id", srvID.String()), zap.String("device", dev.Serial))
func processOutofband(ctx context.Context, c internalfleetdb.Client, server *fleetdb.Server, dev *types.ComponentInventoryDevice, log *zap.Logger) error { //nolint
log.Info("processing", zap.String("server", server.Name), zap.String("device", dev.Inv.Serial))
return errors.New("not implemented")
}
Loading

0 comments on commit 916fac5

Please sign in to comment.