Skip to content

Commit

Permalink
Update dell-hwmgr adaptor to align with NodePool CRD changes
Browse files Browse the repository at this point in the history
Signed-off-by: Don Penney <[email protected]>
  • Loading branch information
donpenney committed Nov 19, 2024
1 parent 37de970 commit da04bc2
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 65 deletions.
77 changes: 25 additions & 52 deletions adaptors/dell-hwmgr/hwmgrclient/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,6 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"
)

// TODO: Define how these labels are specified. New field in NodePool?
// For now, we'll use an enum and label and hardcode a correlation to the nodegroup list order
const (
ResourceSelectorControllerIdx = iota
ResourceSelectorWorkerIdx

ResourceSelectorControllerLabel = "controller" // TODO:
ResourceSelectorWorkerLabel = "worker"
)

const (
RoleKey = "role"
Tenant = "default_tenant" // TODO: Hardcoded, for now
Expand Down Expand Up @@ -204,56 +194,39 @@ func ResourceGroupIdFromNodePool(nodepool *hwmgmtv1alpha1.NodePool) string {
func ResourceGroupFromNodePool(nodepool *hwmgmtv1alpha1.NodePool) *hwmgrapi.CreateResourceGroupJSONRequestBody {
rgId := ResourceGroupIdFromNodePool(nodepool)
tenant := Tenant
// TODO: Get these values appropriately
resourceTypeId := "ResourceGroup~2.1.1"
resourceTypeId := utils.GetResourceTypeId(nodepool)
description := "Resource Group managed by O-Cloud Hardware Manager Plugin"
excludes := make(map[string]interface{})
roleKey := RoleKey
// TODO: What should the roles be?
controllerRole := ResourceSelectorControllerLabel
workerRole := ResourceSelectorWorkerLabel

rg := hwmgrapi.CreateResourceGroupJSONRequestBody{
Tenant: &tenant,
ResourceGroup: &hwmgrapi.RhprotoResourceGroupObjectRequest{
Description: &description,
Id: &rgId,
Name: &rgId,
ResourceTypeId: &resourceTypeId,
ResourceSelectors: &map[string]hwmgrapi.RhprotoResourceSelectorRequest{
ResourceSelectorControllerLabel: {
RpId: &nodepool.Spec.NodeGroup[ResourceSelectorControllerIdx].Name,
ResourceProfileId: &nodepool.Spec.NodeGroup[ResourceSelectorControllerIdx].HwProfile,
NumResources: &nodepool.Spec.NodeGroup[ResourceSelectorControllerIdx].Size,
Filters: &hwmgrapi.RhprotoResourceSelectorFilter{
Include: &hwmgrapi.RhprotoResourceSelectorFilterInclude{
Labels: &[]hwmgrapi.RhprotoResourceSelectorFilterIncludeLabel{
{
Key: &roleKey,
Value: &controllerRole,
},
},
},
Exclude: &excludes,
},
},
ResourceSelectorWorkerLabel: {
RpId: &nodepool.Spec.NodeGroup[ResourceSelectorWorkerIdx].Name,
ResourceProfileId: &nodepool.Spec.NodeGroup[ResourceSelectorWorkerIdx].HwProfile,
NumResources: &nodepool.Spec.NodeGroup[ResourceSelectorWorkerIdx].Size,
Filters: &hwmgrapi.RhprotoResourceSelectorFilter{
Include: &hwmgrapi.RhprotoResourceSelectorFilterInclude{
Labels: &[]hwmgrapi.RhprotoResourceSelectorFilterIncludeLabel{
{
Key: &roleKey,
Value: &workerRole,
},
},
resourceSelectors := make(map[string]hwmgrapi.RhprotoResourceSelectorRequest)
for _, nodegroup := range nodepool.Spec.NodeGroup {
resourceSelectors[nodegroup.Name] = hwmgrapi.RhprotoResourceSelectorRequest{
RpId: &nodegroup.ResourcePoolId,
ResourceProfileId: &nodegroup.HwProfile,
NumResources: &nodegroup.Size,
Filters: &hwmgrapi.RhprotoResourceSelectorFilter{
Include: &hwmgrapi.RhprotoResourceSelectorFilterInclude{
Labels: &[]hwmgrapi.RhprotoResourceSelectorFilterIncludeLabel{
{
Key: &roleKey,
Value: &nodegroup.Name, // TODO: This should be nodegroup.Role, but has to be nodegroup.Name for now
},
Exclude: &excludes,
},
},
Exclude: &excludes,
},
}
}

rg := hwmgrapi.CreateResourceGroupJSONRequestBody{
Tenant: &tenant,
ResourceGroup: &hwmgrapi.RhprotoResourceGroupObjectRequest{
Description: &description,
Id: &rgId,
Name: &rgId,
ResourceTypeId: &resourceTypeId,
ResourceSelectors: &resourceSelectors,
},
}

Expand Down
42 changes: 34 additions & 8 deletions adaptors/dell-hwmgr/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
"github.com/openshift-kni/oran-hwmgr-plugin/internal/controller/utils"
"github.com/openshift-kni/oran-hwmgr-plugin/internal/logging"
hwmgmtv1alpha1 "github.com/openshift-kni/oran-o2ims/api/hardwaremanagement/v1alpha1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/util/retry"
Expand Down Expand Up @@ -58,20 +59,42 @@ type ExtensionInterface struct {
Ports []ExtensionPort `json:"ports,omitempty"`
}

func bmcSecretName(nodename string) string {
return fmt.Sprintf("%s-bmc-secret", nodename)
}

// CheckBMCSecret creates the bmc-secret for a node
func (a *Adaptor) CheckBMCSecret(ctx context.Context, resource hwmgrapi.RhprotoResource) error {
nodename := *resource.Id

a.Logger.InfoContext(ctx, "Checking bmc-secret:", "nodename", nodename)

secretName := bmcSecretName(nodename)

// TODO: For now, just check that the secret exists. Once the creds are accessible, we can create the secret
bmcSecret := &corev1.Secret{}

if err := a.Get(ctx, types.NamespacedName{Name: secretName, Namespace: a.Namespace}, bmcSecret); err != nil {
return fmt.Errorf("failed to get secret %s: %w", secretName, err)
}

return nil
}

// AllocateNode processes a NodePool CR, allocating a free node for each specified nodegroup as needed
func (a *Adaptor) AllocateNode(ctx context.Context, nodepool *hwmgmtv1alpha1.NodePool, resource hwmgrapi.RhprotoResource) (string, error) {
func (a *Adaptor) AllocateNode(ctx context.Context, nodepool *hwmgmtv1alpha1.NodePool, resource hwmgrapi.RhprotoResource, nodegroupName string) (string, error) {
nodename := *resource.Id
ctx = logging.AppendCtx(ctx, slog.String("nodenameCtx", nodename))

// TODO: Need to be able to create a BMC secret, but we don't have access?
// if err := a.CreateBMCSecret(ctx, nodename, nodeinfo.BMC.UsernameBase64, nodeinfo.BMC.PasswordBase64); err != nil {
// return fmt.Errorf("failed to create bmc-secret when allocating node %s: %w", nodename, err)
// }
if err := a.ValidateNodeConfig(resource); err != nil {
if err := a.ValidateNodeConfig(ctx, resource); err != nil {
return "", fmt.Errorf("failed to validate resource configuration: %w", err)
}

if err := a.CreateNode(ctx, nodepool, resource); err != nil {
if err := a.CreateNode(ctx, nodepool, resource, nodegroupName); err != nil {
return "", fmt.Errorf("failed to create allocated node (%s): %w", *resource.Id, err)
}

Expand Down Expand Up @@ -144,7 +167,7 @@ func (a *Adaptor) getNodeInterfaces(resource hwmgrapi.RhprotoResource) ([]*hwmgm
}

// ValidateNodeConfig performs basic data structure validation on the resource
func (a *Adaptor) ValidateNodeConfig(resource hwmgrapi.RhprotoResource) error {
func (a *Adaptor) ValidateNodeConfig(ctx context.Context, resource hwmgrapi.RhprotoResource) error {
// Check required fields
if resource.ResourceAttribute == nil ||
resource.ResourceAttribute.Compute == nil ||
Expand All @@ -154,6 +177,10 @@ func (a *Adaptor) ValidateNodeConfig(resource hwmgrapi.RhprotoResource) error {
return fmt.Errorf("resource structure missing required resource attribute field")
}

if err := a.CheckBMCSecret(ctx, resource); err != nil {
return fmt.Errorf("bmc-secret check failed: %w", err)
}

if _, err := a.parseExtensionInterfaces(resource); err != nil {
return fmt.Errorf("invalid interface list: %w", err)
}
Expand All @@ -162,9 +189,8 @@ func (a *Adaptor) ValidateNodeConfig(resource hwmgrapi.RhprotoResource) error {
}

// CreateNode creates a Node CR with specified attributes
func (a *Adaptor) CreateNode(ctx context.Context, nodepool *hwmgmtv1alpha1.NodePool, resource hwmgrapi.RhprotoResource) error {
func (a *Adaptor) CreateNode(ctx context.Context, nodepool *hwmgmtv1alpha1.NodePool, resource hwmgrapi.RhprotoResource, nodegroupName string) error {
nodename := *resource.Id
groupname := *resource.ResourcePoolId
hwprofile := *resource.ResourceProfileID

a.Logger.InfoContext(ctx, "Creating node")
Expand All @@ -184,7 +210,7 @@ func (a *Adaptor) CreateNode(ctx context.Context, nodepool *hwmgmtv1alpha1.NodeP
},
Spec: hwmgmtv1alpha1.NodeSpec{
NodePool: nodepool.Name,
GroupName: groupname,
GroupName: nodegroupName,
HwProfile: hwprofile,
},
}
Expand Down Expand Up @@ -212,7 +238,7 @@ func (a *Adaptor) UpdateNodeStatus(ctx context.Context, resource hwmgrapi.Rhprot

node.Status.BMC = &hwmgmtv1alpha1.BMC{
Address: IdracUrlPrefix + *resource.ResourceAttribute.Compute.Lom.IpAddress + IdracUrlSuffix,
CredentialsName: *resource.ResourceAttribute.Compute.Lom.Password,
CredentialsName: bmcSecretName(nodename),
}
node.Status.Hostname = *resource.Name // TODO: Define how the hostname is set

Expand Down
9 changes: 5 additions & 4 deletions adaptors/dell-hwmgr/nodepool.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,9 @@ const (

// ValidateNodePool performs basic validation of the nodepool data
func (a *Adaptor) ValidateNodePool(nodepool *hwmgmtv1alpha1.NodePool) error {
if len(nodepool.Spec.NodeGroup) != 2 {
return fmt.Errorf("nodepool %s invalid: Expected 2 entries in .spec.nodeGroup, got %d", nodepool.Name, len(nodepool.Spec.NodeGroup))
resourceTypeId := utils.GetResourceTypeId(nodepool)
if resourceTypeId == "" {
return fmt.Errorf("nodepool %s is missing resourceTypeId in spec", nodepool.Name)
}

return nil
Expand Down Expand Up @@ -185,13 +186,13 @@ func (a *Adaptor) HandleNodePoolProcessing(
// TODO: Need to add validation to ensure the rg satisfies the nodepool

// Create the Node CRs corresponding to the allocated resources
for _, resourceSelector := range *rg.ResourceSelectors {
for nodegroupName, resourceSelector := range *rg.ResourceSelectors {
for _, node := range *resourceSelector.Resources {
if slices.Contains(nodepool.Status.Properties.NodeNames, *node.Id) {
a.Logger.InfoContext(ctx, "Node is already added", slog.String("nodename", *node.Id))
continue
}
if nodename, err := a.AllocateNode(ctx, nodepool, node); err != nil {
if nodename, err := a.AllocateNode(ctx, nodepool, node, nodegroupName); err != nil {
a.Logger.InfoContext(ctx, "Failed allocating node", slog.String("err", err.Error()))
if err := utils.UpdateNodePoolStatusCondition(ctx, a.Client, nodepool,
hwmgmtv1alpha1.Provisioned, hwmgmtv1alpha1.Failed, metav1.ConditionFalse,
Expand Down
9 changes: 8 additions & 1 deletion internal/controller/utils/nodepool_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,14 @@ import (
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
)

const NodepoolFinalizer = "oran-hwmgr-plugin/nodepool-finalizer"
const (
NodepoolFinalizer = "oran-hwmgr-plugin/nodepool-finalizer"
ResourceTypeIdKey = "resourceTypeId"
)

func GetResourceTypeId(nodepool *hwmgmtv1alpha1.NodePool) string {
return nodepool.Spec.Extensions[ResourceTypeIdKey]
}

func GetNodePoolProvisionedCondition(nodepool *hwmgmtv1alpha1.NodePool) *metav1.Condition {
return meta.FindStatusCondition(
Expand Down

0 comments on commit da04bc2

Please sign in to comment.