-
Notifications
You must be signed in to change notification settings - Fork 40
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: make API and controller changes to support manual disk selection #229
Conversation
a469dce
to
deb1d65
Compare
3bc331d
to
66bdc36
Compare
@@ -254,6 +254,10 @@ spec: | |||
node: | |||
description: Node is the name of the node | |||
type: string | |||
reason: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks like something that can be part of the make bundle
commit.
@@ -208,6 +215,46 @@ func (r *LVMClusterReconciler) reconcile(ctx context.Context, instance *lvmv1alp | |||
return ctrl.Result{}, nil | |||
} | |||
|
|||
func (r *LVMClusterReconciler) verifyLvmClusterSpec(ctx context.Context, instance *lvmv1alpha1.LVMCluster) error { | |||
|
|||
// make sure no device overlap with another VGs |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what if the user decides to give the device names instead of device paths?
I know we encourage them to use paths, but still if they decide to use device names instead, then this validation will always fail, if I'm not wrong.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Even in that case, it should work, as the device names will only be the same. I am just loading the devices into a map; if the key already exists, we are erroring out.
@@ -208,6 +215,46 @@ func (r *LVMClusterReconciler) reconcile(ctx context.Context, instance *lvmv1alp | |||
return ctrl.Result{}, nil | |||
} | |||
|
|||
func (r *LVMClusterReconciler) verifyLvmClusterSpec(ctx context.Context, instance *lvmv1alpha1.LVMCluster) error { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
method name can be more specific about what we are trying to verify instead of verifyLvmClusterSpec
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comments still holds. The function only validates the device classes in the Spec. The function name should reflect that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
added a new func for this logic and that will be called from here
api/v1alpha1/lvmcluster_types.go
Outdated
@@ -108,6 +114,11 @@ type LVMClusterStatus struct { | |||
// Ready describes if the LVMCluster is ready. | |||
// +optional | |||
Ready bool `json:"ready,omitempty"` | |||
|
|||
// Reason describes the reason behind any success or failure. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do you mean reason behind failure
only? Don't think we add any success reason.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we can also have a reason behind the success which will always be the exact string. I think success reason should not matter much, as much as failure.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would prefer to use conditions here if possible.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
added conditions
controllers/lvmcluster_controller.go
Outdated
instance.Status.Reason = err.Error() | ||
|
||
// Apply status changes | ||
err = r.Client.Status().Update(ctx, instance) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO, updating status should not be part of the verification function. It should only be concerned about the verification part.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This verification function is called precisely after getting the instance and we won't get to an actual update call as we will be returning from here only, so we need to do an update here itself only and only if there is a failure.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should also check for node selector when validating the devices overlaps. It is possible for the same device path in different nodes to be used in different device classes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
checking node selectors as well now
api/v1alpha1/lvmcluster_types.go
Outdated
|
||
// Reason describes the reason behind any success or failure. | ||
// +optional | ||
Reason string `json:"reason,omitempty"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we add reason
for error specific to this PR only?
If that's the case, then we need to add reasons for other failures as well in a separate PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am updating the reason wherever required.
// TODO: Implement this | ||
func filterMatchingDevices(blockDevices []internal.BlockDevice, volumeGroup *lvmv1alpha1.LVMVolumeGroup) ([]internal.BlockDevice, []internal.BlockDevice, error) { | ||
// currently just match all devices | ||
func (r *VGReconciler) filterMatchingDevices(blockDevices []internal.BlockDevice, volumeGroup *lvmv1alpha1.LVMVolumeGroup) ([]internal.BlockDevice, []internal.BlockDevice, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unit test should be added for this function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
comment still valid.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will add them later once we agree with the actual code changes to minimize the changes in unit tests.
// TODO: Implement this | ||
func filterMatchingDevices(blockDevices []internal.BlockDevice, volumeGroup *lvmv1alpha1.LVMVolumeGroup) ([]internal.BlockDevice, []internal.BlockDevice, error) { | ||
// currently just match all devices | ||
func (r *VGReconciler) filterMatchingDevices(blockDevices []internal.BlockDevice, volumeGroup *lvmv1alpha1.LVMVolumeGroup) ([]internal.BlockDevice, []internal.BlockDevice, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do you plan to the use the unmatched disks
return value? If not, then we can avoid returning that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no plans we can remove it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still see this return value in the code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
missed it earlier, made changes now
if ok { | ||
filteredBlockDevices = append(filteredBlockDevices, blockDevice) | ||
} else { | ||
err := fmt.Errorf("can not find disk name %s in the available block devices", path) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
err := fmt.Errorf("can not find disk name %s in the available block devices", path) | |
err := fmt.Errorf("can not find disk name %s in the available block devices", diskName) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
both will be the same only, So updating to path should make any differences
api/v1alpha1/lvmcluster_types.go
Outdated
@@ -108,6 +114,11 @@ type LVMClusterStatus struct { | |||
// Ready describes if the LVMCluster is ready. | |||
// +optional | |||
Ready bool `json:"ready,omitempty"` | |||
|
|||
// Reason describes the reason behind any success or failure. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would prefer to use conditions here if possible.
controllers/lvmcluster_controller.go
Outdated
instance.Status.Reason = err.Error() | ||
|
||
// Apply status changes | ||
err = r.Client.Status().Update(ctx, instance) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should also check for node selector when validating the devices overlaps. It is possible for the same device path in different nodes to be used in different device classes.
if device.DiskByPath != "" { | ||
args = append(args, device.DiskByPath) | ||
} else { | ||
args = append(args, device.KName) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
don't think it will work if complete device name with path (for example: dev/sdb
) is not provided in the args
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It should work as we are getting the full path now.
} | ||
|
||
// ListBlockDevices using the lsblk command | ||
func ListBlockDevices(exec Executor) ([]BlockDevice, error) { | ||
// var output bytes.Buffer | ||
var blockDeviceMap map[string][]BlockDevice | ||
columns := "NAME,ROTA,TYPE,SIZE,MODEL,VENDOR,RO,STATE,KNAME,SERIAL,PARTLABEL,FSTYPE" | ||
args := []string{"--json", "-o", columns} | ||
args := []string{"--json", "--paths", "-o", columns} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why is --paths
argument needed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
using --paths will give us the full path and make our job easy while comparing the paths and while adding paths into some commands we don't have to add /dev/
anymore.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
some comments are not addressed
@@ -208,6 +215,46 @@ func (r *LVMClusterReconciler) reconcile(ctx context.Context, instance *lvmv1alp | |||
return ctrl.Result{}, nil | |||
} | |||
|
|||
func (r *LVMClusterReconciler) verifyLvmClusterSpec(ctx context.Context, instance *lvmv1alpha1.LVMCluster) error { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comments still holds. The function only validates the device classes in the Spec. The function name should reflect that.
e1fda0d
to
a0a6098
Compare
500639b
to
a0323b7
Compare
devices := make(map[string]map[string]string) | ||
|
||
for _, deviceClass := range instance.Spec.Storage.DeviceClasses { | ||
if deviceClass.DeviceSelector != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what if we (in the future) have two deviceClasses - one taking up all the disks and one with manual disk selection?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we should not support such cases IMO. This code will just check the manual disk paths only as other device class wont have any list of devices in the spec.
r.Log.Error(err, "failed to verify device paths") | ||
|
||
setLVMClusterCRvalidCondition(&instance.Status.Conditions, corev1.ConditionFalse, "CRInvalid", err.Error()) | ||
return err |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shouldn't we use setLVMClusterCRvalidCondition
when there's a verify issue?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We are setting the condition in both cases either in failure or in success.
Can you pls elaborate on what you mean?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I need more coffee :D sorry
return []internal.BlockDevice{}, err | ||
} | ||
} else { | ||
err = fmt.Errorf("unsupported disk path format %s", path) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please add to the error message that only /dev/disk/by-path
and /dev/
links are currently supported
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
|
||
blockDevice, ok := hasExactDisk(blockDevices, diskName) | ||
|
||
if filepath.Dir(path) == internal.DiskByPathPrefix { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why can't we use this flow for all /dev/disk/by-*
options?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can, We need more conditions to do that. Also as of now, all other patterns other than diskbypath will go into the else condition starting with dev.
} | ||
|
||
devices := []string{} | ||
if diskPattern == internal.DiskByPathPrefix { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
idea: why not always use the disk path in the status?!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had this discussion earlier with @nbalacha and we came to the conclusion that we will show the paths as given in the spec. It will be easier for a user to compare them from the spec.
make sure device paths does not overlap with another VG or within the same VG. Signed-off-by: Nitin Goyal <nigoyal@redhat.com>
Signed-off-by: Nitin Goyal <nigoyal@redhat.com>
implement filterMatchingDevices Signed-off-by: Nitin Goyal <nigoyal@redhat.com>
if VolumeGroup CR uses paths add paths in the devices else add names Signed-off-by: Nitin Goyal <nigoyal@redhat.com>
update the error in the reason Signed-off-by: Nitin Goyal <nigoyal@redhat.com>
Signed-off-by: Nitin Goyal <nigoyal@redhat.com>
Signed-off-by: Nitin Goyal <nigoyal@redhat.com>
Signed-off-by: Nitin Goyal <nigoyal@redhat.com>
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: iamniting, nbalacha, sp98 The full list of commands accepted by this bot can be found here. The pull request process is described here
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
Allow user to select the block devices while VG creation in the LVMCluster CR.
Signed-off-by: Nitin Goyal nigoyal@redhat.com