Skip to content

Commit

Permalink
Merge pull request #76 from nbalacha/status
Browse files Browse the repository at this point in the history
feat:  adds status information to the LVMCluster CR
  • Loading branch information
nbalacha authored Jan 18, 2022
2 parents 52673fa + c6eb697 commit 9a667b6
Show file tree
Hide file tree
Showing 6 changed files with 210 additions and 12 deletions.
24 changes: 21 additions & 3 deletions api/v1alpha1/lvmcluster_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,11 @@ type DeviceClass struct {
// +kubebuilder:validation:Pattern="^[a-z0-9]([-a-z0-9]*[a-z0-9])?$"
Name string `json:"name,omitempty"`

// DeviceSelector is a set of rules that should match for a device to be included in this TopoLVMCluster
// DeviceSelector is a set of rules that should match for a device to be included in the LVMCluster
// +optional
DeviceSelector *DeviceSelector `json:"deviceSelector,omitempty"`

// NodeSelector chooses nodes
// NodeSelector chooses nodes on which to create the deviceclass
// +optional
NodeSelector *corev1.NodeSelector `json:"nodeSelector,omitempty"`

Expand Down Expand Up @@ -79,9 +79,27 @@ type LVMClusterStatus struct {
// INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
// Important: Run "make" to regenerate code after modifying this file

// ready describes if the LvmCluster is ready.
// Ready describes if the LVMCluster is ready.
// +optional
Ready bool `json:"ready,omitempty"`
// DeviceClassStatuses describes the status of all deviceClasses
DeviceClassStatuses []DeviceClassStatus `json:"deviceClassStatuses,omitempty"`
}

// DeviceClassStatus defines the observed status of the deviceclass across all nodes
type DeviceClassStatus struct {
// Name is the name of the deviceclass
Name string `json:"name,omitempty"`
// NodeStatus tells if the deviceclass was created on the node
NodeStatus []NodeStatus `json:"nodeStatus,omitempty"`
}

// NodeStatus defines the observed state of the deviceclass on the node
type NodeStatus struct {
// Node is the name of the node
Node string `json:"node,omitempty"`
// Status is the status of the VG on the node
Status VGStatusType `json:"status,omitempty"`
}

//+kubebuilder:object:root=true
Expand Down
44 changes: 43 additions & 1 deletion api/v1alpha1/zz_generated.deepcopy.go

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

33 changes: 30 additions & 3 deletions config/crd/bases/lvm.topolvm.io_lvmclusters.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ spec:
properties:
deviceSelector:
description: DeviceSelector is a set of rules that should match
for a device to be included in this TopoLVMCluster
for a device to be included in the LVMCluster
type: object
name:
description: 'Name of the class, the VG and possibly the storageclass.
Expand All @@ -54,7 +54,8 @@ spec:
pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
type: string
nodeSelector:
description: NodeSelector chooses nodes
description: NodeSelector chooses nodes on which to create the
deviceclass
properties:
nodeSelectorTerms:
description: Required. A list of node selector terms. The
Expand Down Expand Up @@ -184,8 +185,34 @@ spec:
status:
description: LVMClusterStatus defines the observed state of LVMCluster
properties:
deviceClassStatuses:
description: DeviceClassStatuses describes the status of all deviceClasses
items:
description: DeviceClassStatus defines the observed status of the
deviceclass across all nodes
properties:
name:
description: Name is the name of the deviceclass
type: string
nodeStatus:
description: NodeStatus tells if the deviceclass was created
on the node
items:
description: NodeStatus defines the observed state of the
deviceclass on the node
properties:
node:
description: Node is the name of the node
type: string
status:
description: Status is the status of the VG on the node
type: string
type: object
type: array
type: object
type: array
ready:
description: ready describes if the LvmCluster is ready.
description: Ready describes if the LVMCluster is ready.
type: boolean
type: object
type: object
Expand Down
26 changes: 26 additions & 0 deletions config/rbac/role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,32 @@ rules:
- get
- patch
- update
- apiGroups:
- lvm.topolvm.io
resources:
- lvmvolumegroupnodestatuses
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- lvm.topolvm.io
resources:
- lvmvolumegroupnodestatuses/finalizers
verbs:
- update
- apiGroups:
- lvm.topolvm.io
resources:
- lvmvolumegroupnodestatuses/status
verbs:
- get
- patch
- update
- apiGroups:
- lvm.topolvm.io
resources:
Expand Down
57 changes: 52 additions & 5 deletions controllers/lvmcluster_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ type LVMClusterReconciler struct {
//+kubebuilder:rbac:groups=lvm.topolvm.io,resources=lvmvolumegroups,verbs=get;list;watch;create;update;patch;delete
//+kubebuilder:rbac:groups=lvm.topolvm.io,resources=lvmvolumegroups/status,verbs=get;update;patch
//+kubebuilder:rbac:groups=lvm.topolvm.io,resources=lvmvolumegroups/finalizers,verbs=update
//+kubebuilder:rbac:groups=lvm.topolvm.io,resources=lvmvolumegroupnodestatuses,verbs=get;list;watch;create;update;patch;delete
//+kubebuilder:rbac:groups=lvm.topolvm.io,resources=lvmvolumegroupnodestatuses/status,verbs=get;update;patch
//+kubebuilder:rbac:groups=lvm.topolvm.io,resources=lvmvolumegroupnodestatuses/finalizers,verbs=update
//+kubebuilder:rbac:groups=security.openshift.io,resources=securitycontextconstraints,verbs=get;create;update;delete
//+kubebuilder:rbac:groups=core,resources=pods,verbs=get;list;watch

Expand Down Expand Up @@ -100,12 +103,9 @@ func (r *LVMClusterReconciler) Reconcile(ctx context.Context, req ctrl.Request)
}
result, reconcileError := r.reconcile(ctx, lvmCluster)

// Apply status changes
statusError := r.Client.Status().Update(ctx, lvmCluster)
statusError := r.updateLVMClusterStatus(ctx, lvmCluster)
if statusError != nil {
if errors.IsNotFound(err) {
r.Log.Error(statusError, "failed to update status")
}
r.Log.Error(statusError, "failed to update VG Node status")
}

// Reconcile errors have higher priority than status update errors
Expand Down Expand Up @@ -197,6 +197,53 @@ func (r *LVMClusterReconciler) reconcile(ctx context.Context, instance *lvmv1alp
return ctrl.Result{}, nil
}

func (r *LVMClusterReconciler) updateLVMClusterStatus(ctx context.Context, instance *lvmv1alpha1.LVMCluster) error {

vgNodeMap := make(map[string][]lvmv1alpha1.NodeStatus)

vgNodeStatusList := &lvmv1alpha1.LVMVolumeGroupNodeStatusList{}
err := r.Client.List(ctx, vgNodeStatusList, client.InNamespace(r.Namespace))
if err != nil {
r.Log.Error(err, "failed to list LVMVolumeGroupNodeStatus")
return err
}

for _, nodeItem := range vgNodeStatusList.Items {
for _, item := range nodeItem.Spec.LVMVGStatus {
val, ok := vgNodeMap[item.Name]
if !ok {
vgNodeMap[item.Name] = []lvmv1alpha1.NodeStatus{
{
Node: nodeItem.Name,
Status: item.Status,
},
}
} else {
new := lvmv1alpha1.NodeStatus{Node: nodeItem.Name, Status: item.Status}
val = append(val, new)
vgNodeMap[item.Name] = val
}
}
}

allVgStatuses := []lvmv1alpha1.DeviceClassStatus{}
for k := range vgNodeMap {
//r.Log.Info("vgnode map ", "key", k, "NodeStatus", vgNodeMap[k])
new := lvmv1alpha1.DeviceClassStatus{Name: k, NodeStatus: vgNodeMap[k]}
allVgStatuses = append(allVgStatuses, new)
}

instance.Status.DeviceClassStatuses = allVgStatuses
// Apply status changes
err = r.Client.Status().Update(ctx, instance)
if err != nil {
if errors.IsNotFound(err) {
r.Log.Error(err, "failed to update status")
}
}
return err
}

// NOTE: when updating this, please also update doc/design/operator.md
type resourceManager interface {

Expand Down
38 changes: 38 additions & 0 deletions controllers/lvmcluster_controller_watches.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,53 @@ limitations under the License.
package controllers

import (
"context"

lvmv1alpha1 "github.com/red-hat-storage/lvm-operator/api/v1alpha1"
appsv1 "k8s.io/api/apps/v1"
"k8s.io/apimachinery/pkg/types"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/handler"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
"sigs.k8s.io/controller-runtime/pkg/source"
)

// SetupWithManager sets up the controller with the Manager.
func (r *LVMClusterReconciler) SetupWithManager(mgr ctrl.Manager) error {
return ctrl.NewControllerManagedBy(mgr).
For(&lvmv1alpha1.LVMCluster{}).
Owns(&appsv1.DaemonSet{}).
Owns(&lvmv1alpha1.LVMVolumeGroup{}).
Owns(&lvmv1alpha1.LVMVolumeGroupNodeStatus{}).
Watches(
&source.Kind{Type: &lvmv1alpha1.LVMVolumeGroupNodeStatus{}},
handler.EnqueueRequestsFromMapFunc(r.getLVMClusterObjsForReconcile),
// builder.WithPredicates(predicate.ResourceVersionChangedPredicate{}),
).
Complete(r)
}

func (r *LVMClusterReconciler) getLVMClusterObjsForReconcile(obj client.Object) []reconcile.Request {
foundLVMClusterList := &lvmv1alpha1.LVMClusterList{}
listOps := &client.ListOptions{
Namespace: obj.GetNamespace(),
}

err := r.Client.List(context.TODO(), foundLVMClusterList, listOps)
if err != nil {
r.Log.Error(err, "getLVMClusterObjsForReconcile: Failed to get LVMCluster objs")
return []reconcile.Request{}
}

requests := make([]reconcile.Request, len(foundLVMClusterList.Items))
for i, item := range foundLVMClusterList.Items {
requests[i] = reconcile.Request{
NamespacedName: types.NamespacedName{
Name: item.GetName(),
Namespace: item.GetNamespace(),
},
}
}
return requests
}

0 comments on commit 9a667b6

Please sign in to comment.