Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / test / libcephfs / access.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3 /*
4  * Ceph - scalable distributed file system
5  *
6  * Copyright (C) 2011 New Dream Network
7  *
8  * This is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License version 2.1, as published by the Free Software
11  * Foundation.  See file COPYING.
12  *
13  */
14
15 #include "gtest/gtest.h"
16 #include "common/ceph_argparse.h"
17 #include "include/buffer.h"
18 #include "include/stringify.h"
19 #include "include/cephfs/libcephfs.h"
20 #include "include/rados/librados.h"
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <unistd.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <dirent.h>
27 #include <sys/xattr.h>
28 #include <sys/uio.h>
29 #include <iostream>
30 #include <vector>
31 #include "json_spirit/json_spirit.h"
32
33 #ifdef __linux__
34 #include <limits.h>
35 #endif
36
37
38 rados_t cluster;
39
40 string key;
41
42 int do_mon_command(string s, string *key)
43 {
44   char *outs, *outbuf;
45   size_t outs_len, outbuf_len;
46   const char *ss = s.c_str();
47   int r = rados_mon_command(cluster, (const char **)&ss, 1,
48                             0, 0,
49                             &outbuf, &outbuf_len,
50                             &outs, &outs_len);
51   if (outbuf_len) {
52     string s(outbuf, outbuf_len);
53     std::cout << "out: " << s << std::endl;
54
55     // parse out the key
56     json_spirit::mValue v, k;
57     json_spirit::read_or_throw(s, v);
58     k = v.get_array()[0].get_obj().find("key")->second;
59     *key = k.get_str();
60     std::cout << "key: " << *key << std::endl;
61     free(outbuf);
62   } else {
63     return -EINVAL;
64   }
65   if (outs_len) {
66     string s(outs, outs_len);
67     std::cout << "outs: " << s << std::endl;
68     free(outs);
69   }
70   return r;
71 }
72
73 string get_unique_dir()
74 {
75   return string("/ceph_test_libcephfs_access.") + stringify(rand());
76 }
77
78 TEST(AccessTest, Foo) {
79   string dir = get_unique_dir();
80   string user = "libcephfs_foo_test." + stringify(rand());
81   // admin mount to set up test
82   struct ceph_mount_info *admin;
83   ASSERT_EQ(0, ceph_create(&admin, NULL));
84   ASSERT_EQ(0, ceph_conf_read_file(admin, NULL));
85   ASSERT_EQ(0, ceph_conf_parse_env(admin, NULL));
86   ASSERT_EQ(0, ceph_mount(admin, "/"));
87   ASSERT_EQ(0, ceph_mkdir(admin, dir.c_str(), 0755));
88
89   // create access key
90   string key;
91   ASSERT_EQ(0, do_mon_command(
92       "{\"prefix\": \"auth get-or-create\", \"entity\": \"client." + user + "\", "
93       "\"caps\": [\"mon\", \"allow *\", \"osd\", \"allow rw\", "
94       "\"mds\", \"allow rw\""
95       "], \"format\": \"json\"}", &key));
96
97   struct ceph_mount_info *cmount;
98   ASSERT_EQ(0, ceph_create(&cmount, user.c_str()));
99   ASSERT_EQ(0, ceph_conf_read_file(cmount, NULL));
100   ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
101   ASSERT_EQ(0, ceph_conf_set(cmount, "key", key.c_str()));
102   ASSERT_EQ(0, ceph_mount(cmount, "/"));
103
104   ceph_shutdown(cmount);
105
106   // clean up
107   ASSERT_EQ(0, ceph_rmdir(admin, dir.c_str()));
108   ceph_shutdown(admin);
109 }
110
111 TEST(AccessTest, Path) {
112   string good = get_unique_dir();
113   string bad = get_unique_dir();
114   string user = "libcephfs_path_test." + stringify(rand());
115   struct ceph_mount_info *admin;
116   ASSERT_EQ(0, ceph_create(&admin, NULL));
117   ASSERT_EQ(0, ceph_conf_read_file(admin, NULL));
118   ASSERT_EQ(0, ceph_conf_parse_env(admin, NULL));
119   ASSERT_EQ(0, ceph_mount(admin, "/"));
120   ASSERT_EQ(0, ceph_mkdir(admin, good.c_str(), 0755));
121   ASSERT_EQ(0, ceph_mkdir(admin, string(good + "/p").c_str(), 0755));
122   ASSERT_EQ(0, ceph_mkdir(admin, bad.c_str(), 0755));
123   ASSERT_EQ(0, ceph_mkdir(admin, string(bad + "/p").c_str(), 0755));
124   int fd = ceph_open(admin, string(good + "/q").c_str(), O_CREAT|O_WRONLY, 0755);
125   ceph_close(admin, fd);
126   fd = ceph_open(admin, string(bad + "/q").c_str(), O_CREAT|O_WRONLY, 0755);
127   ceph_close(admin, fd);
128   fd = ceph_open(admin, string(bad + "/z").c_str(), O_CREAT|O_WRONLY, 0755);
129   ceph_write(admin, fd, "TEST FAILED", 11, 0);
130   ceph_close(admin, fd);
131
132   string key;
133   ASSERT_EQ(0, do_mon_command(
134       "{\"prefix\": \"auth get-or-create\", \"entity\": \"client." + user + "\", "
135       "\"caps\": [\"mon\", \"allow r\", \"osd\", \"allow rwx\", "
136       "\"mds\", \"allow r, allow rw path=" + good + "\""
137       "], \"format\": \"json\"}", &key));
138
139   struct ceph_mount_info *cmount;
140   ASSERT_EQ(0, ceph_create(&cmount, user.c_str()));
141   ASSERT_EQ(0, ceph_conf_read_file(cmount, NULL));
142   ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
143   ASSERT_EQ(0, ceph_conf_set(cmount, "key", key.c_str()));
144   ASSERT_EQ(0, ceph_mount(cmount, "/"));
145
146   // allowed
147   ASSERT_GE(ceph_mkdir(cmount, string(good + "/x").c_str(), 0755), 0);
148   ASSERT_GE(ceph_rmdir(cmount, string(good + "/p").c_str()), 0);
149   ASSERT_GE(ceph_unlink(cmount, string(good + "/q").c_str()), 0);
150   fd = ceph_open(cmount, string(good + "/y").c_str(), O_CREAT|O_WRONLY, 0755);
151   ASSERT_GE(fd, 0);
152   ceph_write(cmount, fd, "bar", 3, 0);
153   ceph_close(cmount, fd);
154   ASSERT_GE(ceph_unlink(cmount, string(good + "/y").c_str()), 0);
155   ASSERT_GE(ceph_rmdir(cmount, string(good + "/x").c_str()), 0);
156
157   fd = ceph_open(cmount, string(bad + "/z").c_str(), O_RDONLY, 0644);
158   ASSERT_GE(fd, 0);
159   ceph_close(cmount, fd);
160
161   // not allowed
162   ASSERT_LT(ceph_mkdir(cmount, string(bad + "/x").c_str(), 0755), 0);
163   ASSERT_LT(ceph_rmdir(cmount, string(bad + "/p").c_str()), 0);
164   ASSERT_LT(ceph_unlink(cmount, string(bad + "/q").c_str()), 0);
165   fd = ceph_open(cmount, string(bad + "/y").c_str(), O_CREAT|O_WRONLY, 0755);
166   ASSERT_LT(fd, 0);
167
168   // unlink open file
169   fd = ceph_open(cmount, string(good + "/unlinkme").c_str(), O_CREAT|O_WRONLY, 0755);
170   ceph_unlink(cmount, string(good + "/unlinkme").c_str());
171   ASSERT_GE(ceph_write(cmount, fd, "foo", 3, 0), 0);
172   ASSERT_GE(ceph_fchmod(cmount, fd, 0777), 0);
173   ASSERT_GE(ceph_ftruncate(cmount, fd, 0), 0);
174   ASSERT_GE(ceph_fsetxattr(cmount, fd, "user.any", "bar", 3, 0), 0);
175   ceph_close(cmount, fd);
176
177   // rename open file
178   fd = ceph_open(cmount, string(good + "/renameme").c_str(), O_CREAT|O_WRONLY, 0755);
179   ASSERT_EQ(ceph_rename(admin, string(good + "/renameme").c_str(),
180                         string(bad + "/asdf").c_str()), 0);
181   ASSERT_GE(ceph_write(cmount, fd, "foo", 3, 0), 0);
182   ASSERT_GE(ceph_fchmod(cmount, fd, 0777), -EACCES);
183   ASSERT_GE(ceph_ftruncate(cmount, fd, 0), -EACCES);
184   ASSERT_GE(ceph_fsetxattr(cmount, fd, "user.any", "bar", 3, 0), -EACCES);
185   ceph_close(cmount, fd);
186
187   ceph_shutdown(cmount);
188   ASSERT_EQ(0, ceph_unlink(admin, string(bad + "/q").c_str()));
189   ASSERT_EQ(0, ceph_unlink(admin, string(bad + "/z").c_str()));
190   ASSERT_EQ(0, ceph_rmdir(admin, string(bad + "/p").c_str()));
191   ASSERT_EQ(0, ceph_unlink(admin, string(bad + "/asdf").c_str()));
192   ASSERT_EQ(0, ceph_rmdir(admin, good.c_str()));
193   ASSERT_EQ(0, ceph_rmdir(admin, bad.c_str()));
194   ceph_shutdown(admin);
195 }
196
197 TEST(AccessTest, ReadOnly) {
198   string dir = get_unique_dir();
199   string dir2 = get_unique_dir();
200   string user = "libcephfs_readonly_test." + stringify(rand());
201   struct ceph_mount_info *admin;
202   ASSERT_EQ(0, ceph_create(&admin, NULL));
203   ASSERT_EQ(0, ceph_conf_read_file(admin, NULL));
204   ASSERT_EQ(0, ceph_conf_parse_env(admin, NULL));
205   ASSERT_EQ(0, ceph_mount(admin, "/"));
206   ASSERT_EQ(0, ceph_mkdir(admin, dir.c_str(), 0755));
207   int fd = ceph_open(admin, string(dir + "/out").c_str(), O_CREAT|O_WRONLY, 0755);
208   ceph_write(admin, fd, "foo", 3, 0);
209   ceph_close(admin,fd);
210
211   string key;
212   ASSERT_EQ(0, do_mon_command(
213       "{\"prefix\": \"auth get-or-create\", \"entity\": \"client." + user + "\", "
214       "\"caps\": [\"mon\", \"allow r\", \"osd\", \"allow rw\", "
215       "\"mds\", \"allow r\""
216       "], \"format\": \"json\"}", &key));
217
218   struct ceph_mount_info *cmount;
219   ASSERT_EQ(0, ceph_create(&cmount, user.c_str()));
220   ASSERT_EQ(0, ceph_conf_read_file(cmount, NULL));
221   ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
222   ASSERT_EQ(0, ceph_conf_set(cmount, "key", key.c_str()));
223   ASSERT_EQ(0, ceph_mount(cmount, "/"));
224
225   // allowed
226   fd = ceph_open(cmount, string(dir + "/out").c_str(), O_RDONLY, 0644);
227   ASSERT_GE(fd, 0);
228   ceph_close(cmount,fd);
229
230   // not allowed
231   fd = ceph_open(cmount, string(dir + "/bar").c_str(), O_CREAT|O_WRONLY, 0755);
232   ASSERT_LT(fd, 0);
233   ASSERT_LT(ceph_mkdir(cmount, dir2.c_str(), 0755), 0);
234
235   ceph_shutdown(cmount);
236   ASSERT_EQ(0, ceph_unlink(admin, string(dir + "/out").c_str()));
237   ASSERT_EQ(0, ceph_rmdir(admin, dir.c_str()));
238   ceph_shutdown(admin);
239 }
240
241 TEST(AccessTest, User) {
242   string dir = get_unique_dir();
243   string user = "libcephfs_user_test." + stringify(rand());
244
245   // admin mount to set up test
246   struct ceph_mount_info *admin;
247   ASSERT_EQ(0, ceph_create(&admin, NULL));
248   ASSERT_EQ(0, ceph_conf_read_file(admin, NULL));
249   ASSERT_EQ(0, ceph_conf_parse_env(admin, NULL));
250   ASSERT_EQ(0, ceph_conf_set(admin, "client_permissions", "0"));
251   ASSERT_EQ(0, ceph_mount(admin, "/"));
252   ASSERT_EQ(0, ceph_mkdir(admin, dir.c_str(), 0755));
253
254   // create access key
255   string key;
256   ASSERT_EQ(0, do_mon_command(
257       "{\"prefix\": \"auth get-or-create\", \"entity\": \"client." + user + "\", "
258       "\"caps\": [\"mon\", \"allow *\", \"osd\", \"allow rw\", "
259       "\"mds\", \"allow rw uid=123 gids=456,789\""
260       "], \"format\": \"json\"}", &key));
261
262   struct ceph_mount_info *cmount;
263   ASSERT_EQ(0, ceph_create(&cmount, user.c_str()));
264   ASSERT_EQ(0, ceph_conf_read_file(cmount, NULL));
265   ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
266   ASSERT_EQ(0, ceph_conf_set(cmount, "key", key.c_str()));
267   ASSERT_EQ(-EACCES, ceph_mount(cmount, "/"));
268   ASSERT_EQ(0, ceph_conf_set(cmount, "client_mount_uid", "123"));
269   ASSERT_EQ(0, ceph_conf_set(cmount, "client_mount_gid", "456"));
270   ASSERT_EQ(0, ceph_conf_set(cmount, "client_permissions", "0"));
271   ASSERT_EQ(0, ceph_mount(cmount, "/"));
272
273   // user bits
274   ASSERT_EQ(0, ceph_chmod(admin, dir.c_str(), 0700));
275   ASSERT_EQ(0, ceph_chown(admin, dir.c_str(), 123, 456));
276   ASSERT_EQ(0, ceph_mkdir(cmount, string(dir + "/u1").c_str(), 0755));
277   ASSERT_EQ(0, ceph_chown(admin, dir.c_str(), 1, 456));
278   ASSERT_EQ(-EACCES, ceph_mkdir(cmount, string(dir + "/no").c_str(), 0755));
279
280   // group bits
281   ASSERT_EQ(0, ceph_chmod(admin, dir.c_str(), 0770));
282   ASSERT_EQ(0, ceph_chown(admin, dir.c_str(), 1, 456));
283   ASSERT_EQ(0, ceph_mkdir(cmount, string(dir + "/u2").c_str(), 0755));
284   ASSERT_EQ(0, ceph_chown(admin, dir.c_str(), 1, 2));
285   ASSERT_EQ(-EACCES, ceph_mkdir(cmount, string(dir + "/no").c_str(), 0755));
286
287   // user overrides group
288   ASSERT_EQ(0, ceph_chmod(admin, dir.c_str(), 0470));
289   ASSERT_EQ(0, ceph_chown(admin, dir.c_str(), 123, 456));
290   ASSERT_EQ(-EACCES, ceph_mkdir(cmount, string(dir + "/no").c_str(), 0755));
291
292   // other
293   ASSERT_EQ(0, ceph_chmod(admin, dir.c_str(), 0777));
294   ASSERT_EQ(0, ceph_chown(admin, dir.c_str(), 1, 1));
295   ASSERT_EQ(0, ceph_mkdir(cmount, string(dir + "/u3").c_str(), 0755));
296   ASSERT_EQ(0, ceph_chmod(admin, dir.c_str(), 0770));
297   ASSERT_EQ(-EACCES, ceph_mkdir(cmount, string(dir + "/no").c_str(), 0755));
298
299   // user and group overrides other
300   ASSERT_EQ(0, ceph_chmod(admin, dir.c_str(), 07));
301   ASSERT_EQ(0, ceph_chown(admin, dir.c_str(), 1, 456));
302   ASSERT_EQ(-EACCES, ceph_mkdir(cmount, string(dir + "/no").c_str(), 0755));
303   ASSERT_EQ(0, ceph_chown(admin, dir.c_str(), 123, 1));
304   ASSERT_EQ(-EACCES, ceph_mkdir(cmount, string(dir + "/no").c_str(), 0755));
305   ASSERT_EQ(0, ceph_chown(admin, dir.c_str(), 123, 456));
306   ASSERT_EQ(-EACCES, ceph_mkdir(cmount, string(dir + "/no").c_str(), 0755));
307
308   // chown and chgrp
309   ASSERT_EQ(0, ceph_chmod(admin, dir.c_str(), 0700));
310   ASSERT_EQ(0, ceph_chown(admin, dir.c_str(), 123, 456));
311   // FIXME: Re-enable these 789 tests once we can set multiple GIDs via libcephfs/config
312   // ASSERT_EQ(0, ceph_chown(cmount, dir.c_str(), 123, 789));
313   ASSERT_EQ(0, ceph_chown(cmount, dir.c_str(), 123, 456));
314   // ASSERT_EQ(0, ceph_chown(cmount, dir.c_str(), -1, 789));
315   ASSERT_EQ(0, ceph_chown(cmount, dir.c_str(), -1, 456));
316   ASSERT_EQ(-EACCES, ceph_chown(cmount, dir.c_str(), 123, 1));
317   ASSERT_EQ(-EACCES, ceph_chown(cmount, dir.c_str(), 1, 456));
318
319   ASSERT_EQ(0, ceph_chown(admin, dir.c_str(), 1, 1));
320   ASSERT_EQ(-EACCES, ceph_chown(cmount, dir.c_str(), 123, 456));
321   ASSERT_EQ(-EACCES, ceph_chown(cmount, dir.c_str(), 123, -1));
322   ASSERT_EQ(-EACCES, ceph_chown(cmount, dir.c_str(), -1, 456));
323
324   ASSERT_EQ(0, ceph_chown(admin, dir.c_str(), 1, 456));
325   ASSERT_EQ(-EACCES, ceph_chown(cmount, dir.c_str(), 123, 456));
326   ASSERT_EQ(-EACCES, ceph_chown(cmount, dir.c_str(), 123, -1));
327   ASSERT_EQ(-EACCES, ceph_chown(cmount, dir.c_str(), -1, 456));
328
329   ASSERT_EQ(0, ceph_chown(admin, dir.c_str(), 123, 1));
330   ASSERT_EQ(0, ceph_chown(cmount, dir.c_str(), -1, 456));
331   // ASSERT_EQ(0, ceph_chown(cmount, dir.c_str(), 123, 789));
332
333   ceph_shutdown(cmount);
334
335   // clean up
336   ASSERT_EQ(0, ceph_rmdir(admin, string(dir + "/u1").c_str()));
337   ASSERT_EQ(0, ceph_rmdir(admin, string(dir + "/u2").c_str()));
338   ASSERT_EQ(0, ceph_rmdir(admin, string(dir + "/u3").c_str()));
339   ASSERT_EQ(0, ceph_rmdir(admin, dir.c_str()));
340   ceph_shutdown(admin);
341 }
342
343 static int update_root_mode()
344 {
345   struct ceph_mount_info *admin;
346   int r = ceph_create(&admin, NULL);
347   if (r < 0)
348     return r;
349   ceph_conf_read_file(admin, NULL);
350   ceph_conf_parse_env(admin, NULL);
351   ceph_conf_set(admin, "client_permissions", "false");
352   r = ceph_mount(admin, "/");
353   if (r < 0)
354     goto out;
355   r = ceph_chmod(admin, "/", 0777);
356 out:
357   ceph_shutdown(admin);
358   return r;
359 }
360
361
362 int main(int argc, char **argv)
363 {
364   int r = update_root_mode();
365   if (r < 0)
366     exit(1);
367
368   ::testing::InitGoogleTest(&argc, argv);
369
370   srand(getpid());
371
372   r = rados_create(&cluster, NULL);
373   if (r < 0)
374     exit(1);
375   
376   r = rados_conf_read_file(cluster, NULL);
377   if (r < 0)
378     exit(1);
379
380   rados_conf_parse_env(cluster, NULL);
381   r = rados_connect(cluster);
382   if (r < 0)
383     exit(1);
384
385   r = RUN_ALL_TESTS();
386
387   rados_shutdown(cluster);
388
389   return r;
390 }