]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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) 2013 eNovance SAS <licensing@enovance.com> | |
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 | #include <iostream> | |
15 | #include <stdio.h> | |
16 | #include <stdlib.h> | |
17 | #include <string.h> | |
18 | #include <errno.h> | |
19 | #include <sys/wait.h> | |
20 | #include <unistd.h> | |
21 | #include <fstream> | |
22 | #include <map> | |
23 | #include <list> | |
24 | extern "C"{ | |
25 | #include <curl/curl.h> | |
26 | } | |
27 | #include "common/ceph_crypto.h" | |
28 | #include "include/str_list.h" | |
29 | #include "common/ceph_json.h" | |
30 | #include "common/code_environment.h" | |
31 | #include "common/ceph_argparse.h" | |
32 | #include "common/Finisher.h" | |
33 | #include "global/global_init.h" | |
34 | #include "rgw/rgw_common.h" | |
35 | #include "rgw/rgw_rados.h" | |
7c673cae | 36 | #include <gtest/gtest.h> |
9f95a23c | 37 | |
7c673cae FG |
38 | using namespace std; |
39 | ||
40 | #define CURL_VERBOSE 0 | |
41 | #define HTTP_RESPONSE_STR "RespCode" | |
42 | #define CEPH_CRYPTO_HMACSHA1_DIGESTSIZE 20 | |
43 | #define RGW_ADMIN_RESP_PATH "/tmp/.test_rgw_admin_resp" | |
44 | #define CEPH_UID "ceph" | |
45 | ||
46 | static string uid = CEPH_UID; | |
47 | static string display_name = "CEPH"; | |
48 | static string meta_caps = "metadata"; | |
49 | ||
50 | extern "C" int ceph_armor(char *dst, const char *dst_end, | |
51 | const char *src, const char *end); | |
52 | static void print_usage(char *exec){ | |
53 | cout << "Usage: " << exec << " <Options>\n"; | |
54 | cout << "Options:\n" | |
55 | "-g <gw-ip> - The ip address of the gateway\n" | |
56 | "-p <gw-port> - The port number of the gateway\n" | |
57 | "-c <ceph.conf> - Absolute path of ceph config file\n" | |
58 | "-rgw-admin <path/to/radosgw-admin> - radosgw-admin absolute path\n"; | |
59 | } | |
60 | ||
61 | namespace admin_meta { | |
62 | class test_helper { | |
63 | private: | |
64 | string host; | |
65 | string port; | |
66 | string creds; | |
67 | string rgw_admin_path; | |
68 | string conf_path; | |
69 | CURL *curl_inst; | |
70 | map<string, string> response; | |
71 | list<string> extra_hdrs; | |
72 | string *resp_data; | |
73 | unsigned resp_code; | |
74 | public: | |
75 | test_helper() : curl_inst(0), resp_data(NULL), resp_code(0) { | |
76 | curl_global_init(CURL_GLOBAL_ALL); | |
77 | } | |
78 | ~test_helper(){ | |
79 | curl_global_cleanup(); | |
80 | } | |
81 | int send_request(string method, string uri, | |
82 | size_t (*function)(void *,size_t,size_t,void *) = 0, | |
83 | void *ud = 0, size_t length = 0); | |
84 | int extract_input(int argc, char *argv[]); | |
85 | string& get_response(string hdr){ | |
86 | return response[hdr]; | |
87 | } | |
88 | void set_extra_header(string hdr){ | |
89 | extra_hdrs.push_back(hdr); | |
90 | } | |
91 | void set_response(char *val); | |
92 | void set_response_data(char *data, size_t len){ | |
93 | if(resp_data) delete resp_data; | |
94 | resp_data = new string(data, len); | |
95 | } | |
96 | string& get_rgw_admin_path() { | |
97 | return rgw_admin_path; | |
98 | } | |
99 | string& get_ceph_conf_path() { | |
100 | return conf_path; | |
101 | } | |
102 | void set_creds(string& c) { | |
103 | creds = c; | |
104 | } | |
105 | const string *get_response_data(){return resp_data;} | |
106 | unsigned get_resp_code(){return resp_code;} | |
107 | }; | |
108 | ||
109 | int test_helper::extract_input(int argc, char *argv[]){ | |
110 | #define ERR_CHECK_NEXT_PARAM(o) \ | |
111 | if(((int)loop + 1) >= argc)return -1; \ | |
112 | else o = argv[loop+1]; | |
113 | ||
114 | for(unsigned loop = 1;loop < (unsigned)argc; loop += 2){ | |
115 | if(strcmp(argv[loop], "-g") == 0){ | |
116 | ERR_CHECK_NEXT_PARAM(host); | |
117 | }else if(strcmp(argv[loop],"-p") == 0){ | |
118 | ERR_CHECK_NEXT_PARAM(port); | |
119 | }else if(strcmp(argv[loop], "-c") == 0){ | |
120 | ERR_CHECK_NEXT_PARAM(conf_path); | |
121 | }else if(strcmp(argv[loop], "-rgw-admin") == 0){ | |
122 | ERR_CHECK_NEXT_PARAM(rgw_admin_path); | |
123 | }else return -1; | |
124 | } | |
11fdf7f2 | 125 | if(host.empty() || rgw_admin_path.empty()) |
7c673cae FG |
126 | return -1; |
127 | return 0; | |
128 | } | |
129 | ||
130 | void test_helper::set_response(char *r){ | |
131 | string sr(r), h, v; | |
132 | size_t off = sr.find(": "); | |
133 | if(off != string::npos){ | |
134 | h.assign(sr, 0, off); | |
135 | v.assign(sr, off + 2, sr.find("\r\n") - (off+2)); | |
136 | }else{ | |
137 | /*Could be the status code*/ | |
138 | if(sr.find("HTTP/") != string::npos){ | |
139 | h.assign(HTTP_RESPONSE_STR); | |
140 | off = sr.find(" "); | |
141 | v.assign(sr, off + 1, sr.find("\r\n") - (off + 1)); | |
142 | resp_code = atoi((v.substr(0, 3)).c_str()); | |
143 | } | |
144 | } | |
145 | response[h] = v; | |
146 | } | |
147 | ||
148 | size_t write_header(void *ptr, size_t size, size_t nmemb, void *ud){ | |
149 | test_helper *h = static_cast<test_helper *>(ud); | |
150 | h->set_response((char *)ptr); | |
151 | return size*nmemb; | |
152 | } | |
153 | ||
154 | size_t write_data(void *ptr, size_t size, size_t nmemb, void *ud){ | |
155 | test_helper *h = static_cast<test_helper *>(ud); | |
156 | h->set_response_data((char *)ptr, size*nmemb); | |
157 | return size*nmemb; | |
158 | } | |
159 | ||
160 | static inline void buf_to_hex(const unsigned char *buf, int len, char *str) | |
161 | { | |
162 | int i; | |
163 | str[0] = '\0'; | |
164 | for (i = 0; i < len; i++) { | |
165 | sprintf(&str[i*2], "%02x", (int)buf[i]); | |
166 | } | |
167 | } | |
168 | ||
169 | static void calc_hmac_sha1(const char *key, int key_len, | |
170 | const char *msg, int msg_len, char *dest) | |
171 | /* destination should be CEPH_CRYPTO_HMACSHA1_DIGESTSIZE bytes long */ | |
172 | { | |
173 | ceph::crypto::HMACSHA1 hmac((const unsigned char *)key, key_len); | |
174 | hmac.Update((const unsigned char *)msg, msg_len); | |
175 | hmac.Final((unsigned char *)dest); | |
176 | ||
177 | char hex_str[(CEPH_CRYPTO_HMACSHA1_DIGESTSIZE * 2) + 1]; | |
178 | admin_meta::buf_to_hex((unsigned char *)dest, CEPH_CRYPTO_HMACSHA1_DIGESTSIZE, hex_str); | |
179 | } | |
180 | ||
11fdf7f2 | 181 | static int get_s3_auth(const string &method, string creds, const string &date, string res, string& out){ |
7c673cae FG |
182 | string aid, secret, auth_hdr; |
183 | string tmp_res; | |
184 | size_t off = creds.find(":"); | |
185 | out = ""; | |
186 | if(off != string::npos){ | |
187 | aid.assign(creds, 0, off); | |
188 | secret.assign(creds, off + 1, string::npos); | |
189 | ||
190 | /*sprintf(auth_hdr, "%s\n\n\n%s\n%s", req_type, date, res);*/ | |
191 | char hmac_sha1[CEPH_CRYPTO_HMACSHA1_DIGESTSIZE]; | |
192 | char b64[65]; /* 64 is really enough */ | |
193 | size_t off = res.find("?"); | |
194 | if(off == string::npos) | |
195 | tmp_res = res; | |
196 | else | |
197 | tmp_res.assign(res, 0, off); | |
198 | auth_hdr.append(method + string("\n\n\n") + date + string("\n") + tmp_res); | |
199 | admin_meta::calc_hmac_sha1(secret.c_str(), secret.length(), | |
200 | auth_hdr.c_str(), auth_hdr.length(), hmac_sha1); | |
201 | int ret = ceph_armor(b64, b64 + 64, hmac_sha1, | |
202 | hmac_sha1 + CEPH_CRYPTO_HMACSHA1_DIGESTSIZE); | |
203 | if (ret < 0) { | |
204 | cout << "ceph_armor failed\n"; | |
205 | return -1; | |
206 | } | |
207 | b64[ret] = 0; | |
208 | out.append(aid + string(":") + b64); | |
209 | }else return -1; | |
210 | return 0; | |
211 | } | |
212 | ||
213 | void get_date(string& d){ | |
214 | struct timeval tv; | |
215 | char date[64]; | |
216 | struct tm tm; | |
217 | char *days[] = {(char *)"Sun", (char *)"Mon", (char *)"Tue", | |
218 | (char *)"Wed", (char *)"Thu", (char *)"Fri", | |
219 | (char *)"Sat"}; | |
220 | char *months[] = {(char *)"Jan", (char *)"Feb", (char *)"Mar", | |
221 | (char *)"Apr", (char *)"May", (char *)"Jun", | |
222 | (char *)"Jul",(char *) "Aug", (char *)"Sep", | |
223 | (char *)"Oct", (char *)"Nov", (char *)"Dec"}; | |
224 | gettimeofday(&tv, NULL); | |
225 | gmtime_r(&tv.tv_sec, &tm); | |
226 | sprintf(date, "%s, %d %s %d %d:%d:%d GMT", | |
227 | days[tm.tm_wday], | |
228 | tm.tm_mday, months[tm.tm_mon], | |
229 | tm.tm_year + 1900, | |
230 | tm.tm_hour, tm.tm_min, 0 /*tm.tm_sec*/); | |
231 | d = date; | |
232 | } | |
233 | ||
234 | int test_helper::send_request(string method, string res, | |
235 | size_t (*read_function)( void *,size_t,size_t,void *), | |
236 | void *ud, | |
237 | size_t length){ | |
238 | string url; | |
239 | string auth, date; | |
240 | url.append(string("http://") + host); | |
241 | if(port.length() > 0)url.append(string(":") + port); | |
242 | url.append(res); | |
243 | curl_inst = curl_easy_init(); | |
244 | if(curl_inst){ | |
245 | curl_easy_setopt(curl_inst, CURLOPT_URL, url.c_str()); | |
246 | curl_easy_setopt(curl_inst, CURLOPT_CUSTOMREQUEST, method.c_str()); | |
247 | curl_easy_setopt(curl_inst, CURLOPT_VERBOSE, CURL_VERBOSE); | |
248 | curl_easy_setopt(curl_inst, CURLOPT_HEADERFUNCTION, admin_meta::write_header); | |
249 | curl_easy_setopt(curl_inst, CURLOPT_WRITEHEADER, (void *)this); | |
250 | curl_easy_setopt(curl_inst, CURLOPT_WRITEFUNCTION, admin_meta::write_data); | |
251 | curl_easy_setopt(curl_inst, CURLOPT_WRITEDATA, (void *)this); | |
252 | if(read_function){ | |
253 | curl_easy_setopt(curl_inst, CURLOPT_READFUNCTION, read_function); | |
254 | curl_easy_setopt(curl_inst, CURLOPT_READDATA, (void *)ud); | |
255 | curl_easy_setopt(curl_inst, CURLOPT_UPLOAD, 1L); | |
256 | curl_easy_setopt(curl_inst, CURLOPT_INFILESIZE_LARGE, (curl_off_t)length); | |
257 | } | |
258 | ||
259 | get_date(date); | |
260 | string http_date; | |
261 | http_date.append(string("Date: ") + date); | |
262 | ||
263 | string s3auth; | |
264 | if (admin_meta::get_s3_auth(method, creds, date, res, s3auth) < 0) | |
265 | return -1; | |
266 | auth.append(string("Authorization: AWS ") + s3auth); | |
267 | ||
268 | struct curl_slist *slist = NULL; | |
269 | slist = curl_slist_append(slist, auth.c_str()); | |
270 | slist = curl_slist_append(slist, http_date.c_str()); | |
271 | for(list<string>::iterator it = extra_hdrs.begin(); | |
272 | it != extra_hdrs.end(); ++it){ | |
273 | slist = curl_slist_append(slist, (*it).c_str()); | |
274 | } | |
275 | if(read_function) | |
276 | curl_slist_append(slist, "Expect:"); | |
277 | curl_easy_setopt(curl_inst, CURLOPT_HTTPHEADER, slist); | |
278 | ||
279 | response.erase(response.begin(), response.end()); | |
280 | extra_hdrs.erase(extra_hdrs.begin(), extra_hdrs.end()); | |
281 | CURLcode res = curl_easy_perform(curl_inst); | |
282 | if(res != CURLE_OK){ | |
283 | cout << "Curl perform failed for " << url << ", res: " << | |
284 | curl_easy_strerror(res) << "\n"; | |
285 | return -1; | |
286 | } | |
287 | curl_slist_free_all(slist); | |
288 | } | |
289 | curl_easy_cleanup(curl_inst); | |
290 | return 0; | |
291 | } | |
292 | }; | |
293 | ||
294 | admin_meta::test_helper *g_test; | |
295 | Finisher *finisher; | |
296 | ||
297 | int run_rgw_admin(string& cmd, string& resp) { | |
298 | pid_t pid; | |
299 | pid = fork(); | |
300 | if (pid == 0) { | |
301 | /* child */ | |
302 | list<string> l; | |
303 | get_str_list(cmd, " \t", l); | |
304 | char *argv[l.size()]; | |
305 | unsigned loop = 1; | |
306 | ||
307 | argv[0] = (char *)"radosgw-admin"; | |
308 | for (list<string>::iterator it = l.begin(); | |
309 | it != l.end(); ++it) { | |
310 | argv[loop++] = (char *)(*it).c_str(); | |
311 | } | |
312 | argv[loop] = NULL; | |
313 | if (!freopen(RGW_ADMIN_RESP_PATH, "w+", stdout)) { | |
314 | cout << "Unable to open stdout file" << std::endl; | |
315 | } | |
316 | execv((g_test->get_rgw_admin_path()).c_str(), argv); | |
317 | } else if (pid > 0) { | |
318 | int status; | |
319 | waitpid(pid, &status, 0); | |
320 | if (WIFEXITED(status)) { | |
321 | if(WEXITSTATUS(status) != 0) { | |
322 | cout << "Child exited with status " << WEXITSTATUS(status) << std::endl; | |
323 | return -1; | |
324 | } | |
325 | } | |
326 | ifstream in; | |
327 | struct stat st; | |
328 | ||
329 | if (stat(RGW_ADMIN_RESP_PATH, &st) < 0) { | |
330 | cout << "Error stating the admin response file, errno " << errno << std::endl; | |
331 | return -1; | |
332 | } else { | |
333 | char *data = (char *)malloc(st.st_size + 1); | |
334 | in.open(RGW_ADMIN_RESP_PATH); | |
335 | in.read(data, st.st_size); | |
336 | in.close(); | |
337 | data[st.st_size] = 0; | |
338 | resp = data; | |
339 | free(data); | |
340 | unlink(RGW_ADMIN_RESP_PATH); | |
341 | /* cout << "radosgw-admin " << cmd << ": " << resp << std::endl;*/ | |
342 | } | |
343 | } else | |
344 | return -1; | |
345 | return 0; | |
346 | } | |
347 | ||
348 | int get_creds(string& json, string& creds) { | |
349 | JSONParser parser; | |
350 | if(!parser.parse(json.c_str(), json.length())) { | |
351 | cout << "Error parsing create user response" << std::endl; | |
352 | return -1; | |
353 | } | |
354 | ||
355 | RGWUserInfo info; | |
356 | decode_json_obj(info, &parser); | |
357 | creds = ""; | |
358 | for(map<string, RGWAccessKey>::iterator it = info.access_keys.begin(); | |
359 | it != info.access_keys.end(); ++it) { | |
360 | RGWAccessKey _k = it->second; | |
361 | /*cout << "accesskeys [ " << it->first << " ] = " << | |
362 | "{ " << _k.id << ", " << _k.key << ", " << _k.subuser << "}" << std::endl;*/ | |
363 | creds.append(it->first + string(":") + _k.key); | |
364 | break; | |
365 | } | |
366 | return 0; | |
367 | } | |
368 | ||
369 | int user_create(string& uid, string& display_name, bool set_creds = true) { | |
370 | stringstream ss; | |
371 | string creds; | |
372 | ss << "-c " << g_test->get_ceph_conf_path() << " user create --uid=" << uid | |
373 | << " --display-name=" << display_name; | |
374 | ||
375 | string out; | |
376 | string cmd = ss.str(); | |
377 | if(run_rgw_admin(cmd, out) != 0) { | |
378 | cout << "Error creating user" << std::endl; | |
379 | return -1; | |
380 | } | |
381 | get_creds(out, creds); | |
382 | if(set_creds) | |
383 | g_test->set_creds(creds); | |
384 | return 0; | |
385 | } | |
386 | ||
387 | int user_info(string& uid, string& display_name, RGWUserInfo& uinfo) { | |
388 | stringstream ss; | |
389 | ss << "-c " << g_test->get_ceph_conf_path() << " user info --uid=" << uid | |
390 | << " --display-name=" << display_name; | |
391 | ||
392 | string out; | |
393 | string cmd = ss.str(); | |
394 | if(run_rgw_admin(cmd, out) != 0) { | |
395 | cout << "Error reading user information" << std::endl; | |
396 | return -1; | |
397 | } | |
398 | JSONParser parser; | |
399 | if(!parser.parse(out.c_str(), out.length())) { | |
400 | cout << "Error parsing create user response" << std::endl; | |
401 | return -1; | |
402 | } | |
403 | decode_json_obj(uinfo, &parser); | |
404 | return 0; | |
405 | } | |
406 | ||
407 | int user_rm(string& uid, string& display_name) { | |
408 | stringstream ss; | |
409 | ss << "-c " << g_test->get_ceph_conf_path() << " user rm --uid=" << uid | |
410 | << " --display-name=" << display_name; | |
411 | ||
412 | string out; | |
413 | string cmd = ss.str(); | |
414 | if(run_rgw_admin(cmd, out) != 0) { | |
415 | cout << "Error removing user" << std::endl; | |
416 | return -1; | |
417 | } | |
418 | return 0; | |
419 | } | |
420 | ||
421 | int meta_caps_add(const char *perm) { | |
422 | stringstream ss; | |
423 | ||
424 | ss << "-c " << g_test->get_ceph_conf_path() << " caps add --caps=" << | |
425 | meta_caps << "=" << perm << " --uid=" << uid; | |
426 | string out; | |
427 | string cmd = ss.str(); | |
428 | if(run_rgw_admin(cmd, out) != 0) { | |
429 | cout << "Error creating user" << std::endl; | |
430 | return -1; | |
431 | } | |
432 | return 0; | |
433 | } | |
434 | ||
435 | int meta_caps_rm(const char *perm) { | |
436 | stringstream ss; | |
437 | ||
438 | ss << "-c " << g_test->get_ceph_conf_path() << " caps rm --caps=" << | |
439 | meta_caps << "=" << perm << " --uid=" << uid; | |
440 | string out; | |
441 | string cmd = ss.str(); | |
442 | if(run_rgw_admin(cmd, out) != 0) { | |
443 | cout << "Error creating user" << std::endl; | |
444 | return -1; | |
445 | } | |
446 | return 0; | |
447 | } | |
448 | ||
449 | int compare_access_keys(RGWAccessKey& k1, RGWAccessKey& k2) { | |
450 | if (k1.id.compare(k2.id) != 0) | |
451 | return -1; | |
452 | if (k1.key.compare(k2.key) != 0) | |
453 | return -1; | |
454 | if (k1.subuser.compare(k2.subuser) != 0) | |
455 | return -1; | |
456 | ||
457 | return 0; | |
458 | } | |
459 | ||
460 | int compare_user_info(RGWUserInfo& i1, RGWUserInfo& i2) { | |
461 | int rv; | |
462 | ||
463 | if ((rv = i1.user_id.compare(i2.user_id)) != 0) | |
464 | return rv; | |
465 | if ((rv = i1.display_name.compare(i2.display_name)) != 0) | |
466 | return rv; | |
467 | if ((rv = i1.user_email.compare(i2.user_email)) != 0) | |
468 | return rv; | |
469 | if (i1.access_keys.size() != i2.access_keys.size()) | |
470 | return -1; | |
471 | for (map<string, RGWAccessKey>::iterator it = i1.access_keys.begin(); | |
472 | it != i1.access_keys.end(); ++it) { | |
473 | RGWAccessKey k1, k2; | |
474 | k1 = it->second; | |
475 | if (i2.access_keys.count(it->first) == 0) | |
476 | return -1; | |
477 | k2 = i2.access_keys[it->first]; | |
478 | if (compare_access_keys(k1, k2) != 0) | |
479 | return -1; | |
480 | } | |
481 | if (i1.swift_keys.size() != i2.swift_keys.size()) | |
482 | return -1; | |
483 | for (map<string, RGWAccessKey>::iterator it = i1.swift_keys.begin(); | |
484 | it != i1.swift_keys.end(); ++it) { | |
485 | RGWAccessKey k1, k2; | |
486 | k1 = it->second; | |
487 | if (i2.swift_keys.count(it->first) == 0) | |
488 | return -1; | |
489 | k2 = i2.swift_keys[it->first]; | |
490 | if (compare_access_keys(k1, k2) != 0) | |
491 | return -1; | |
492 | } | |
493 | if (i1.subusers.size() != i2.subusers.size()) | |
494 | return -1; | |
495 | for (map<string, RGWSubUser>::iterator it = i1.subusers.begin(); | |
496 | it != i1.subusers.end(); ++it) { | |
497 | RGWSubUser k1, k2; | |
498 | k1 = it->second; | |
499 | if (!i2.subusers.count(it->first)) | |
500 | return -1; | |
501 | k2 = i2.subusers[it->first]; | |
502 | if (k1.name.compare(k2.name) != 0) | |
503 | return -1; | |
504 | if (k1.perm_mask != k2.perm_mask) | |
505 | return -1; | |
506 | } | |
507 | if (i1.suspended != i2.suspended) | |
508 | return -1; | |
509 | if (i1.max_buckets != i2.max_buckets) | |
510 | return -1; | |
511 | uint32_t p1, p2; | |
512 | p1 = p2 = RGW_CAP_ALL; | |
513 | if (i1.caps.check_cap(meta_caps, p1) != 0) | |
514 | return -1; | |
515 | if (i2.caps.check_cap(meta_caps, p2) != 0) | |
516 | return -1; | |
517 | return 0; | |
518 | } | |
519 | ||
520 | size_t read_dummy_post(void *ptr, size_t s, size_t n, void *ud) { | |
521 | int dummy = 0; | |
522 | memcpy(ptr, &dummy, sizeof(dummy)); | |
523 | return sizeof(dummy); | |
524 | } | |
525 | ||
526 | ||
527 | int parse_json_resp(JSONParser &parser) { | |
528 | string *resp; | |
529 | resp = (string *)g_test->get_response_data(); | |
530 | if(!resp) | |
531 | return -1; | |
532 | if(!parser.parse(resp->c_str(), resp->length())) { | |
533 | cout << "Error parsing create user response" << std::endl; | |
534 | return -1; | |
535 | } | |
536 | return 0; | |
537 | } | |
538 | ||
539 | size_t meta_read_json(void *ptr, size_t s, size_t n, void *ud){ | |
540 | stringstream *ss = (stringstream *)ud; | |
541 | size_t len = ss->str().length(); | |
542 | if(s*n < len){ | |
543 | cout << "Cannot copy json data, as len is not enough\n"; | |
544 | return 0; | |
545 | } | |
546 | memcpy(ptr, (void *)ss->str().c_str(), len); | |
547 | return len; | |
548 | } | |
549 | ||
550 | TEST(TestRGWAdmin, meta_list){ | |
551 | JSONParser parser; | |
552 | bool found = false; | |
553 | const char *perm = "*"; | |
554 | ||
555 | ASSERT_EQ(0, user_create(uid, display_name)); | |
556 | ASSERT_EQ(0, meta_caps_add(perm)); | |
557 | ||
558 | /*Check the sections*/ | |
559 | g_test->send_request(string("GET"), string("/admin/metadata/")); | |
560 | EXPECT_EQ(200U, g_test->get_resp_code()); | |
561 | ||
562 | ASSERT_TRUE(parse_json_resp(parser) == 0); | |
563 | EXPECT_TRUE(parser.is_array()); | |
564 | ||
565 | vector<string> l; | |
566 | l = parser.get_array_elements(); | |
567 | for(vector<string>::iterator it = l.begin(); | |
568 | it != l.end(); ++it) { | |
569 | if((*it).compare("\"user\"") == 0) { | |
570 | found = true; | |
571 | break; | |
572 | } | |
573 | } | |
574 | EXPECT_TRUE(found); | |
575 | ||
576 | /*Check with a wrong section*/ | |
577 | g_test->send_request(string("GET"), string("/admin/metadata/users")); | |
578 | EXPECT_EQ(404U, g_test->get_resp_code()); | |
579 | ||
580 | /*Check the list of keys*/ | |
581 | g_test->send_request(string("GET"), string("/admin/metadata/user")); | |
582 | EXPECT_EQ(200U, g_test->get_resp_code()); | |
583 | ||
584 | ASSERT_TRUE(parse_json_resp(parser) == 0); | |
585 | EXPECT_TRUE(parser.is_array()); | |
586 | ||
587 | l = parser.get_array_elements(); | |
588 | EXPECT_EQ(1U, l.size()); | |
589 | for(vector<string>::iterator it = l.begin(); | |
590 | it != l.end(); ++it) { | |
591 | if((*it).compare(string("\"") + uid + string("\"")) == 0) { | |
592 | found = true; | |
593 | break; | |
594 | } | |
595 | } | |
596 | EXPECT_TRUE(found); | |
597 | ||
598 | /*Check with second user*/ | |
599 | string uid2 = "ceph1", display_name2 = "CEPH1"; | |
600 | ASSERT_EQ(0, user_create(uid2, display_name2, false)); | |
601 | /*Check the list of keys*/ | |
602 | g_test->send_request(string("GET"), string("/admin/metadata/user")); | |
603 | EXPECT_EQ(200U, g_test->get_resp_code()); | |
604 | ||
605 | ASSERT_TRUE(parse_json_resp(parser) == 0); | |
606 | EXPECT_TRUE(parser.is_array()); | |
607 | ||
608 | l = parser.get_array_elements(); | |
609 | EXPECT_EQ(2U, l.size()); | |
610 | bool found2 = false; | |
611 | for(vector<string>::iterator it = l.begin(); | |
612 | it != l.end(); ++it) { | |
613 | if((*it).compare(string("\"") + uid + string("\"")) == 0) { | |
614 | found = true; | |
615 | } | |
616 | if((*it).compare(string("\"") + uid2 + string("\"")) == 0) { | |
617 | found2 = true; | |
618 | } | |
619 | } | |
620 | EXPECT_TRUE(found && found2); | |
621 | ASSERT_EQ(0, user_rm(uid2, display_name2)); | |
622 | ||
623 | /*Remove the metadata caps*/ | |
624 | int rv = meta_caps_rm(perm); | |
625 | EXPECT_EQ(0, rv); | |
626 | ||
627 | if(rv == 0) { | |
628 | g_test->send_request(string("GET"), string("/admin/metadata/")); | |
629 | EXPECT_EQ(403U, g_test->get_resp_code()); | |
630 | ||
631 | g_test->send_request(string("GET"), string("/admin/metadata/user")); | |
632 | EXPECT_EQ(403U, g_test->get_resp_code()); | |
633 | } | |
634 | ASSERT_EQ(0, user_rm(uid, display_name)); | |
635 | } | |
636 | ||
637 | TEST(TestRGWAdmin, meta_get){ | |
638 | JSONParser parser; | |
639 | const char *perm = "*"; | |
640 | RGWUserInfo info; | |
641 | ||
642 | ASSERT_EQ(0, user_create(uid, display_name)); | |
643 | ASSERT_EQ(0, meta_caps_add(perm)); | |
644 | ||
645 | ASSERT_EQ(0, user_info(uid, display_name, info)); | |
646 | ||
647 | g_test->send_request(string("GET"), string("/admin/metadata/user?key=test")); | |
648 | EXPECT_EQ(404U, g_test->get_resp_code()); | |
649 | ||
650 | g_test->send_request(string("GET"), (string("/admin/metadata/user?key=") + uid)); | |
651 | EXPECT_EQ(200U, g_test->get_resp_code()); | |
652 | ||
653 | ASSERT_TRUE(parse_json_resp(parser) == 0); | |
654 | RGWObjVersionTracker objv_tracker; | |
655 | string metadata_key; | |
656 | ||
657 | obj_version *objv = &objv_tracker.read_version; | |
658 | ||
659 | JSONDecoder::decode_json("key", metadata_key, &parser); | |
660 | JSONDecoder::decode_json("ver", *objv, &parser); | |
661 | JSONObj *jo = parser.find_obj("data"); | |
662 | ASSERT_TRUE(jo); | |
663 | string exp_meta_key = "user:"; | |
664 | exp_meta_key.append(uid); | |
665 | EXPECT_TRUE(metadata_key.compare(exp_meta_key) == 0); | |
666 | ||
667 | RGWUserInfo obt_info; | |
668 | decode_json_obj(obt_info, jo); | |
669 | ||
670 | EXPECT_TRUE(compare_user_info(info, obt_info) == 0); | |
671 | ||
672 | /*Make a modification and check if its reflected*/ | |
673 | ASSERT_EQ(0, meta_caps_rm(perm)); | |
674 | perm = "read"; | |
675 | ASSERT_EQ(0, meta_caps_add(perm)); | |
676 | ||
677 | JSONParser parser1; | |
678 | g_test->send_request(string("GET"), (string("/admin/metadata/user?key=") + uid)); | |
679 | EXPECT_EQ(200U, g_test->get_resp_code()); | |
680 | ||
681 | ASSERT_TRUE(parse_json_resp(parser1) == 0); | |
682 | ||
683 | RGWObjVersionTracker objv_tracker1; | |
684 | obj_version *objv1 = &objv_tracker1.read_version; | |
685 | ||
686 | JSONDecoder::decode_json("key", metadata_key, &parser1); | |
687 | JSONDecoder::decode_json("ver", *objv1, &parser1); | |
688 | jo = parser1.find_obj("data"); | |
689 | ASSERT_TRUE(jo); | |
690 | ||
691 | decode_json_obj(obt_info, jo); | |
692 | uint32_t p1, p2; | |
693 | p1 = RGW_CAP_ALL; | |
694 | p2 = RGW_CAP_READ; | |
695 | EXPECT_TRUE (info.caps.check_cap(meta_caps, p1) == 0); | |
696 | EXPECT_TRUE (obt_info.caps.check_cap(meta_caps, p2) == 0); | |
697 | p2 = RGW_CAP_WRITE; | |
698 | EXPECT_TRUE (obt_info.caps.check_cap(meta_caps, p2) != 0); | |
699 | ||
700 | /*Version and tag infromation*/ | |
701 | EXPECT_TRUE(objv1->ver > objv->ver); | |
702 | EXPECT_EQ(objv1->tag, objv->tag); | |
703 | ||
704 | int rv = meta_caps_rm(perm); | |
705 | EXPECT_EQ(0, rv); | |
706 | ||
707 | if(rv == 0) { | |
708 | g_test->send_request(string("GET"), (string("/admin/metadata/user?key=") + uid)); | |
709 | EXPECT_EQ(403U, g_test->get_resp_code()); | |
710 | } | |
711 | ASSERT_EQ(0, user_rm(uid, display_name)); | |
712 | } | |
713 | ||
714 | TEST(TestRGWAdmin, meta_put){ | |
715 | JSONParser parser; | |
716 | const char *perm = "*"; | |
717 | RGWUserInfo info; | |
718 | ||
719 | ASSERT_EQ(0, user_create(uid, display_name)); | |
720 | ASSERT_EQ(0, meta_caps_add(perm)); | |
721 | ||
722 | g_test->send_request(string("GET"), (string("/admin/metadata/user?key=") + uid)); | |
723 | EXPECT_EQ(200U, g_test->get_resp_code()); | |
724 | ||
725 | ASSERT_TRUE(parse_json_resp(parser) == 0); | |
726 | RGWObjVersionTracker objv_tracker; | |
727 | string metadata_key; | |
728 | ||
729 | obj_version *objv = &objv_tracker.read_version; | |
730 | ||
731 | JSONDecoder::decode_json("key", metadata_key, &parser); | |
732 | JSONDecoder::decode_json("ver", *objv, &parser); | |
733 | JSONObj *jo = parser.find_obj("data"); | |
734 | ASSERT_TRUE(jo); | |
735 | string exp_meta_key = "user:"; | |
736 | exp_meta_key.append(uid); | |
737 | EXPECT_TRUE(metadata_key.compare(exp_meta_key) == 0); | |
738 | ||
739 | RGWUserInfo obt_info; | |
740 | decode_json_obj(obt_info, jo); | |
741 | ||
742 | /*Change the cap and PUT */ | |
743 | RGWUserCaps caps; | |
744 | string new_cap; | |
745 | Formatter *f = new JSONFormatter(); | |
746 | ||
747 | new_cap = meta_caps + string("=write"); | |
748 | caps.add_from_string(new_cap); | |
749 | obt_info.caps = caps; | |
750 | f->open_object_section("metadata_info"); | |
751 | ::encode_json("key", metadata_key, f); | |
752 | ::encode_json("ver", *objv, f); | |
753 | ::encode_json("data", obt_info, f); | |
754 | f->close_section(); | |
755 | std::stringstream ss; | |
756 | f->flush(ss); | |
757 | ||
758 | g_test->send_request(string("PUT"), (string("/admin/metadata/user?key=") + uid), | |
759 | meta_read_json, | |
760 | (void *)&ss, ss.str().length()); | |
761 | EXPECT_EQ(200U, g_test->get_resp_code()); | |
762 | ||
763 | ASSERT_EQ(0, user_info(uid, display_name, obt_info)); | |
764 | uint32_t cp; | |
765 | cp = RGW_CAP_WRITE; | |
766 | EXPECT_TRUE (obt_info.caps.check_cap(meta_caps, cp) == 0); | |
767 | cp = RGW_CAP_READ; | |
768 | EXPECT_TRUE (obt_info.caps.check_cap(meta_caps, cp) != 0); | |
769 | ||
770 | int rv = meta_caps_rm("write"); | |
771 | EXPECT_EQ(0, rv); | |
772 | if(rv == 0) { | |
773 | g_test->send_request(string("PUT"), (string("/admin/metadata/user?key=") + uid)); | |
774 | EXPECT_EQ(403U, g_test->get_resp_code()); | |
775 | } | |
776 | ASSERT_EQ(0, user_rm(uid, display_name)); | |
777 | } | |
778 | ||
779 | TEST(TestRGWAdmin, meta_lock_unlock) { | |
780 | const char *perm = "*"; | |
781 | string rest_req; | |
782 | ||
783 | ASSERT_EQ(0, user_create(uid, display_name)); | |
784 | ASSERT_EQ(0, meta_caps_add(perm)); | |
785 | ||
786 | rest_req = "/admin/metadata/user?key=" CEPH_UID "&lock&length=3"; | |
787 | g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); | |
788 | EXPECT_EQ(400U, g_test->get_resp_code()); /*Bad request*/ | |
789 | ||
790 | rest_req = "/admin/metadata/user?lock&length=3&lock_id=ceph"; | |
791 | g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); | |
792 | EXPECT_EQ(400U, g_test->get_resp_code()); /*Bad request*/ | |
793 | ||
794 | rest_req = "/admin/metadata/user?key=" CEPH_UID "&unlock"; | |
795 | g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); | |
796 | EXPECT_EQ(400U, g_test->get_resp_code()); /*Bad request*/ | |
797 | ||
798 | rest_req = "/admin/metadata/user?unlock&lock_id=ceph"; | |
799 | g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); | |
800 | EXPECT_EQ(400U, g_test->get_resp_code()); /*Bad request*/ | |
801 | ||
802 | rest_req = "/admin/metadata/user?key=" CEPH_UID "&lock&length=3&lock_id=ceph"; | |
803 | g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); | |
804 | EXPECT_EQ(200U, g_test->get_resp_code()); | |
805 | ||
806 | rest_req = "/admin/metadata/user?key=" CEPH_UID "&unlock&lock_id=ceph"; | |
807 | g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); | |
808 | EXPECT_EQ(200U, g_test->get_resp_code()); | |
809 | ||
810 | rest_req = "/admin/metadata/user?key=" CEPH_UID "&lock&length=3&lock_id=ceph1"; | |
811 | g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); | |
812 | EXPECT_EQ(200U, g_test->get_resp_code()); | |
813 | ||
814 | rest_req = "/admin/metadata/user?key=" CEPH_UID "&unlock&lock_id=ceph1"; | |
815 | g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); | |
816 | EXPECT_EQ(200U, g_test->get_resp_code()); | |
817 | ||
818 | rest_req = "/admin/metadata/user?key=" CEPH_UID "&lock&length=3&lock_id=ceph"; | |
819 | g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); | |
820 | EXPECT_EQ(200U, g_test->get_resp_code()); | |
821 | utime_t sleep_time(3, 0); | |
822 | ||
823 | rest_req = "/admin/metadata/user?key=" CEPH_UID "&lock&length=3&lock_id=ceph1"; | |
824 | g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); | |
825 | EXPECT_EQ(500U, g_test->get_resp_code()); | |
826 | ||
827 | rest_req = "/admin/metadata/user?key=" CEPH_UID "&lock&length=3&lock_id=ceph"; | |
828 | g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); | |
829 | EXPECT_EQ(409U, g_test->get_resp_code()); | |
830 | sleep_time.sleep(); | |
831 | ||
832 | rest_req = "/admin/metadata/user?key=" CEPH_UID "&lock&length=3&lock_id=ceph1"; | |
833 | g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); | |
834 | EXPECT_EQ(200U, g_test->get_resp_code()); | |
835 | ||
836 | rest_req = "/admin/metadata/user?key=" CEPH_UID "&unlock&lock_id=ceph1"; | |
837 | g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); | |
838 | EXPECT_EQ(200U, g_test->get_resp_code()); | |
839 | ||
840 | ASSERT_EQ(0, meta_caps_rm(perm)); | |
841 | perm = "read"; | |
842 | ASSERT_EQ(0, meta_caps_add(perm)); | |
843 | rest_req = "/admin/metadata/user?key=" CEPH_UID "&lock&length=3&lock_id=ceph"; | |
844 | g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); | |
845 | EXPECT_EQ(403U, g_test->get_resp_code()); | |
846 | ||
847 | rest_req = "/admin/metadata/user?key=" CEPH_UID "&unlock&lock_id=ceph"; | |
848 | g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); | |
849 | EXPECT_EQ(403U, g_test->get_resp_code()); | |
850 | ||
851 | ASSERT_EQ(0, meta_caps_rm(perm)); | |
852 | perm = "write"; | |
853 | ASSERT_EQ(0, meta_caps_add(perm)); | |
854 | rest_req = "/admin/metadata/user?key=" CEPH_UID "&lock&length=3&lock_id=ceph"; | |
855 | g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); | |
856 | EXPECT_EQ(200U, g_test->get_resp_code()); | |
857 | ||
858 | rest_req = "/admin/metadata/user?key=" CEPH_UID "&unlock&lock_id=ceph"; | |
859 | g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); | |
860 | EXPECT_EQ(200U, g_test->get_resp_code()); | |
861 | ||
862 | ASSERT_EQ(0, meta_caps_rm(perm)); | |
863 | rest_req = "/admin/metadata/user?key=" CEPH_UID "&lock&length=3&lock_id=ceph"; | |
864 | g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); | |
865 | EXPECT_EQ(403U, g_test->get_resp_code()); | |
866 | ||
867 | rest_req = "/admin/metadata/user?key=" CEPH_UID "&unlock&lock_id=ceph"; | |
868 | g_test->send_request(string("POST"), rest_req, read_dummy_post, NULL, sizeof(int)); | |
869 | EXPECT_EQ(403U, g_test->get_resp_code()); | |
870 | ||
871 | ASSERT_EQ(0, user_rm(uid, display_name)); | |
872 | } | |
873 | ||
874 | TEST(TestRGWAdmin, meta_delete){ | |
875 | JSONParser parser; | |
876 | const char *perm = "*"; | |
877 | RGWUserInfo info; | |
878 | ||
879 | ASSERT_EQ(0, user_create(uid, display_name)); | |
880 | ASSERT_EQ(0, meta_caps_add(perm)); | |
881 | ||
882 | g_test->send_request(string("DELETE"), (string("/admin/metadata/user?key=") + uid)); | |
883 | EXPECT_EQ(200U, g_test->get_resp_code()); | |
884 | ||
885 | ASSERT_TRUE(user_info(uid, display_name, info) != 0); | |
886 | ||
887 | ASSERT_EQ(0, user_create(uid, display_name)); | |
888 | perm = "read"; | |
889 | ASSERT_EQ(0, meta_caps_add(perm)); | |
890 | ||
891 | g_test->send_request(string("DELETE"), (string("/admin/metadata/user?key=") + uid)); | |
892 | EXPECT_EQ(403U, g_test->get_resp_code()); | |
893 | ASSERT_EQ(0, user_rm(uid, display_name)); | |
894 | } | |
895 | ||
896 | int main(int argc, char *argv[]){ | |
897 | vector<const char*> args; | |
898 | argv_to_vec(argc, (const char **)argv, args); | |
899 | ||
900 | auto cct = global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT, | |
11fdf7f2 TL |
901 | CODE_ENVIRONMENT_UTILITY, |
902 | CINIT_FLAG_NO_DEFAULT_CONFIG_FILE); | |
7c673cae FG |
903 | common_init_finish(g_ceph_context); |
904 | g_test = new admin_meta::test_helper(); | |
905 | finisher = new Finisher(g_ceph_context); | |
906 | #ifdef GTEST | |
907 | ::testing::InitGoogleTest(&argc, argv); | |
908 | #endif | |
909 | finisher->start(); | |
910 | ||
911 | if(g_test->extract_input(argc, argv) < 0){ | |
912 | print_usage(argv[0]); | |
913 | return -1; | |
914 | } | |
915 | #ifdef GTEST | |
916 | int r = RUN_ALL_TESTS(); | |
917 | if (r >= 0) { | |
918 | cout << "There are no failures in the test case\n"; | |
919 | } else { | |
920 | cout << "There are some failures\n"; | |
921 | } | |
922 | #endif | |
923 | finisher->stop(); | |
924 | return 0; | |
925 | } |