]> git.proxmox.com Git - ceph.git/blame - ceph/src/test/librgw_file_xattr.cc
buildsys: switch source download to quincy
[ceph.git] / ceph / src / test / librgw_file_xattr.cc
CommitLineData
f67539c2
TL
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) 2015 Red Hat, Inc.
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 <stdint.h>
16#include <tuple>
17#include <iostream>
18#include <vector>
19#include <map>
20#include <random>
21#include <boost/algorithm/string.hpp>
22#include "xxhash.h"
23
24#include "include/rados/librgw.h"
25#include "include/rados/rgw_file.h"
26#include "rgw/rgw_file.h"
27
28#include "gtest/gtest.h"
29#include "common/ceph_argparse.h"
30#include "common/errno.h"
31#include "common/debug.h"
32#include "global/global_init.h"
33#include "include/ceph_assert.h"
34
35#define dout_context g_ceph_context
36#define dout_subsys ceph_subsys_rgw
37
38namespace {
39
40 using namespace rgw;
41
42 string uid("testuser");
43 string access_key("");
44 string secret_key("");
45
46 librgw_t rgw_h = nullptr;
47 struct rgw_fs *fs = nullptr;
48
49 uint32_t owner_uid = 867;
50 uint32_t owner_gid = 5309;
51 uint32_t create_mask = RGW_SETATTR_UID | RGW_SETATTR_GID | RGW_SETATTR_MODE;
52
53 string bucket_name{"v4recov"};
54 string object_path{"node0/clientids"};
55
56 string key1{"black"};
57 string val1{"metallic"};
58
59 struct rgw_file_handle *bucket_fh = nullptr;
60 struct rgw_file_handle *object_fh = nullptr;
61
62 typedef std::tuple<string,uint64_t, struct rgw_file_handle*> fid_type;
63 std::vector<fid_type> fids;
64
65 class obj_rec
66 {
67 public:
68 string name;
69 struct rgw_file_handle* fh;
70 struct rgw_file_handle* parent_fh;
71 RGWFileHandle* rgw_fh; // alias into fh
72
73 struct state {
74 bool readdir;
75 state() : readdir(false) {}
76 } state;
77
78 obj_rec(string _name, struct rgw_file_handle* _fh,
79 struct rgw_file_handle* _parent_fh, RGWFileHandle* _rgw_fh)
80 : name(std::move(_name)), fh(_fh), parent_fh(_parent_fh),
81 rgw_fh(_rgw_fh) {}
82
83 void clear() {
84 fh = nullptr;
85 rgw_fh = nullptr;
86 }
87
88 void sync() {
89 if (fh)
90 rgw_fh = get_rgwfh(fh);
91 }
92
93 friend ostream& operator<<(ostream& os, const obj_rec& rec);
94 };
95
96 ostream& operator<<(ostream& os, const obj_rec& rec)
97 {
98 RGWFileHandle* rgw_fh = rec.rgw_fh;
99 if (rgw_fh) {
100 const char* type = rgw_fh->is_dir() ? "DIR " : "FILE ";
101 os << rec.rgw_fh->full_object_name()
102 << " (" << rec.rgw_fh->object_name() << "): "
103 << type;
104 }
105 return os;
106 }
107
108 typedef std::vector<obj_rec> obj_vec;
109 obj_vec ovec;
110
111 bool do_stat = false;
112 bool do_create = false;
113 bool do_delete = false;
114 bool do_hexdump = false;
115 bool verbose = false;
116
117 struct {
118 int argc;
119 char **argv;
120 } saved_args;
121}
122
123TEST(LibRGW, INIT) {
124 int ret = librgw_create(&rgw_h, saved_args.argc, saved_args.argv);
125 ASSERT_EQ(ret, 0);
126 ASSERT_NE(rgw_h, nullptr);
127}
128
129TEST(LibRGW, MOUNT) {
130 int ret = rgw_mount(rgw_h, uid.c_str(), access_key.c_str(),
131 secret_key.c_str(), &fs, RGW_MOUNT_FLAG_NONE);
132 ASSERT_EQ(ret, 0);
133 ASSERT_NE(fs, nullptr);
134}
135
136TEST(LibRGW, LOOKUP_BUCKET) {
137 int ret = rgw_lookup(fs, fs->root_fh, bucket_name.c_str(), &bucket_fh,
138 nullptr, 0, RGW_LOOKUP_FLAG_NONE);
139 ASSERT_EQ(ret, 0);
140}
141
142TEST(LibRGW, CREATE_BUCKET) {
143 if ((! bucket_fh) && do_create) {
144 struct stat st;
145
146 st.st_uid = owner_uid;
147 st.st_gid = owner_gid;
148 st.st_mode = 755;
149
150 int ret = rgw_mkdir(fs, fs->root_fh, bucket_name.c_str(), &st, create_mask,
151 &bucket_fh, RGW_MKDIR_FLAG_NONE);
152 ASSERT_EQ(ret, 0);
153 }
154}
155
156TEST(LibRGW, CREATE_PATH) {
157
158 if (!bucket_fh)
159 return;
160
161 vector<string> segs;
162 boost::split(segs, object_path, boost::is_any_of("/"));
163
164 struct stat st;
165 st.st_uid = owner_uid;
166 st.st_gid = owner_gid;
167 st.st_mode = 755;
168
169 int ix, ret, sz = segs.size();
170 for (ix = 0; ix < sz; ++ix) {
171 auto& seg = segs[ix];
172 struct rgw_file_handle* parent_fh = (ix > 0) ? ovec[ix-1].fh : bucket_fh;
173 obj_rec dir{seg, nullptr, parent_fh, nullptr};
174 if (do_create) {
175 ret = rgw_mkdir(fs, dir.parent_fh, dir.name.c_str(), &st, create_mask,
176 &dir.fh, RGW_MKDIR_FLAG_NONE);
177 } else {
178 ret = rgw_lookup(fs, dir.parent_fh, dir.name.c_str(), &dir.fh,
179 nullptr, 0, RGW_LOOKUP_FLAG_NONE);
180 }
181 ASSERT_EQ(ret, 0);
182 dir.sync();
183 ovec.push_back(dir);
184 if (verbose) {
185 std::cout << "create: " << dir.name << std::endl;
186 }
187 }
188}
189
190TEST(LibRGW, CHECK_PATH_REFS) {
191
192 if (!bucket_fh)
193 return;
194
195 int ix, sz = ovec.size();
196 for (ix = 0; ix < sz; ++ix) {
197 auto& dir = ovec[ix];
198 if (verbose) {
199 std::cout << "name: " << dir.name
200 << " refcnt: " << dir.rgw_fh->get_refcnt()
201 << std::endl;
202 }
203 if (ix == 0) {
204 // sentinel, +1 parent, +1 path
205 ASSERT_EQ(dir.rgw_fh->get_refcnt(), 3U);
206 }
207 if (ix == 1) {
208 // sentinel, +1 path
209 ASSERT_EQ(dir.rgw_fh->get_refcnt(), 2U);
210 }
211 }
212}
213
214TEST(LibRGW, SETXATTR1) {
215
216 if (!bucket_fh)
217 return;
218
219 auto& dir = ovec[ovec.size()-1];
220 rgw_xattrstr xattr_k = { const_cast<char*>(key1.c_str()),
221 uint32_t(key1.length()) };
222 rgw_xattrstr xattr_v = { const_cast<char*>(val1.c_str()),
223 uint32_t(val1.length()) };
224
225 rgw_xattr xattr = { xattr_k, xattr_v };
226 rgw_xattrlist xattrlist = { &xattr, 1 };
227
228 int ret = rgw_setxattrs(fs, dir.fh, &xattrlist, RGW_SETXATTR_FLAG_NONE);
229 ASSERT_EQ(ret, 0);
230}
231
232extern "C" {
233 static int getattr_cb(rgw_xattrlist *attrs, void *arg, uint32_t flags)
234 {
235 auto& attrmap =
236 *(static_cast<std::map<std::string, std::string>*>(arg));
237 for (uint32_t ix = 0; ix < attrs->xattr_cnt; ++ix) {
238 auto& xattr = attrs->xattrs[ix];
239 string k{xattr.key.val, xattr.key.len};
240 string v{xattr.val.val, xattr.val.len};
241 if (verbose) {
242 std::cout << __func__
243 << " attr k: " << k << " v: " << v
244 << std::endl;
245 }
246 attrmap.insert(std::map<std::string, std::string>::value_type(k, v));
247 }
248 return 0;
249 }
250}
251
252TEST(LibRGW, GETXATTR1) {
253
254 if (!bucket_fh)
255 return;
256
257 using std::get;
258 auto& dir = ovec[ovec.size()-1];
259
260 rgw_xattrstr xattr_k1 =
261 {const_cast<char*>(key1.c_str()), uint32_t(key1.length())};
262 rgw_xattrstr xattr_v1 = {nullptr, 0};
263
264 std::string key2 = "user.rgw.etag";
265 rgw_xattrstr xattr_k2 =
266 {const_cast<char*>(key2.c_str()), uint32_t(key2.length())};
267 rgw_xattrstr xattr_v2 = {nullptr, 0};
268
269 rgw_xattr xattrs[2] = {{xattr_k1, xattr_v1},
270 {xattr_k2, xattr_v2}};
271
272 /* XXX gcc won't accept static_cast here, don't see why */
273 rgw_xattrlist xattrlist = {reinterpret_cast<rgw_xattr*>(&xattrs), 2};
274
275 std::map<std::string, std::string> out_attrmap;
276
277 int ret = rgw_getxattrs(fs, dir.fh, &xattrlist, getattr_cb, &out_attrmap,
278 RGW_GETXATTR_FLAG_NONE);
279 ASSERT_EQ(ret, 0);
280 /* check exposed attrs */
281 ASSERT_TRUE(out_attrmap.find("user.rgw.etag") != out_attrmap.end());
282 /* check our user attr */
283 ASSERT_TRUE(out_attrmap.find(key1) != out_attrmap.end());
284}
285
286TEST(LibRGW, LSXATTR1) {
287
288 if (!bucket_fh)
289 return;
290
291 using std::get;
292 auto& dir = ovec[ovec.size()-1];
293
294 rgw_xattrstr filter_prefix = { nullptr, 0}; // XXX ignored, for now
295
296 std::map<std::string, std::string> out_attrmap;
297
298 int ret = rgw_lsxattrs(fs, dir.fh, &filter_prefix, getattr_cb,
299 &out_attrmap, RGW_LSXATTR_FLAG_NONE);
300 ASSERT_EQ(ret, 0);
301
302 /* check exposed attrs */
303 ASSERT_TRUE(out_attrmap.find("user.rgw.etag") != out_attrmap.end());
304}
305
306TEST(LibRGW, RMXATTR1) {
307
308 if (!bucket_fh)
309 return;
310
311 using std::get;
312 auto& dir = ovec[ovec.size()-1];
313
314 rgw_xattrstr xattr_k = { const_cast<char*>(key1.c_str()),
315 uint32_t(key1.length()) };
316 rgw_xattrstr xattr_v = { nullptr, 0 };
317
318 rgw_xattr xattr = { xattr_k, xattr_v };
319 rgw_xattrlist xattrlist = { &xattr, 1 };
320
321 int ret = rgw_rmxattrs(fs, dir.fh, &xattrlist, RGW_RMXATTR_FLAG_NONE);
322 ASSERT_EQ(ret, 0);
323}
324
325TEST(LibRGW, LSXATTR2) {
326
327 if (!bucket_fh)
328 return;
329
330 using std::get;
331 auto& dir = ovec[ovec.size()-1];
332
333 rgw_xattrstr filter_prefix = { nullptr, 0 }; // XXX ignored, for now
334
335 std::map<std::string, std::string> out_attrmap;
336
337 int ret = rgw_lsxattrs(fs, dir.fh, &filter_prefix, getattr_cb,
338 &out_attrmap, RGW_LSXATTR_FLAG_NONE);
339 ASSERT_EQ(ret, 0);
340 /* check exposed attrs */
341 ASSERT_TRUE(out_attrmap.find("user.rgw.etag") != out_attrmap.end());
342 /* verify deletion */
343 ASSERT_TRUE(out_attrmap.find(key1) == out_attrmap.end());
344}
345
346TEST(LibRGW, CLEANUP) {
347 int ret = 0;
348 if (object_fh) {
349 ret = rgw_fh_rele(fs, object_fh, 0 /* flags */);
350 ASSERT_EQ(ret, 0);
351 }
352 if (bucket_fh) {
353 ret = rgw_fh_rele(fs, bucket_fh, 0 /* flags */);
354 }
355 ASSERT_EQ(ret, 0);
356}
357
358TEST(LibRGW, UMOUNT) {
359 if (! fs)
360 return;
361
362 int ret = rgw_umount(fs, RGW_UMOUNT_FLAG_NONE);
363 ASSERT_EQ(ret, 0);
364}
365
366TEST(LibRGW, SHUTDOWN) {
367 librgw_shutdown(rgw_h);
368}
369
370int main(int argc, char *argv[])
371{
372 char *v{nullptr};
373 string val;
374 vector<const char*> args;
375
376 argv_to_vec(argc, const_cast<const char**>(argv), args);
377 env_to_vec(args);
378
379 v = getenv("AWS_ACCESS_KEY_ID");
380 if (v) {
381 access_key = v;
382 }
383
384 v = getenv("AWS_SECRET_ACCESS_KEY");
385 if (v) {
386 secret_key = v;
387 }
388
389 for (auto arg_iter = args.begin(); arg_iter != args.end();) {
390 if (ceph_argparse_witharg(args, arg_iter, &val, "--access",
391 (char*) nullptr)) {
392 access_key = val;
393 } else if (ceph_argparse_witharg(args, arg_iter, &val, "--secret",
394 (char*) nullptr)) {
395 secret_key = val;
396 } else if (ceph_argparse_witharg(args, arg_iter, &val, "--uid",
397 (char*) nullptr)) {
398 uid = val;
399 } else if (ceph_argparse_witharg(args, arg_iter, &val, "--bn",
400 (char*) nullptr)) {
401 bucket_name = val;
402 } else if (ceph_argparse_flag(args, arg_iter, "--stat",
403 (char*) nullptr)) {
404 do_stat = true;
405 } else if (ceph_argparse_flag(args, arg_iter, "--create",
406 (char*) nullptr)) {
407 do_create = true;
408 } else if (ceph_argparse_flag(args, arg_iter, "--delete",
409 (char*) nullptr)) {
410 do_delete = true;
411 } else if (ceph_argparse_flag(args, arg_iter, "--hexdump",
412 (char*) nullptr)) {
413 do_hexdump = true;
414 } else if (ceph_argparse_flag(args, arg_iter, "--verbose",
415 (char*) nullptr)) {
416 verbose = true;
417 } else {
418 ++arg_iter;
419 }
420 }
421
422 /* dont accidentally run as anonymous */
423 if ((access_key == "") ||
424 (secret_key == "")) {
425 std::cout << argv[0] << " no AWS credentials, exiting" << std::endl;
426 return EPERM;
427 }
428
429 saved_args.argc = argc;
430 saved_args.argv = argv;
431
432 ::testing::InitGoogleTest(&argc, argv);
433 return RUN_ALL_TESTS();
434}