Skip to content

Commit 427121f

Browse files
committed
allow empty systemUuid, generate pseudoUuid from serial
1 parent f90c9e2 commit 427121f

File tree

3 files changed

+68
-11
lines changed

3 files changed

+68
-11
lines changed

api/v1alpha1/server_types.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,9 @@ type ServerSpec struct {
8383
UUID string `json:"uuid,omitempty"`
8484

8585
// SystemUUID is the unique identifier for the server.
86-
// +required
86+
// If not provided, it will be derived from the serial
87+
// during the discovery phase when the probe registers system details.
88+
// +optional
8789
SystemUUID string `json:"systemUUID"`
8890

8991
// SystemURI is the unique URI for the server resource in REDFISH API.

bmc/redfish.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -851,7 +851,9 @@ func (r *RedfishBMC) getSystemFromUri(ctx context.Context, systemURI string) (*r
851851
}); err != nil {
852852
return nil, fmt.Errorf("failed to wait for for server systems to be ready: %w", err)
853853
}
854-
if system.UUID != "" {
854+
// System is considered ready even if UUID is empty - allow graceful handling of systems
855+
// that don't expose System.UUID in their Redfish payload
856+
if system != nil {
855857
return system, nil
856858
}
857859
return nil, fmt.Errorf("no system found for %v", systemURI)

internal/controller/server_controller.go

Lines changed: 62 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package controller
55

66
import (
77
"context"
8+
"crypto/md5"
89
"crypto/rand"
910
"crypto/rsa"
1011
"encoding/json"
@@ -812,6 +813,7 @@ func (r *ServerReconciler) extractServerDetailsFromRegistry(ctx context.Context,
812813
}
813814

814815
serverBase := server.DeepCopy()
816+
815817
// update network interfaces
816818
nics := make([]metalv1alpha1.NetworkInterface, 0, len(serverDetails.NetworkInterfaces))
817819
for _, s := range serverDetails.NetworkInterfaces {
@@ -888,6 +890,23 @@ func (r *ServerReconciler) patchServerState(ctx context.Context, server *metalv1
888890
return true, nil
889891
}
890892

893+
// generatePseudoUUID generates a deterministic UUID from an input string.
894+
// Format: 99999999-xxxx-3xxx-8xxx-xxxxxxxxxxxx (prefix identifies generated UUIDs)
895+
func generatePseudoUUID(input string) string {
896+
hash := md5.Sum([]byte(input))
897+
hashHex := fmt.Sprintf("%x", hash[:])
898+
899+
// Build UUID with version (3) and variant (8) bits set
900+
uuid := fmt.Sprintf("99999999-%s-%s3%s-8%s-%s",
901+
hashHex[0:4],
902+
hashHex[4:8],
903+
hashHex[8:11],
904+
hashHex[11:14],
905+
hashHex[14:32],
906+
)
907+
return uuid
908+
}
909+
891910
func (r *ServerReconciler) patchServerURI(ctx context.Context, log logr.Logger, bmcClient bmc.BMC, server *metalv1alpha1.Server) (bool, error) {
892911
if len(server.Spec.SystemURI) != 0 {
893912
return false, nil
@@ -899,21 +918,55 @@ func (r *ServerReconciler) patchServerURI(ctx context.Context, log logr.Logger,
899918
return false, err
900919
}
901920

902-
for _, system := range systems {
903-
if strings.EqualFold(system.UUID, server.Spec.SystemUUID) {
904-
serverBase := server.DeepCopy()
905-
server.Spec.SystemURI = system.URI
906-
if err := r.Patch(ctx, server, client.MergeFrom(serverBase)); err != nil {
907-
return false, fmt.Errorf("failed to patch server URI: %w", err)
921+
// Try to find system by UUID if one is provided
922+
if len(server.Spec.SystemUUID) > 0 {
923+
for _, system := range systems {
924+
if strings.EqualFold(system.UUID, server.Spec.SystemUUID) {
925+
serverBase := server.DeepCopy()
926+
server.Spec.SystemURI = system.URI
927+
if err := r.Patch(ctx, server, client.MergeFrom(serverBase)); err != nil {
928+
return false, fmt.Errorf("failed to patch server URI: %w", err)
929+
}
930+
return true, nil
908931
}
909932
}
910933
}
911-
if len(server.Spec.SystemURI) == 0 {
912-
log.V(1).Info("Patching systemURI failed", "no system found for UUID", server.Spec.SystemUUID)
934+
935+
// If no system found by UUID or UUID is empty, and we only have one system, use it
936+
// This handles cases where the Redfish implementation doesn't provide System.UUID
937+
if len(systems) == 1 {
938+
system := systems[0]
939+
serverBase := server.DeepCopy()
940+
server.Spec.SystemURI = system.URI
941+
942+
// If SystemUUID is empty, use system UUID if available, otherwise generate from SerialNumber
943+
if len(server.Spec.SystemUUID) == 0 {
944+
if len(system.UUID) > 0 {
945+
server.Spec.SystemUUID = system.UUID
946+
} else if len(system.SerialNumber) > 0 {
947+
server.Spec.SystemUUID = generatePseudoUUID(system.SerialNumber)
948+
log.V(1).Info("Generated pseudo-UUID from system serial number",
949+
"serialNumber", system.SerialNumber, "pseudoUUID", server.Spec.SystemUUID)
950+
} else {
951+
return false, fmt.Errorf("system does not provide UUID or SerialNumber; cannot generate a unique identifier")
952+
}
953+
}
954+
955+
if err := r.Patch(ctx, server, client.MergeFrom(serverBase)); err != nil {
956+
return false, fmt.Errorf("failed to patch server URI: %w", err)
957+
}
958+
return true, nil
959+
}
960+
961+
// Multiple systems available but couldn't match by UUID
962+
if len(server.Spec.SystemUUID) > 0 {
963+
log.V(1).Info("No system found for UUID, and multiple systems available", "requestedUUID", server.Spec.SystemUUID)
913964
return false, fmt.Errorf("unable to find system URI for UUID: %v", server.Spec.SystemUUID)
914965
}
915966

916-
return true, nil
967+
// No SystemUUID provided and multiple systems available - cannot determine which to use
968+
log.V(1).Info("No SystemUUID provided and multiple systems available, cannot determine target system")
969+
return false, fmt.Errorf("SystemUUID must be provided when multiple systems are available")
917970
}
918971

919972
func (r *ServerReconciler) ensureServerPowerState(ctx context.Context, log logr.Logger, bmcClient bmc.BMC, server *metalv1alpha1.Server) error {

0 commit comments

Comments
 (0)