Skip to content

Commit

Permalink
api: types: introduce NodeGroupStatus
Browse files Browse the repository at this point in the history
Similar there is NodeGroup to set the node group configuration under the
resource's spec, we want to track each node group's status.

So far tracking the status was dependant on having lists of all affected
MachineConfigPools associated with their NodeGroupConfig; list of all
the daemonsets owned by the resources and general operator conditions
and related objects.

As a preparation step to enabling NodeSelector under the node group
(replacing MCP on HCP) we want a way to track the statuses of the node
groups and their configs. Because NodeGroupConfigs in the operator
status were reflected only as part of v1.MachineConfigPool this will not
support our needs. So we want to have a structure that would match for
any selector and a better way to follow on the node-group status,
hence introducing NodeGroupStatus a type that will point to the status
of each NodeGroup in the operator spec. This type includes:
* 1 MCP Name
* 1 Daemonset
* The configuration setting of the RTE on this group

Signed-off-by: Shereen Haj <[email protected]>
  • Loading branch information
shajmakh committed Sep 20, 2024
1 parent e2e5478 commit d4cd5f4
Show file tree
Hide file tree
Showing 16 changed files with 336 additions and 141 deletions.
35 changes: 17 additions & 18 deletions api/numaresourcesoperator/v1/numaresourcesoperator_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ package v1

import (
"fmt"

corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

Expand Down Expand Up @@ -120,32 +119,32 @@ type NodeGroup struct {
Config *NodeGroupConfig `json:"config,omitempty"`
}

// NodeGroupStatus defines the status of a single node group
type NodeGroupStatus struct {
// DaemonSet of the configured RTE for this node group
//+operator-sdk:csv:customresourcedefinitions:type=status,displayName="RTE DaemonSet"
DaemonSet NamespacedName `json:"daemonsets,omitempty"`
// NodeGroupConfig represents the latest available configuration applied to this NodeGroup
//+operator-sdk:csv:customresourcedefinitions:type=status,displayName="Optional configuration enforced on this NodeGroup"
Config *NodeGroupConfig `json:"config,omitempty"`
// MachineConfigPoolName matches the name of the MCP derived from the MCP selector
//+operator-sdk:csv:customresourcedefinitions:type=status,displayName="Matching MCP name for this node group"
MachineConfigPoolName string `json:"machineConfigPoolName"`
}

// NUMAResourcesOperatorStatus defines the observed state of NUMAResourcesOperator
type NUMAResourcesOperatorStatus struct {
// DaemonSets of the configured RTEs, one per node group
//+operator-sdk:csv:customresourcedefinitions:type=status,displayName="RTE DaemonSets"
DaemonSets []NamespacedName `json:"daemonsets,omitempty"`
// MachineConfigPools resolved from configured node groups
//+operator-sdk:csv:customresourcedefinitions:type=status,displayName="RTE MCPs from node groups"
MachineConfigPools []MachineConfigPool `json:"machineconfigpools,omitempty"`
// Conditions show the current state of the NUMAResourcesOperator Operator
// NodeGroups report the observed status of the configured NodeGroups, matching by their name
// +optional
//+operator-sdk:csv:customresourcedefinitions:type=status,displayName="Node groups observed status"
NodeGroups []NodeGroupStatus `json:"nodeGroups,omitempty"` // Conditions show the current state of the NUMAResourcesOperator Operator
//+operator-sdk:csv:customresourcedefinitions:type=status,displayName="Condition reported"
Conditions []metav1.Condition `json:"conditions,omitempty"`
// RelatedObjects list of objects of interest for this operator
//+operator-sdk:csv:customresourcedefinitions:type=status,displayName="Related Objects"
RelatedObjects []configv1.ObjectReference `json:"relatedObjects,omitempty"`
}

// MachineConfigPool defines the observed state of each MachineConfigPool selected by node groups
type MachineConfigPool struct {
// Name the name of the machine config pool
Name string `json:"name"`
// NodeGroupConfig represents the latest available configuration applied to this MachineConfigPool
// +optional
//+operator-sdk:csv:customresourcedefinitions:type=status,displayName="Optional configuration enforced on this NodeGroup"
Config *NodeGroupConfig `json:"config,omitempty"`
}

//+genclient
//+genclient:nonNamespaced
//+kubebuilder:object:root=true
Expand Down
52 changes: 24 additions & 28 deletions api/numaresourcesoperator/v1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ limitations under the License.
package v1alpha1

import (
"fmt"
"github.com/openshift-kni/numaresources-operator/pkg/objectnames"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/controller-runtime/pkg/conversion"

Expand Down Expand Up @@ -74,20 +76,31 @@ func (src *NUMAResourcesOperator) ConvertToV1Rote(dst *nropv1.NUMAResourcesOpera
}
// Status
if src.Status.DaemonSets != nil {
dst.Status.DaemonSets = make([]nropv1.NamespacedName, 0, len(src.Status.DaemonSets))
for idx := range src.Status.DaemonSets {
dst.Status.DaemonSets = append(dst.Status.DaemonSets, nropv1.NamespacedName{
Namespace: src.Status.DaemonSets[idx].Namespace,
Name: src.Status.DaemonSets[idx].Name,
})
for _, ds := range src.Status.DaemonSets {
ngDetected := false
for _, ngStatus := range dst.Status.NodeGroups {
if ngStatus.MachineConfigPoolName == objectnames.GetAssociatedNameFromRTEDaemonset(ds.Name, dst.Name) {
ngStatus.DaemonSet = nropv1.NamespacedName{
Namespace: ds.Namespace,
Name: ds.Name,
}

ngDetected = true
}
}

if !ngDetected {
return fmt.Errorf("could not detect node group matching daemonset %s", ds.Name)
}
}
}
if src.Status.MachineConfigPools != nil {
dst.Status.MachineConfigPools = make([]nropv1.MachineConfigPool, 0, len(src.Status.MachineConfigPools))
dst.Status.NodeGroups = make([]nropv1.NodeGroupStatus, 0, len(src.Status.MachineConfigPools))
for idx := range src.Status.MachineConfigPools {
dst.Status.MachineConfigPools = append(dst.Status.MachineConfigPools, convertMachineConfigPoolV1Alpha1ToV1(src.Status.MachineConfigPools[idx]))
dst.Status.NodeGroups = append(dst.Status.NodeGroups, nropv1.NodeGroupStatus{MachineConfigPoolName: src.Status.MachineConfigPools[idx].Name})
}
}

if src.Status.Conditions != nil {
dst.Status.Conditions = make([]metav1.Condition, len(src.Status.Conditions))
copy(dst.Status.Conditions, src.Status.Conditions)
Expand Down Expand Up @@ -120,44 +133,30 @@ func (dst *NUMAResourcesOperator) ConvertFromV1Rote(src *nropv1.NUMAResourcesOpe
dst.Spec.PodExcludes[idx].Name = src.Spec.PodExcludes[idx].Name
}
}

// Status
if src.Status.DaemonSets != nil {
dst.Status.DaemonSets = make([]NamespacedName, len(src.Status.DaemonSets))
for idx := range src.Spec.PodExcludes {
dst.Spec.PodExcludes[idx].Namespace = src.Spec.PodExcludes[idx].Namespace
dst.Spec.PodExcludes[idx].Name = src.Spec.PodExcludes[idx].Name
}
}
if src.Status.MachineConfigPools != nil {
dst.Status.MachineConfigPools = make([]MachineConfigPool, 0, len(src.Status.MachineConfigPools))
for idx := range src.Status.MachineConfigPools {
dst.Status.MachineConfigPools = append(dst.Status.MachineConfigPools, convertMachineConfigPoolV1ToV1Alpha1(src.Status.MachineConfigPools[idx]))
}
}
if src.Status.Conditions != nil {
dst.Status.Conditions = make([]metav1.Condition, len(src.Status.Conditions))
copy(dst.Status.Conditions, src.Status.Conditions)
}

return nil
}
if src.Status.NodeGroups != nil {
dst.Status.DaemonSets = make([]NamespacedName, len(src.Status.NodeGroups))
dst.Status.MachineConfigPools = make([]MachineConfigPool, len(src.Status.NodeGroups))

func convertMachineConfigPoolV1Alpha1ToV1(src MachineConfigPool) nropv1.MachineConfigPool {
dst := nropv1.MachineConfigPool{}
dst.Name = src.Name
if src.Config != nil {
dst.Config = convertNodeGroupConfigV1Alpha1ToV1(*src.Config)
}
return dst
}

func convertMachineConfigPoolV1ToV1Alpha1(src nropv1.MachineConfigPool) MachineConfigPool {
dst := MachineConfigPool{}
dst.Name = src.Name
if src.Config != nil {
dst.Config = convertNodeGroupConfigV1ToV1Alpha1(*src.Config)
for _, ng := range src.Status.NodeGroups {
dst.Status.DaemonSets = append(dst.Status.DaemonSets, NamespacedName{
Namespace: ng.DaemonSet.Namespace,
Name: ng.DaemonSet.Name,
})
dst.Status.MachineConfigPools = append(dst.Status.MachineConfigPools, MachineConfigPool{
Name: ng.MachineConfigPoolName,
Config: convertNodeGroupConfigV1ToV1Alpha1(*ng.Config),
//MCP conditions are no longer needed in v1
})
}
}
return dst
return nil
}

func convertNodeGroupConfigV1Alpha1ToV1(src NodeGroupConfig) *nropv1.NodeGroupConfig {
Expand Down
18 changes: 17 additions & 1 deletion cmd/nrtcacheck/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,9 @@ func findRTEPodsByNodeName(ctx context.Context, cli client.Client) (map[string]t
}

podsByName := make(map[string]types.NamespacedName)
for _, ds := range nroObj.Status.DaemonSets {
// don't assume all ds statuses are healthy so collected the non empty ones
dss := collectNamespacedNameDaemonSets(nroObj.Status.NodeGroups)
for _, ds := range dss {
dsObj := appsv1.DaemonSet{}
err = cli.Get(context.TODO(), types.NamespacedName{Namespace: ds.Namespace, Name: ds.Name}, &dsObj)
if err != nil {
Expand Down Expand Up @@ -266,3 +268,17 @@ func getKlogLevel() int {
}
return 0
}

func collectNamespacedNameDaemonSets(ngStatuses []nropv1.NodeGroupStatus) []nropv1.NamespacedName {
dss := make([]nropv1.NamespacedName, 0, len(ngStatuses))
for _, ngStatus := range ngStatuses {
if ngStatus.DaemonSet.String() == string(nropv1.Separator) {
continue
}
dss = append(dss, nropv1.NamespacedName{
Namespace: ngStatus.DaemonSet.Namespace,
Name: ngStatus.DaemonSet.Name,
})
}
return dss
}
Loading

0 comments on commit d4cd5f4

Please sign in to comment.