]> git.proxmox.com Git - ceph.git/blob - ceph/src/pybind/mgr/volumes/fs/operations/group.py
bump version to 15.2.4-pve1
[ceph.git] / ceph / src / pybind / mgr / volumes / fs / operations / group.py
1 import os
2 import errno
3 import logging
4 from contextlib import contextmanager
5
6 import cephfs
7
8 from .snapshot_util import mksnap, rmsnap
9 from .template import GroupTemplate
10 from ..fs_util import listdir, get_ancestor_xattr
11 from ..exception import VolumeException
12
13 log = logging.getLogger(__name__)
14
15 class Group(GroupTemplate):
16 # Reserved subvolume group name which we use in paths for subvolumes
17 # that are not assigned to a group (i.e. created with group=None)
18 NO_GROUP_NAME = "_nogroup"
19
20 def __init__(self, fs, vol_spec, groupname):
21 assert groupname != Group.NO_GROUP_NAME
22 self.fs = fs
23 self.user_id = None
24 self.group_id = None
25 self.vol_spec = vol_spec
26 self.groupname = groupname if groupname else Group.NO_GROUP_NAME
27
28 @property
29 def path(self):
30 return os.path.join(self.vol_spec.base_dir.encode('utf-8'), self.groupname.encode('utf-8'))
31
32 @property
33 def group_name(self):
34 return self.groupname
35
36 @property
37 def uid(self):
38 return self.user_id
39
40 @uid.setter
41 def uid(self, val):
42 self.user_id = val
43
44 @property
45 def gid(self):
46 return self.group_id
47
48 @gid.setter
49 def gid(self, val):
50 self.group_id = val
51
52 def is_default_group(self):
53 return self.groupname == Group.NO_GROUP_NAME
54
55 def list_subvolumes(self):
56 try:
57 return listdir(self.fs, self.path)
58 except VolumeException as ve:
59 # listing a default group when it's not yet created
60 if ve.errno == -errno.ENOENT and self.is_default_group():
61 return []
62 raise
63
64 def create_snapshot(self, snapname):
65 snappath = os.path.join(self.path,
66 self.vol_spec.snapshot_dir_prefix.encode('utf-8'),
67 snapname.encode('utf-8'))
68 mksnap(self.fs, snappath)
69
70 def remove_snapshot(self, snapname):
71 snappath = os.path.join(self.path,
72 self.vol_spec.snapshot_dir_prefix.encode('utf-8'),
73 snapname.encode('utf-8'))
74 rmsnap(self.fs, snappath)
75
76 def list_snapshots(self):
77 try:
78 dirpath = os.path.join(self.path,
79 self.vol_spec.snapshot_dir_prefix.encode('utf-8'))
80 return listdir(self.fs, dirpath)
81 except VolumeException as ve:
82 if ve.errno == -errno.ENOENT:
83 return []
84 raise
85
86 def create_group(fs, vol_spec, groupname, pool, mode, uid, gid):
87 """
88 create a subvolume group.
89
90 :param fs: ceph filesystem handle
91 :param vol_spec: volume specification
92 :param groupname: subvolume group name
93 :param pool: the RADOS pool where the data objects of the subvolumes will be stored
94 :param mode: the user permissions
95 :param uid: the user identifier
96 :param gid: the group identifier
97 :return: None
98 """
99 group = Group(fs, vol_spec, groupname)
100 path = group.path
101 fs.mkdirs(path, mode)
102 try:
103 if not pool:
104 pool = get_ancestor_xattr(fs, path, "ceph.dir.layout.pool")
105 try:
106 fs.setxattr(path, 'ceph.dir.layout.pool', pool.encode('utf-8'), 0)
107 except cephfs.InvalidValue:
108 raise VolumeException(-errno.EINVAL,
109 "Invalid pool layout '{0}'. It must be a valid data pool".format(pool))
110 if uid is None:
111 uid = 0
112 else:
113 try:
114 uid = int(uid)
115 if uid < 0:
116 raise ValueError
117 except ValueError:
118 raise VolumeException(-errno.EINVAL, "invalid UID")
119 if gid is None:
120 gid = 0
121 else:
122 try:
123 gid = int(gid)
124 if gid < 0:
125 raise ValueError
126 except ValueError:
127 raise VolumeException(-errno.EINVAL, "invalid GID")
128 fs.chown(path, uid, gid)
129 except (cephfs.Error, VolumeException) as e:
130 try:
131 # cleanup group path on best effort basis
132 log.debug("cleaning up subvolume group path: {0}".format(path))
133 fs.rmdir(path)
134 except cephfs.Error as ce:
135 log.debug("failed to clean up subvolume group {0} with path: {1} ({2})".format(groupname, path, ce))
136 if isinstance(e, cephfs.Error):
137 e = VolumeException(-e.args[0], e.args[1])
138 raise e
139
140 def remove_group(fs, vol_spec, groupname):
141 """
142 remove a subvolume group.
143
144 :param fs: ceph filesystem handle
145 :param vol_spec: volume specification
146 :param groupname: subvolume group name
147 :return: None
148 """
149 group = Group(fs, vol_spec, groupname)
150 try:
151 fs.rmdir(group.path)
152 except cephfs.Error as e:
153 if e.args[0] == errno.ENOENT:
154 raise VolumeException(-errno.ENOENT, "subvolume group '{0}' does not exist".format(groupname))
155 raise VolumeException(-e.args[0], e.args[1])
156
157 @contextmanager
158 def open_group(fs, vol_spec, groupname):
159 """
160 open a subvolume group. This API is to be used as a context manager.
161
162 :param fs: ceph filesystem handle
163 :param vol_spec: volume specification
164 :param groupname: subvolume group name
165 :return: yields a group object (subclass of GroupTemplate)
166 """
167 group = Group(fs, vol_spec, groupname)
168 try:
169 st = fs.stat(group.path)
170 group.uid = int(st.st_uid)
171 group.gid = int(st.st_gid)
172 except cephfs.Error as e:
173 if e.args[0] == errno.ENOENT:
174 if not group.is_default_group():
175 raise VolumeException(-errno.ENOENT, "subvolume group '{0}' does not exist".format(groupname))
176 else:
177 raise VolumeException(-e.args[0], e.args[1])
178 yield group