From efc1633cce3aaab074ebd0fde42fba1915df9290 Mon Sep 17 00:00:00 2001 From: Georgi Chulkov Date: Fri, 3 May 2024 13:47:39 +0200 Subject: [PATCH] Add BMC info to OOBs --- internal/bmc/fake.go | 24 +++++++++++++- internal/bmc/ipmi.go | 29 +++++++++-------- internal/bmc/redfish.go | 2 +- internal/controller/oob_controller.go | 47 ++++++++++++++++++++++++--- 4 files changed, 82 insertions(+), 20 deletions(-) diff --git a/internal/bmc/fake.go b/internal/bmc/fake.go index 2e0ab316..a231cab3 100644 --- a/internal/bmc/fake.go +++ b/internal/bmc/fake.go @@ -8,6 +8,8 @@ import ( "fmt" "regexp" "time" + + "github.com/google/uuid" ) func RegisterFake() { @@ -81,7 +83,27 @@ func (b *FakeBMC) DeleteUsers(_ context.Context, _ *regexp.Regexp) error { } func (b *FakeBMC) ReadInfo(_ context.Context) (Info, error) { - return Info{}, nil + id, err := uuid.NewRandom() + if err != nil { + return Info{}, fmt.Errorf("cannot generate UUID: %w", err) + } + + return Info{ + Type: TypeMachine, + Manufacturer: "Fake", + SerialNumber: "0", + FirmwareVersion: "1", + Machines: []Machine{ + { + UUID: id.String(), + Manufacturer: "Fake", + SKU: "Fake-0", + SerialNumber: "1", + Power: PowerOn, + LocatorLED: LEDOff, + }, + }, + }, nil } func (b *FakeBMC) SetLocatorLED(_ context.Context, state LED) (LED, error) { diff --git a/internal/bmc/ipmi.go b/internal/bmc/ipmi.go index e93d2b8a..13c3d7f1 100644 --- a/internal/bmc/ipmi.go +++ b/internal/bmc/ipmi.go @@ -14,6 +14,7 @@ import ( "time" "github.com/hashicorp/go-multierror" + "github.com/ironcore-dev/metal/internal/log" ) @@ -68,20 +69,20 @@ type IPMIUser struct { // TODO: ipmi ciphers, should this also be tested? -func outputmap(ml string, mi *map[string]string) { - for _, line := range strings.Split(ml, "\n") { - colon := strings.Index(line, ":") - if colon == -1 { - continue - } - k := strings.TrimSpace(line[:colon]) - v := strings.TrimSpace(line[colon+1:]) - if k == "" { - continue - } - (*mi)[k] = v - } -} +//func outputmap(ml string, mi *map[string]string) { +// for _, line := range strings.Split(ml, "\n") { +// colon := strings.Index(line, ":") +// if colon == -1 { +// continue +// } +// k := strings.TrimSpace(line[:colon]) +// v := strings.TrimSpace(line[colon+1:]) +// if k == "" { +// continue +// } +// (*mi)[k] = v +// } +//} func outputmapspace(ml string, mi *map[string]string) { for _, line := range strings.Split(ml, "\n") { diff --git a/internal/bmc/redfish.go b/internal/bmc/redfish.go index ead011a8..3288e872 100644 --- a/internal/bmc/redfish.go +++ b/internal/bmc/redfish.go @@ -634,7 +634,7 @@ func (b *RedfishBMC) ReadInfo(ctx context.Context) (Info, error) { machine.SerialNumber = system.SerialNumber machine.UUID = strings.ToLower(system.UUID) if machine.UUID == "" { - return Info{}, fmt.Errorf("System has no UUID") + return Info{}, fmt.Errorf("system has no UUID") } info.Machines = append(info.Machines, machine) } diff --git a/internal/controller/oob_controller.go b/internal/controller/oob_controller.go index b4fb101c..673f91df 100644 --- a/internal/controller/oob_controller.go +++ b/internal/controller/oob_controller.go @@ -61,9 +61,9 @@ const ( OOBSecretSpecMACAddress = ".spec.MACAddress" // OOBTemporaryNamespaceHack TODO: Remove temporary namespace hack. OOBTemporaryNamespaceHack = "oob" - - OOBErrorBadEndpoint = "BadEndpoint" - OOBErrorBadCredentials = "BadCredentials" + OOBErrorBadEndpoint = "BadEndpoint" + OOBErrorBadCredentials = "BadCredentials" + OOBErrorBadInfo = "BadInfo" ) func NewOOBReconciler(systemNamespace, ipLabelSelector, macDB string, credsRenewalBeforeExpiry time.Duration, usernamePrefix, temporaryPasswordSecret string) (*OOBReconciler, error) { @@ -131,6 +131,7 @@ type access struct { } type ctxkOOBHost struct{} +type ctxkBMC struct{} func (r *OOBReconciler) PreStart(ctx context.Context) error { return r.ensureTemporaryPassword(ctx) @@ -291,6 +292,15 @@ func (r *OOBReconciler) reconcile(ctx context.Context, oob *metalv1alpha1.OOB) ( return ctrl.Result{}, err } + ctx, advance, err = r.runPhase(ctx, oob, oobRecPhase{ + name: "Info", + run: r.processInfo, + errType: OOBErrorBadInfo, + }) + if !advance { + return ctrl.Result{}, err + } + ctx, advance, err = r.runPhase(ctx, oob, oobRecPhase{ name: "Ready", run: r.processReady, @@ -825,7 +835,36 @@ func (r *OOBReconciler) processCredentials(ctx context.Context, oob *metalv1alph } } - return ctx, apply, nil, nil + return context.WithValue(ctx, ctxkBMC{}, b), apply, status, nil +} + +func (r *OOBReconciler) processInfo(ctx context.Context, oob *metalv1alpha1.OOB) (context.Context, *metalv1alpha1apply.OOBApplyConfiguration, *metalv1alpha1apply.OOBStatusApplyConfiguration, error) { + b := ctx.Value(ctxkBMC{}).(bmc.BMC) + + var status *metalv1alpha1apply.OOBStatusApplyConfiguration + + log.Info(ctx, "Reading BMC info") + info, err := b.ReadInfo(ctx) + if err != nil { + return r.setError(ctx, oob, nil, status, OOBErrorBadInfo, fmt.Errorf("cannot read BMC info: %w", err)) + } + + if oob.Status.Manufacturer != info.Manufacturer || + oob.Status.SerialNumber != info.SerialNumber || + oob.Status.FirmwareVersion != info.FirmwareVersion { + log.Debug(ctx, "Setting manufacturer, serial number, and firmware version") + var applyst *metalv1alpha1apply.OOBApplyConfiguration + applyst, err = metalv1alpha1apply.ExtractOOBStatus(oob, OOBFieldManager) + if err != nil { + return ctx, nil, nil, fmt.Errorf("cannot extract OOB status: %w", err) + } + status = util.Ensure(applyst.Status). + WithManufacturer(info.Manufacturer). + WithSerialNumber(info.SerialNumber). + WithFirmwareVersion(info.FirmwareVersion) + } + + return ctx, nil, status, nil } func (r *OOBReconciler) processReady(ctx context.Context, oob *metalv1alpha1.OOB) (context.Context, *metalv1alpha1apply.OOBApplyConfiguration, *metalv1alpha1apply.OOBStatusApplyConfiguration, error) {