Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: adds status information to the LVMCluster CR #76

Merged
merged 2 commits into from
Jan 18, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
}