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

Commit

Permalink
refactor routes to use query parameters for inband
Browse files Browse the repository at this point in the history
  • Loading branch information
DoctorVin committed May 10, 2024
1 parent 8b2899f commit 838579f
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 62 deletions.
25 changes: 15 additions & 10 deletions pkg/api/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@ type ServerComponents map[string][]*rivets.Component
// Client can perform queries against the Component Inventory Service.
type Client interface {
Version(context.Context) (string, error)
GetServerComponents(context.Context, string) (ServerComponents, error)
GetServerComponents(context.Context, string, bool) (ServerComponents, error)
UpdateInbandInventory(context.Context, string, *types.InventoryDevice) (string, error)
UpdateOutOfbandInventory(context.Context, string, *types.InventoryDevice) (string, error)
}

type componentInventoryClient struct {
type cisClient struct {
// The server address with the schema
serverAddress string
// Authentication token
Expand All @@ -35,7 +35,7 @@ type componentInventoryClient struct {
// Creates a new Client, with reasonable defaults
func NewClient(serverAddress string, opts ...Option) (Client, error) {
// create a client with sane default values
client := componentInventoryClient{serverAddress: serverAddress}
client := cisClient{serverAddress: serverAddress}
// mutate client and add all optional params
for _, o := range opts {
if err := o(&client); err != nil {
Expand All @@ -51,8 +51,13 @@ func NewClient(serverAddress string, opts ...Option) (Client, error) {
return client, nil
}

func (c componentInventoryClient) GetServerComponents(ctx context.Context, serverID string) (ServerComponents, error) {
path := fmt.Sprintf("%v/%v", constants.ComponentsEndpoint, serverID)
func (c cisClient) GetServerComponents(ctx context.Context, serverID string, inband bool) (ServerComponents, error) {
mode := constants.OutOfBandMode
if inband {
mode = constants.InBandMode
}

path := fmt.Sprintf("%v/%v?mode=%s", constants.ComponentsEndpoint, serverID, mode)
resp, err := c.get(ctx, path)
if err != nil {
return nil, err
Expand All @@ -66,7 +71,7 @@ func (c componentInventoryClient) GetServerComponents(ctx context.Context, serve
return sc, err
}

func (c componentInventoryClient) Version(ctx context.Context) (string, error) {
func (c cisClient) Version(ctx context.Context) (string, error) {
resp, err := c.get(ctx, constants.VersionEndpoint)
if err != nil {
return "", err
Expand All @@ -75,8 +80,8 @@ func (c componentInventoryClient) Version(ctx context.Context) (string, error) {
return string(resp), nil
}

func (c componentInventoryClient) UpdateInbandInventory(ctx context.Context, serverID string, device *types.InventoryDevice) (string, error) {
path := fmt.Sprintf("%v/%v", constants.InbandInventoryEndpoint, serverID)
func (c cisClient) UpdateInbandInventory(ctx context.Context, serverID string, device *types.InventoryDevice) (string, error) {
path := fmt.Sprintf("%v/%v?mode=inband", constants.InventoryEndpoint, serverID)
body, err := json.Marshal(device)
if err != nil {
return "", fmt.Errorf("failed to parse device: %v", err)
Expand All @@ -90,8 +95,8 @@ func (c componentInventoryClient) UpdateInbandInventory(ctx context.Context, ser
return string(resp), nil
}

func (c componentInventoryClient) UpdateOutOfbandInventory(ctx context.Context, serverID string, device *types.InventoryDevice) (string, error) {
path := fmt.Sprintf("%v/%v", constants.OutofbandInventoryEndpoint, serverID)
func (c cisClient) UpdateOutOfbandInventory(ctx context.Context, serverID string, device *types.InventoryDevice) (string, error) {
path := fmt.Sprintf("%v/%v?mode=outofband", constants.InventoryEndpoint, serverID)
body, err := json.Marshal(device)
if err != nil {
return "", fmt.Errorf("failed to parse device: %v", err)
Expand Down
12 changes: 6 additions & 6 deletions pkg/api/client/client_private.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,26 +19,26 @@ type httpRequestDoer interface {
}

// Option allows setting custom parameters during construction
type Option func(*componentInventoryClient) error
type Option func(*cisClient) error

// WithHTTPClient allows overriding the default Doer, which is
// automatically created using http.Client. This is useful for tests.
func WithHTTPClient(doer httpRequestDoer) Option {
return func(c *componentInventoryClient) error {
return func(c *cisClient) error {
c.client = doer
return nil
}
}

// WithAuthToken sets the client auth token.
func WithAuthToken(authToken string) Option {
return func(c *componentInventoryClient) error {
return func(c *cisClient) error {
c.authToken = authToken
return nil
}
}

func (c *componentInventoryClient) get(ctx context.Context, path string) ([]byte, error) {
func (c *cisClient) get(ctx context.Context, path string) ([]byte, error) {
requestURL, err := url.Parse(fmt.Sprintf("%s%s", c.serverAddress, path))
if err != nil {
return nil, errors.Wrap(err, "parsing URL")
Expand All @@ -52,7 +52,7 @@ func (c *componentInventoryClient) get(ctx context.Context, path string) ([]byte
return c.do(req)
}

func (c *componentInventoryClient) post(ctx context.Context, path string, body []byte) ([]byte, error) {
func (c *cisClient) post(ctx context.Context, path string, body []byte) ([]byte, error) {
requestURL, err := url.Parse(fmt.Sprintf("%s%s", c.serverAddress, path))
if err != nil {
return nil, fmt.Errorf("failed to parse URL path %v: %v", path, err)
Expand All @@ -66,7 +66,7 @@ func (c *componentInventoryClient) post(ctx context.Context, path string, body [
return c.do(req)
}

func (c *componentInventoryClient) do(req *http.Request) ([]byte, error) {
func (c *cisClient) do(req *http.Request) ([]byte, error) {
req.Header.Set("Content-Type", "application/json")

if c.authToken != "" {
Expand Down
11 changes: 6 additions & 5 deletions pkg/api/constants/constants.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package constants

const (
LivenessEndpoint = "/_health/liveness"
VersionEndpoint = "/api/version"
ComponentsEndpoint = "/components"
InbandInventoryEndpoint = "/inventory/in-band"
OutofbandInventoryEndpoint = "/inventory/out-of-band"
LivenessEndpoint = "/_health/liveness"
VersionEndpoint = "/api/version"
ComponentsEndpoint = "/components"
InventoryEndpoint = "/inventory"
OutOfBandMode = "outofband"
InBandMode = "inband"
)
55 changes: 27 additions & 28 deletions pkg/api/routes/components.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,36 +7,35 @@ import (

// compareComponents compares components between two rivets.Server.
// It logs differences and return false if there are differences.
// The return value is used for testing only.
func compareComponents(fleetServer, alloyServer *rivets.Server, log *zap.Logger) bool {
match := true
alloyComponentsMap := make(map[string][]*rivets.Component)
for _, component := range alloyServer.Components {
slug := component.Name
if _, ok := alloyComponentsMap[slug]; !ok {
alloyComponentsMap[slug] = make([]*rivets.Component, 0)
}
alloyComponentsMap[slug] = append(alloyComponentsMap[slug], component)
func compareComponents(fleetServer, alloyServer *rivets.Server, log *zap.Logger) {
alloyMap := componentsToMap(alloyServer.Components)
fleetMap := componentsToMap(fleetServer.Components)
log.Debug("enumerating incoming")
for k, v := range alloyMap {
log.With(
zap.String("component.name", k),
zap.Int("component.count", len(v)),
).Debug("incoming component")
}
log.Debug("enumerating existing")
for k, v := range fleetMap {
log.With(
zap.String("component.name", k),
zap.Int("component.count", len(v)),
).Debug("existing component")
}
}

for _, fleetComponent := range fleetServer.Components {
slug := fleetComponent.Name
_, ok := alloyComponentsMap[slug]
if !ok {
match = false
// no slug in alloy list, fleet component not in alloy list
fields := []zap.Field{
zap.String("device.id", fleetServer.ID),
zap.String("component", slug),
}
log.Warn("fleetdb component not listed in alloy", fields...)
continue
}
type componentMap map[string][]*rivets.Component

log.With(
zap.String("device.id", fleetServer.ID),
zap.String("component", slug),
).Info("placeholder for server component firmware check")
func componentsToMap(cs []*rivets.Component) componentMap {
theMap := make(map[string][]*rivets.Component)
for _, c := range cs {
name := c.Name
// cSlice can be nil. Appending to nil is OK.
cSlice := theMap[name]
cSlice = append(cSlice, c)
theMap[name] = cSlice
}
return match
return theMap
}
37 changes: 24 additions & 13 deletions pkg/api/routes/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,13 @@ func ComposeHTTPServer(theApp *app.App) *http.Server {
return
}

// XXX: hardcoded inband inventory!
existing, _, err := theApp.FleetDB.GetServerInventory(ctx, serverID, true)
getInband := true
qVal, set := ctx.GetQuery("mode")
if set && qVal == constants.OutOfBandMode {
getInband = false
}

existing, _, err := theApp.FleetDB.GetServerInventory(ctx, serverID, getInband)
if err != nil {
ctx.JSON(http.StatusInternalServerError, map[string]any{
"message": "components unavailable",
Expand All @@ -144,14 +149,9 @@ func ComposeHTTPServer(theApp *app.App) *http.Server {
})

// add an API to ingest inventory data
g.POST(constants.InbandInventoryEndpoint+"/:server",
composeAuthHandler(updateScopes("server:component")),
composeInventoryHandler(theApp, true),
)

g.POST(constants.OutofbandInventoryEndpoint+"/:server",
g.POST(constants.InventoryEndpoint+"/:server",
composeAuthHandler(updateScopes("server:component")),
composeInventoryHandler(theApp, false),
composeInventoryHandler(theApp),
)

return &http.Server{
Expand Down Expand Up @@ -199,7 +199,7 @@ func reject(ctx *gin.Context, code int, msg, err string) {
})
}

func composeInventoryHandler(theApp *app.App, inband bool) gin.HandlerFunc {
func composeInventoryHandler(theApp *app.App) gin.HandlerFunc {
logger := theApp.Log
fdb := theApp.FleetDB
return func(ctx *gin.Context) {
Expand All @@ -213,6 +213,17 @@ func composeInventoryHandler(theApp *app.App, inband bool) gin.HandlerFunc {
return
}

inband := true
qVal, set := ctx.GetQuery("mode")
if set && qVal == constants.OutOfBandMode {
inband = false
}

logger.With(
zap.String("server.id", serverID.String()),
zap.Bool("inband", inband),
).Debug("processing inventory")

var dev types.InventoryDevice
if err = ctx.BindJSON(&dev); err != nil {
logger.With(
Expand All @@ -230,13 +241,13 @@ func composeInventoryHandler(theApp *app.App, inband bool) gin.HandlerFunc {

existing, _, err := fdb.GetServerInventory(ctx, serverID, inband)
if err != nil {
// XXX: need to distinguish between failures to reach FleetDB and failures to find the server
reject(ctx, http.StatusBadRequest, "server not exisit", err.Error())
logger.With(zap.Error(err)).Warn("server lookup")
reject(ctx, http.StatusBadRequest, "unable to retrieve server", err.Error())
return
}

latest := iconv.ToRivetsServer(existing.Name, existing.Facility, dev.Inv, dev.BiosCfg)
// sanity check the latest
// sanity check the latest to what exists in FleetDB
compareComponents(existing, latest, logger)

_, err = fdb.SetServerInventory(ctx, serverID, latest, inband)
Expand Down

0 comments on commit 838579f

Please sign in to comment.