Migration followup#1135
Conversation
d2676d7 to
77b6059
Compare
mxsrc
left a comment
There was a problem hiding this comment.
I'm a bit lost with the PR, the description is not really enough for me to understand what is going on. Ideally we'd split the PR up into indivudal changes, not sure whether that's feasible. Currently the description says the PR does four things, but there is definitely more going on. Questions I have from a quick glance that I can't really answer, that don't seem to correspond to any of the items the description indicates:
- What are the test scripts that are being introduced for, who is supposed to execute them?
- What's the purpose of the fault injection logic, where is it used from?
- Why does the PR introduce replication logic, my understanding is that it's supposed to fix volume migration
Please help me review this, as it stands I don't understand what is going on.
| # Undocumented chaos-testing switch: when set at cluster create, a transparent | ||
| # SPDK delay bdev is inserted between each device's nvme bdev and its alceml so | ||
| # a device can be made to "hang" on demand (see device_controller device-hang). | ||
| enable_hang_device: bool = False |
There was a problem hiding this comment.
I think we need to very carefully think about the implications of integrating fault injection into the business logic. Where is this called from? I cannot find it in this PR. Is there no other way of achieving this?
| _lvol_base = lvol.lvol_bdev[:-len(_MIGRATION_BDEV_SUFFIX)] if lvol.lvol_bdev.endswith(_MIGRATION_BDEV_SUFFIX) else lvol.lvol_bdev | ||
| bdev_short = _lvol_base + _MIGRATION_BDEV_SUFFIX |
There was a problem hiding this comment.
This is not the only place where this is failing. A proper fix uses the idempotent helper that is already present consistently: 0a9690a.
| _lvol_base = lvol.lvol_bdev[:-len(_MIGRATION_BDEV_SUFFIX)] if lvol.lvol_bdev.endswith(_MIGRATION_BDEV_SUFFIX) else lvol.lvol_bdev | ||
| bdev_short = _lvol_base + _MIGRATION_BDEV_SUFFIX |
There was a problem hiding this comment.
This is too easy to miss, same comment as above. If you repeat code, use a helper.
…revious migrations
Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>
526b846 to
e9941c7
Compare
mxsrc
left a comment
There was a problem hiding this comment.
There's a few minor things that should change, I left comments for that. The two larger things are that quite a few places ignore errors instead of escalating them, sometimes logging a warning, sometimes not. In some places this doesn't seem right, I think this should be revisited. As for the core logic, I can't really judge that, this, and the pre-existing code doesn't really document the intent, but from a code-perspective I think we can go forward.
|
|
||
| def bdev_lvol_rename(self, old_name, new_name): | ||
| params = {"old_name": old_name, "new_name": new_name} | ||
| return self._request("bdev_lvol_rename", params) |
There was a problem hiding this comment.
New RPCs should use _request3.
There was a problem hiding this comment.
done, using _request3 for the rpc now
| current = snap.snap_ref_id | ||
| current = snap.snap_ref_id or snap.prev_snap_uuid | ||
| except KeyError: | ||
| break |
There was a problem hiding this comment.
This, and _get_snap_ancestry seem redundant. Is there no way of deduplicating them?
At least _protect_snap_and_ancestors can basically be candidate_set - _collect_snap_ancestry(), can't it?
| status = primary_rpc.bdev_lvol_get_lvol_delete_status(bdev_name) | ||
| if status in (0, 2): | ||
| break | ||
| if status == 1: | ||
| time.sleep(0.25) | ||
| else: | ||
| logger.warning(f"delete bdev {bdev_name}: unexpected status {status}") | ||
| if status != 1: |
There was a problem hiding this comment.
This can be folded into the loop condition.
mxsrc
left a comment
There was a problem hiding this comment.
Gotta look into something else and didn't finish the review, leaving my comments here for now. Something I noticed, not necessarily for now, but a common pattern is to do an operation on a node, as well as their secondary and primary. One single helper would help doing this correctly, ensuring correct error handling.
| _short_tgt = _snap_tgt_short_name(_s) # SNAP_Xm (in-flight) | ||
| _short_canonical = _snap_short_name(_s) # SNAP_X (post-rename) | ||
| _short_am = _short_canonical + _MIGRATION_BDEV_SUFFIX_DONE # SNAP_Xam (fallback) |
There was a problem hiding this comment.
This will hit the same fault scenario we had with the BDEV_SUFFIX, won't it? If the m suffix is already applied, simply adding this will make it SNAP_Xmam?
There was a problem hiding this comment.
after migration we have a rename operation, which should bring the lvols back to the same name they had on source on the target unless there's a different lvol with exact same name so I'm am suffix for those cases
that only happnes if there's an unrelated lvol with the same lvol on the target
| f"_rename_migrated_bdevs: {role} rename {label} (non-fatal): {exc}") | ||
| if exists: | ||
| return _EXISTS | ||
| return True |
There was a problem hiding this comment.
I'm struggling to follow this function. It returns either a boolean (or rather, always True), or some string sentinel. It also adds relevant logic to RPCClient.bdev_lvol_rename. The comments are a bit unclear to me and violate abstraction layers, the RPCClient should contain any knowledge about RPC workings, like the mapping of error codes.
So the suggestion is to add an exists_ok flag to RPCClient.bdev_lvol_rename, and raise an RPCException subclass that indicates the entity already exists. With that primitive, we can lose the sentinel, and _rename_with_fallback becomes much more readable.
In addition to handling the RPC logic, it does the rename on all three nodes that are responsible for the LVol. It doesn't handle inconsistencies or failures correctly though open questions are:
- what happens if the function encounters an existing inconsistency where the target exists on only one of the nodes. There is no way to handle this easily, but at least we need to be aware of it
- Errors of any of the rename (except the first) are ignored and flagged as non-fatal. Is that correct? It introduces an inconsistency that follow up code has to deal with.
There was a problem hiding this comment.
this i been working on mainly on migration-followup2 branch which it changed I'll save this comment for that branch
| """ | ||
| if _SKIP_RENAME_BDEVS: | ||
| logger.info("_rename_migrated_bdevs: skipped (SKIP_RENAME_BDEVS=True)") | ||
| return |
There was a problem hiding this comment.
This seems like a debugging provision? In that case I prefer not to mainline it.
| def _protect_snap_and_ancestors(snap_uuid, candidate_set): | ||
| """Remove *snap_uuid* and all its ancestors from *candidate_set*.""" | ||
| candidate_set -= _collect_snap_ancestry(snap_uuid) |
There was a problem hiding this comment.
At this point we don't need the helper anymore, the operation can simply be used at the call-site.
mxsrc
left a comment
There was a problem hiding this comment.
Thanks for the changes, quite a few good additions in here. I think we need one more iteration though.
The situation with the _get_target_{secondary,tertiary}_node should be handled by:
- adding documentation for why in some cases a suspended node should be returned
- passing the source node ID parameter consistently
- removing the default to enforce this for future changes
- reviewing the
_get_{secondary,tertiary}_rpchelpers: This needs to mirror the logic for the node get helpers, keeping this in sync is evidently hard. Maybe they should be removed, and instead use_make_rpc(_get_{secondary_target_tertiary_node(...)). If they are used for source nodes as well, probably we best introduce separate helpers for that indicating them.
| if (node_offline_devices > 0 | ||
| or (node_online_devices == 0 and node.status != StorageNode.STATUS_REMOVED) | ||
| or node.status == StorageNode.STATUS_OFFLINE): |
There was a problem hiding this comment.
This doesn't seem to be related to the other changes, why is it here?
# Conflicts: # simplyblock_core/controllers/migration_controller.py # simplyblock_core/services/tasks_runner_lvol_migration.py
mxsrc
left a comment
There was a problem hiding this comment.
Looks good, let's go forward. Some of the suggestions are still valid, but they shouldn't block merging this.
in this follow up we addressing multiple issues for migration