Skip to content

Commit 2ab0103

Browse files
committed
mgr/nfs: earmark resolver for subvolume
Signed-off-by: Avan Thakkar <[email protected]>
1 parent 6623566 commit 2ab0103

File tree

2 files changed

+53
-10
lines changed

2 files changed

+53
-10
lines changed

src/pybind/mgr/nfs/export.py

Lines changed: 46 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,10 @@
1313
Set,
1414
cast)
1515
from os.path import normpath
16+
from ceph.fs.earmarking import EarmarkTopScope
1617
import cephfs
1718

19+
from mgr_util import CephFSEarmarkResolver
1820
from rados import TimedOut, ObjectNotFound, Rados
1921

2022
from object_format import ErrorResponse
@@ -535,7 +537,8 @@ def get_export_by_pseudo(
535537

536538
# This method is used by the dashboard module (../dashboard/controllers/nfs.py)
537539
# Do not change interface without updating the Dashboard code
538-
def apply_export(self, cluster_id: str, export_config: str) -> AppliedExportResults:
540+
def apply_export(self, cluster_id: str, export_config: str,
541+
earmark_resolver: Optional[CephFSEarmarkResolver] = None) -> AppliedExportResults:
539542
try:
540543
exports = self._read_export_config(cluster_id, export_config)
541544
except Exception as e:
@@ -544,7 +547,7 @@ def apply_export(self, cluster_id: str, export_config: str) -> AppliedExportResu
544547

545548
aeresults = AppliedExportResults()
546549
for export in exports:
547-
changed_export = self._change_export(cluster_id, export)
550+
changed_export = self._change_export(cluster_id, export, earmark_resolver)
548551
# This will help figure out which export blocks in conf/json file
549552
# are problematic.
550553
if changed_export.get("state", "") == "error":
@@ -573,9 +576,10 @@ def _read_export_config(self, cluster_id: str, export_config: str) -> List[Dict]
573576
return j # j is already a list object
574577
return [j] # return a single object list, with j as the only item
575578

576-
def _change_export(self, cluster_id: str, export: Dict) -> Dict[str, Any]:
579+
def _change_export(self, cluster_id: str, export: Dict,
580+
earmark_resolver: Optional[CephFSEarmarkResolver] = None) -> Dict[str, Any]:
577581
try:
578-
return self._apply_export(cluster_id, export)
582+
return self._apply_export(cluster_id, export, earmark_resolver)
579583
except NotImplementedError:
580584
# in theory, the NotImplementedError here may be raised by a hook back to
581585
# an orchestration module. If the orchestration module supports it the NFS
@@ -651,10 +655,34 @@ def _create_user_key(self, cluster_id: str, entity: str, path: str, fs_name: str
651655
log.info(f"Export user created is {json_res[0]['entity']}")
652656
return json_res[0]['key']
653657

658+
def _check_earmark(self, earmark_resolver: CephFSEarmarkResolver, path: str,
659+
fs_name: str) -> None:
660+
earmark = earmark_resolver.get_earmark(
661+
path,
662+
fs_name,
663+
)
664+
if not earmark:
665+
earmark_resolver.set_earmark(
666+
path,
667+
fs_name,
668+
EarmarkTopScope.NFS.value,
669+
)
670+
else:
671+
if not earmark_resolver.check_earmark(
672+
earmark, EarmarkTopScope.NFS
673+
):
674+
raise NFSException(
675+
'earmark has already been set by ' + earmark.split('.')[0],
676+
-errno.EAGAIN
677+
)
678+
return None
679+
654680
def create_export_from_dict(self,
655681
cluster_id: str,
656682
ex_id: int,
657-
ex_dict: Dict[str, Any]) -> Export:
683+
ex_dict: Dict[str, Any],
684+
earmark_resolver: Optional[CephFSEarmarkResolver] = None
685+
) -> Export:
658686
pseudo_path = ex_dict.get("pseudo")
659687
if not pseudo_path:
660688
raise NFSInvalidOperation("export must specify pseudo path")
@@ -677,6 +705,11 @@ def create_export_from_dict(self,
677705
raise FSNotFound(fs_name)
678706

679707
validate_cephfs_path(self.mgr, fs_name, path)
708+
709+
# Check if earmark is set for the path, given path is of subvolume
710+
if earmark_resolver:
711+
self._check_earmark(earmark_resolver, path, fs_name)
712+
680713
if fsal["cmount_path"] != "/":
681714
_validate_cmount_path(fsal["cmount_path"], path) # type: ignore
682715

@@ -707,7 +740,9 @@ def create_cephfs_export(self,
707740
access_type: str,
708741
clients: list = [],
709742
sectype: Optional[List[str]] = None,
710-
cmount_path: Optional[str] = "/") -> Dict[str, Any]:
743+
cmount_path: Optional[str] = "/",
744+
earmark_resolver: Optional[CephFSEarmarkResolver] = None
745+
) -> Dict[str, Any]:
711746

712747
validate_cephfs_path(self.mgr, fs_name, path)
713748
if cmount_path != "/":
@@ -731,7 +766,8 @@ def create_cephfs_export(self,
731766
},
732767
"clients": clients,
733768
"sectype": sectype,
734-
}
769+
},
770+
earmark_resolver
735771
)
736772
log.debug("creating cephfs export %s", export)
737773
self._ensure_cephfs_export_user(export)
@@ -795,6 +831,7 @@ def _apply_export(
795831
self,
796832
cluster_id: str,
797833
new_export_dict: Dict,
834+
earmark_resolver: Optional[CephFSEarmarkResolver] = None
798835
) -> Dict[str, str]:
799836
for k in ['path', 'pseudo']:
800837
if k not in new_export_dict:
@@ -834,7 +871,8 @@ def _apply_export(
834871
new_export = self.create_export_from_dict(
835872
cluster_id,
836873
new_export_dict.get('export_id', self._gen_export_id(cluster_id)),
837-
new_export_dict
874+
new_export_dict,
875+
earmark_resolver
838876
)
839877

840878
if not old_export:

src/pybind/mgr/nfs/module.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import object_format
77
import orchestrator
88
from orchestrator.module import IngressType
9+
from mgr_util import CephFSEarmarkResolver
910

1011
from .export import ExportMgr, AppliedExportResults
1112
from .cluster import NFSCluster
@@ -41,6 +42,7 @@ def _cmd_nfs_export_create_cephfs(
4142
cmount_path: Optional[str] = "/"
4243
) -> Dict[str, Any]:
4344
"""Create a CephFS export"""
45+
earmark_resolver = CephFSEarmarkResolver(self)
4446
return self.export_mgr.create_export(
4547
fsal_type='cephfs',
4648
fs_name=fsname,
@@ -51,7 +53,8 @@ def _cmd_nfs_export_create_cephfs(
5153
squash=squash,
5254
addr=client_addr,
5355
sectype=sectype,
54-
cmount_path=cmount_path
56+
cmount_path=cmount_path,
57+
earmark_resolver=earmark_resolver
5558
)
5659

5760
@CLICommand('nfs export create rgw', perm='rw')
@@ -114,8 +117,10 @@ def _cmd_nfs_export_get(self, cluster_id: str, pseudo_path: str) -> Dict[str, An
114117
@CLICheckNonemptyFileInput(desc='Export JSON or Ganesha EXPORT specification')
115118
@object_format.Responder()
116119
def _cmd_nfs_export_apply(self, cluster_id: str, inbuf: str) -> AppliedExportResults:
120+
earmark_resolver = CephFSEarmarkResolver(self)
117121
"""Create or update an export by `-i <json_or_ganesha_export_file>`"""
118-
return self.export_mgr.apply_export(cluster_id, export_config=inbuf)
122+
return self.export_mgr.apply_export(cluster_id, export_config=inbuf,
123+
earmark_resolver=earmark_resolver)
119124

120125
@CLICommand('nfs cluster create', perm='rw')
121126
@object_format.EmptyResponder()

0 commit comments

Comments
 (0)