]> git.proxmox.com Git - ceph.git/blob - ceph/qa/tasks/mgr/dashboard/test_cephfs.py
import 15.2.0 Octopus source
[ceph.git] / ceph / qa / tasks / mgr / dashboard / test_cephfs.py
1 # -*- coding: utf-8 -*-
2 from __future__ import absolute_import
3
4 import six
5 from contextlib import contextmanager
6
7 from .helper import DashboardTestCase, JObj, JList, JLeaf
8
9
10 class CephfsTest(DashboardTestCase):
11 CEPHFS = True
12
13 AUTH_ROLES = ['cephfs-manager']
14
15 QUOTA_PATH = '/quotas'
16
17 def assertToHave(self, data, key):
18 self.assertIn(key, data)
19 self.assertIsNotNone(data[key])
20
21 def get_fs_id(self):
22 return self.fs.get_namespace_id()
23
24 def mk_dirs(self, path, expectedStatus=200):
25 self._post("/api/cephfs/{}/mk_dirs".format(self.get_fs_id()),
26 params={'path': path})
27 self.assertStatus(expectedStatus)
28
29 def rm_dir(self, path, expectedStatus=200):
30 self._post("/api/cephfs/{}/rm_dir".format(self.get_fs_id()),
31 params={'path': path})
32 self.assertStatus(expectedStatus)
33
34 def get_root_directory(self, expectedStatus=200):
35 data = self._get("/api/cephfs/{}/get_root_directory".format(self.get_fs_id()))
36 self.assertStatus(expectedStatus)
37 self.assertIsInstance(data, dict)
38 return data
39
40 def ls_dir(self, path, expectedLength, depth = None):
41 return self._ls_dir(path, expectedLength, depth, "api")
42
43 def ui_ls_dir(self, path, expectedLength, depth = None):
44 return self._ls_dir(path, expectedLength, depth, "ui-api")
45
46 def _ls_dir(self, path, expectedLength, depth, baseApiPath):
47 params = {'path': path}
48 if depth is not None:
49 params['depth'] = depth
50 data = self._get("/{}/cephfs/{}/ls_dir".format(baseApiPath, self.get_fs_id()),
51 params=params)
52 self.assertStatus(200)
53 self.assertIsInstance(data, list)
54 self.assertEqual(len(data), expectedLength)
55 return data
56
57 def setQuotas(self, bytes=None, files=None):
58 quotas = {
59 'max_bytes': bytes,
60 'max_files': files
61 }
62 self._post("/api/cephfs/{}/set_quotas".format(self.get_fs_id()), data=quotas,
63 params={'path': self.QUOTA_PATH})
64 self.assertStatus(200)
65
66 def assertQuotas(self, bytes, files):
67 data = self.ls_dir('/', 1)[0]
68 self.assertEqual(data['quotas']['max_bytes'], bytes)
69 self.assertEqual(data['quotas']['max_files'], files)
70
71 @contextmanager
72 def new_quota_dir(self):
73 self.mk_dirs(self.QUOTA_PATH)
74 self.setQuotas(1024**3, 1024)
75 yield 1
76 self.rm_dir(self.QUOTA_PATH)
77
78 @DashboardTestCase.RunAs('test', 'test', ['block-manager'])
79 def test_access_permissions(self):
80 fs_id = self.get_fs_id()
81 self._get("/api/cephfs/{}/clients".format(fs_id))
82 self.assertStatus(403)
83 self._get("/api/cephfs/{}".format(fs_id))
84 self.assertStatus(403)
85 self._get("/api/cephfs/{}/mds_counters".format(fs_id))
86 self.assertStatus(403)
87 self._get("/ui-api/cephfs/{}/tabs".format(fs_id))
88 self.assertStatus(403)
89
90 def test_cephfs_clients(self):
91 fs_id = self.get_fs_id()
92 data = self._get("/api/cephfs/{}/clients".format(fs_id))
93 self.assertStatus(200)
94
95 self.assertIn('status', data)
96 self.assertIn('data', data)
97
98 def test_cephfs_evict_client_does_not_exist(self):
99 fs_id = self.get_fs_id()
100 self._delete("/api/cephfs/{}/client/1234".format(fs_id))
101 self.assertStatus(404)
102
103 def test_cephfs_get(self):
104 fs_id = self.get_fs_id()
105 data = self._get("/api/cephfs/{}/".format(fs_id))
106 self.assertStatus(200)
107
108 self.assertToHave(data, 'cephfs')
109 self.assertToHave(data, 'standbys')
110 self.assertToHave(data, 'versions')
111
112 def test_cephfs_mds_counters(self):
113 fs_id = self.get_fs_id()
114 data = self._get("/api/cephfs/{}/mds_counters".format(fs_id))
115 self.assertStatus(200)
116
117 self.assertIsInstance(data, dict)
118 self.assertIsNotNone(data)
119
120 def test_cephfs_mds_counters_wrong(self):
121 self._get("/api/cephfs/baadbaad/mds_counters")
122 self.assertStatus(400)
123 self.assertJsonBody({
124 "component": 'cephfs',
125 "code": "invalid_cephfs_id",
126 "detail": "Invalid cephfs ID baadbaad"
127 })
128
129 def test_cephfs_list(self):
130 data = self._get("/api/cephfs/")
131 self.assertStatus(200)
132
133 self.assertIsInstance(data, list)
134 cephfs = data[0]
135 self.assertToHave(cephfs, 'id')
136 self.assertToHave(cephfs, 'mdsmap')
137
138 def test_cephfs_tabs(self):
139 fs_id = self.get_fs_id()
140 data = self._get("/ui-api/cephfs/{}/tabs".format(fs_id))
141 self.assertStatus(200)
142 self.assertIsInstance(data, dict)
143
144 # Pools
145 pools = data['pools']
146 self.assertIsInstance(pools, list)
147 self.assertGreater(len(pools), 0)
148 for pool in pools:
149 self.assertEqual(pool['size'], pool['used'] + pool['avail'])
150
151 # Ranks
152 self.assertToHave(data, 'ranks')
153 self.assertIsInstance(data['ranks'], list)
154
155 # Name
156 self.assertToHave(data, 'name')
157 self.assertIsInstance(data['name'], six.string_types)
158
159 # Standbys
160 self.assertToHave(data, 'standbys')
161 self.assertIsInstance(data['standbys'], six.string_types)
162
163 # MDS counters
164 counters = data['mds_counters']
165 self.assertIsInstance(counters, dict)
166 self.assertGreater(len(counters.keys()), 0)
167 for k, v in counters.items():
168 self.assertEqual(v['name'], k)
169
170 # Clients
171 self.assertToHave(data, 'clients')
172 clients = data['clients']
173 self.assertToHave(clients, 'data')
174 self.assertIsInstance(clients['data'], list)
175 self.assertToHave(clients, 'status')
176 self.assertIsInstance(clients['status'], int)
177
178 def test_ls_mk_rm_dir(self):
179 self.ls_dir('/', 0)
180
181 self.mk_dirs('/pictures/birds')
182 self.ls_dir('/', 2, 3)
183 self.ls_dir('/pictures', 1)
184
185 self.rm_dir('/pictures', 500)
186 self.rm_dir('/pictures/birds')
187 self.rm_dir('/pictures')
188
189 self.ls_dir('/', 0)
190
191 def test_snapshots(self):
192 fs_id = self.get_fs_id()
193 self.mk_dirs('/movies/dune/extended_version')
194
195 self._post("/api/cephfs/{}/mk_snapshot".format(fs_id),
196 params={'path': '/movies/dune', 'name': 'test'})
197 self.assertStatus(200)
198
199 data = self.ls_dir('/movies', 1)
200 self.assertSchema(data[0], JObj(sub_elems={
201 'name': JLeaf(str),
202 'path': JLeaf(str),
203 'parent': JLeaf(str),
204 'snapshots': JList(JObj(sub_elems={
205 'name': JLeaf(str),
206 'path': JLeaf(str),
207 'created': JLeaf(str)
208 })),
209 'quotas': JObj(sub_elems={
210 'max_bytes': JLeaf(int),
211 'max_files': JLeaf(int)
212 })
213 }))
214 snapshots = data[0]['snapshots']
215 self.assertEqual(len(snapshots), 1)
216 snapshot = snapshots[0]
217 self.assertEqual(snapshot['name'], "test")
218 self.assertEqual(snapshot['path'], "/movies/dune/.snap/test")
219
220 # Should have filtered out "_test_$timestamp"
221 data = self.ls_dir('/movies/dune', 1)
222 snapshots = data[0]['snapshots']
223 self.assertEqual(len(snapshots), 0)
224
225 self._post("/api/cephfs/{}/rm_snapshot".format(fs_id),
226 params={'path': '/movies/dune', 'name': 'test'})
227 self.assertStatus(200)
228
229 data = self.ls_dir('/movies', 1)
230 self.assertEqual(len(data[0]['snapshots']), 0)
231
232 # Cleanup. Note, the CephFS Python extension (and therefor the Dashboard
233 # REST API) does not support recursive deletion of a directory.
234 self.rm_dir('/movies/dune/extended_version')
235 self.rm_dir('/movies/dune')
236 self.rm_dir('/movies')
237
238 def test_quotas_default(self):
239 self.mk_dirs(self.QUOTA_PATH)
240 self.assertQuotas(0, 0)
241 self.rm_dir(self.QUOTA_PATH)
242
243 def test_quotas_set_both(self):
244 with self.new_quota_dir():
245 self.assertQuotas(1024**3, 1024)
246
247 def test_quotas_set_only_bytes(self):
248 with self.new_quota_dir():
249 self.setQuotas(2048**3)
250 self.assertQuotas(2048**3, 1024)
251
252 def test_quotas_set_only_files(self):
253 with self.new_quota_dir():
254 self.setQuotas(None, 2048)
255 self.assertQuotas(1024**3, 2048)
256
257 def test_quotas_unset_both(self):
258 with self.new_quota_dir():
259 self.setQuotas(0, 0)
260 self.assertQuotas(0, 0)
261
262 def test_listing_of_root_dir(self):
263 self.ls_dir('/', 0) # Should not list root
264 ui_root = self.ui_ls_dir('/', 1)[0] # Should list root by default
265 root = self.get_root_directory()
266 self.assertEqual(ui_root, root)
267
268 def test_listing_of_ui_api_ls_on_deeper_levels(self):
269 # The UI-API and API ls_dir methods should behave the same way on deeper levels
270 self.mk_dirs('/pictures')
271 api_ls = self.ls_dir('/pictures', 0)
272 ui_api_ls = self.ui_ls_dir('/pictures', 0)
273 self.assertEqual(api_ls, ui_api_ls)
274 self.rm_dir('/pictures')