Skip to content

Commit f0ffb26

Browse files
mgr/smb: replace cross check if-block with singledispatch
The previous code relied on a cascading block of if-isintance statements that was dense and somwehat error prone as I found out during an experiment to add a new top level resource type. Refactor the cross check function to use singledispatch: https://docs.python.org/3.9/library/functools.html#functools.singledispatch Now instead of correctly adding check function(s) and updating the if-block, only new check functions using the register decorator is needed. Note that making this checking more generic is difficult as each different resource type really has different cross checking needs. Signed-off-by: John Mulligan <[email protected]>
1 parent 978e92f commit f0ffb26

File tree

1 file changed

+33
-39
lines changed

1 file changed

+33
-39
lines changed

src/pybind/mgr/smb/staging.py

Lines changed: 33 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
from typing import (
2+
Any,
23
Collection,
34
Dict,
45
Iterator,
56
List,
67
Optional,
78
Set,
8-
Union,
99
)
1010

11+
import functools
1112
import logging
1213
import operator
1314

@@ -41,9 +42,6 @@
4142
from .results import ErrorResult, Result, ResultGroup
4243
from .utils import checked
4344

44-
ClusterRef = Union[resources.Cluster, resources.RemovedCluster]
45-
ShareRef = Union[resources.Share, resources.RemovedShare]
46-
4745
log = logging.getLogger(__name__)
4846

4947

@@ -163,38 +161,22 @@ def ug_refs(cluster: resources.Cluster) -> Collection[str]:
163161
}
164162

165163

164+
@functools.singledispatch
166165
def cross_check_resource(
167166
resource: SMBResource,
168167
staging: Staging,
169168
*,
170169
path_resolver: PathResolver,
171170
earmark_resolver: EarmarkResolver,
172171
) -> None:
173-
if isinstance(resource, (resources.Cluster, resources.RemovedCluster)):
174-
_check_cluster(resource, staging)
175-
elif isinstance(resource, (resources.Share, resources.RemovedShare)):
176-
_check_share(
177-
resource,
178-
staging,
179-
path_resolver,
180-
earmark_resolver,
181-
)
182-
elif isinstance(resource, resources.JoinAuth):
183-
_check_join_auths(resource, staging)
184-
elif isinstance(resource, resources.UsersAndGroups):
185-
_check_users_and_groups(resource, staging)
186-
else:
187-
raise TypeError('not a valid smb resource')
188-
172+
raise TypeError(f'not a valid smb resource: {type(resource)}')
189173

190-
def _check_cluster(cluster: ClusterRef, staging: Staging) -> None:
191-
"""Check that the cluster resource can be updated."""
192-
if cluster.intent == Intent.PRESENT:
193-
return _check_cluster_present(cluster, staging)
194-
return _check_cluster_removed(cluster, staging)
195174

196-
197-
def _check_cluster_removed(cluster: ClusterRef, staging: Staging) -> None:
175+
@cross_check_resource.register
176+
def _check_removed_cluster_resource(
177+
cluster: resources.RemovedCluster, staging: Staging, **_: Any
178+
) -> None:
179+
assert cluster.intent == Intent.REMOVED
198180
share_ids = ShareEntry.ids(staging)
199181
clusters_used = {cid for cid, _ in share_ids}
200182
if cluster.cluster_id in clusters_used:
@@ -211,8 +193,11 @@ def _check_cluster_removed(cluster: ClusterRef, staging: Staging) -> None:
211193
)
212194

213195

214-
def _check_cluster_present(cluster: ClusterRef, staging: Staging) -> None:
215-
assert isinstance(cluster, resources.Cluster)
196+
@cross_check_resource.register
197+
def _check_cluster_resource(
198+
cluster: resources.Cluster, staging: Staging, **_: Any
199+
) -> None:
200+
assert cluster.intent == Intent.PRESENT
216201
cluster.validate()
217202
if not staging.is_new(cluster):
218203
_check_cluster_modifications(cluster, staging)
@@ -291,15 +276,22 @@ def _check_cluster_modifications(
291276
raise ErrorResult(cluster, msg, status={'hint': hint})
292277

293278

294-
def _check_share(
295-
share: ShareRef,
279+
@cross_check_resource.register
280+
def _check_removed_share_resource(
281+
share: resources.RemovedShare, staging: Staging, **_: Any
282+
) -> None:
283+
assert share.intent == Intent.REMOVED
284+
285+
286+
@cross_check_resource.register
287+
def _check_share_resource(
288+
share: resources.Share,
296289
staging: Staging,
297-
resolver: PathResolver,
290+
path_resolver: PathResolver,
298291
earmark_resolver: EarmarkResolver,
299292
) -> None:
300293
"""Check that the share resource can be updated."""
301-
if share.intent == Intent.REMOVED:
302-
return
294+
assert share.intent == Intent.PRESENT
303295
assert isinstance(share, resources.Share)
304296
share.validate()
305297
if share.cluster_id not in ClusterEntry.ids(staging):
@@ -310,7 +302,7 @@ def _check_share(
310302
)
311303
assert share.cephfs is not None
312304
try:
313-
volpath = resolver.resolve_exists(
305+
volpath = path_resolver.resolve_exists(
314306
share.cephfs.volume,
315307
share.cephfs.subvolumegroup,
316308
share.cephfs.subvolume,
@@ -411,8 +403,9 @@ def _share_name_in_use(
411403
return found_curr[0].get()['share_id']
412404

413405

414-
def _check_join_auths(
415-
join_auth: resources.JoinAuth, staging: Staging
406+
@cross_check_resource.register
407+
def _check_join_auth_resource(
408+
join_auth: resources.JoinAuth, staging: Staging, **_: Any
416409
) -> None:
417410
"""Check that the JoinAuth resource can be updated."""
418411
if join_auth.intent == Intent.PRESENT:
@@ -455,8 +448,9 @@ def _check_join_auths_present(
455448
)
456449

457450

458-
def _check_users_and_groups(
459-
users_and_groups: resources.UsersAndGroups, staging: Staging
451+
@cross_check_resource.register
452+
def _check_users_and_groups_resource(
453+
users_and_groups: resources.UsersAndGroups, staging: Staging, **_: Any
460454
) -> None:
461455
"""Check that the UsersAndGroups resource can be updated."""
462456
if users_and_groups.intent == Intent.PRESENT:

0 commit comments

Comments
 (0)