Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / rgw / rgw_rest_metadata.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) 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 "include/page.h"
15
16 #include "rgw_rest.h"
17 #include "rgw_op.h"
18 #include "rgw_rest_s3.h"
19 #include "rgw_rest_metadata.h"
20 #include "rgw_client_io.h"
21 #include "common/errno.h"
22 #include "common/strtol.h"
23 #include "include/assert.h"
24
25 #define dout_context g_ceph_context
26 #define dout_subsys ceph_subsys_rgw
27
28 const string RGWOp_Metadata_Get::name() {
29   return "get_metadata";
30 }
31
32 static inline void frame_metadata_key(req_state *s, string& out) {
33   bool exists;
34   string key = s->info.args.get("key", &exists);
35
36   string section;
37   if (!s->init_state.url_bucket.empty()) {
38     section = s->init_state.url_bucket;
39   } else {
40     section = key;
41     key.clear();
42   }
43
44   out = section;
45
46   if (!key.empty()) {
47     out += string(":") + key;
48   }
49 }
50
51 void RGWOp_Metadata_Get::execute() {
52   string metadata_key;
53
54   frame_metadata_key(s, metadata_key);
55
56   /* Get keys */
57   http_ret = store->meta_mgr->get(metadata_key, s->formatter);
58   if (http_ret < 0) {
59     dout(5) << "ERROR: can't get key: " << cpp_strerror(http_ret) << dendl;
60     return;
61   }
62
63   http_ret = 0;
64 }
65
66 const string RGWOp_Metadata_List::name() {
67   return "list_metadata";
68 }
69
70 void RGWOp_Metadata_List::execute() {
71   string marker = s->info.args.get("marker");
72   bool max_entries_specified;
73   string max_entries_str = s->info.args.get("max-entries", &max_entries_specified);
74
75   bool extended_response = (max_entries_specified); /* for backward compatibility, if max-entries is not specified
76                                                     we will send the old response format */
77   uint64_t max_entries = 0;
78
79   if (max_entries_specified) {
80     string err;
81     max_entries = (unsigned)strict_strtol(max_entries_str.c_str(), 10, &err);
82     if (!err.empty()) {
83       dout(5) << "Error parsing max-entries " << max_entries_str << dendl;
84       http_ret = -EINVAL;
85       return;
86     }
87   }
88
89   string metadata_key;
90
91   frame_metadata_key(s, metadata_key);
92   /* List keys */
93   void *handle;
94   int max = 1000;
95
96   http_ret = store->meta_mgr->list_keys_init(metadata_key, marker, &handle);
97   if (http_ret < 0) {
98     dout(5) << "ERROR: can't get key: " << cpp_strerror(http_ret) << dendl;
99     return;
100   }
101
102   bool truncated;
103   uint64_t count = 0;
104
105   if (extended_response) {
106     s->formatter->open_object_section("result");
107   }
108
109   s->formatter->open_array_section("keys");
110
111   uint64_t left;
112   do {
113     list<string> keys;
114     left = (max_entries_specified ? max_entries - count : max);
115     http_ret = store->meta_mgr->list_keys_next(handle, left, keys, &truncated);
116     if (http_ret < 0) {
117       dout(5) << "ERROR: lists_keys_next(): " << cpp_strerror(http_ret)
118               << dendl;
119       return;
120     }
121
122     for (list<string>::iterator iter = keys.begin(); iter != keys.end();
123          ++iter) {
124       s->formatter->dump_string("key", *iter);
125       ++count;
126     }
127
128   } while (truncated && left > 0);
129
130   s->formatter->close_section();
131
132   if (extended_response) {
133     encode_json("truncated", truncated, s->formatter);
134     encode_json("count", count, s->formatter);
135     if (truncated) {
136       encode_json("marker", store->meta_mgr->get_marker(handle), s->formatter);
137     }
138     s->formatter->close_section();
139   }
140   store->meta_mgr->list_keys_complete(handle);
141
142   http_ret = 0;
143 }
144
145 int RGWOp_Metadata_Put::get_data(bufferlist& bl) {
146   size_t cl = 0;
147   char *data;
148   int read_len;
149
150   if (s->length)
151     cl = atoll(s->length);
152   if (cl) {
153     data = (char *)malloc(cl + 1);
154     if (!data) {
155        return -ENOMEM;
156     }
157     read_len = recv_body(s, data, cl);
158     if (cl != (size_t)read_len) {
159       dout(10) << "recv_body incomplete" << dendl;
160     }
161     if (read_len < 0) {
162       free(data);
163       return read_len;
164     }
165     bl.append(data, read_len);
166   } else {
167     int chunk_size = CEPH_PAGE_SIZE;
168     const char *enc = s->info.env->get("HTTP_TRANSFER_ENCODING");
169     if (!enc || strcmp(enc, "chunked")) {
170       return -ERR_LENGTH_REQUIRED;
171     }
172     data = (char *)malloc(chunk_size);
173     if (!data) {
174       return -ENOMEM;
175     }
176     do {
177       read_len = recv_body(s, data, chunk_size);
178       if (read_len < 0) {
179         free(data);
180         return read_len;
181       }
182       bl.append(data, read_len);
183     } while (read_len == chunk_size);
184   }
185
186   free(data);
187   return 0;
188 }
189
190 void RGWOp_Metadata_Put::execute() {
191   bufferlist bl;
192   string metadata_key;
193
194   http_ret = get_data(bl);
195   if (http_ret < 0) {
196     return;
197   }
198
199   http_ret = do_aws4_auth_completion();
200   if (http_ret < 0) {
201     return;
202   }
203   
204   frame_metadata_key(s, metadata_key);
205
206   RGWMetadataHandler::sync_type_t sync_type = RGWMetadataHandler::APPLY_ALWAYS;
207
208   bool mode_exists = false;
209   string mode_string = s->info.args.get("update-type", &mode_exists);
210   if (mode_exists) {
211     bool parsed = RGWMetadataHandler::string_to_sync_type(mode_string,
212                                                           sync_type);
213     if (!parsed) {
214       http_ret = -EINVAL;
215       return;
216     }
217   }
218
219   http_ret = store->meta_mgr->put(metadata_key, bl, sync_type,
220                                   &ondisk_version);
221   if (http_ret < 0) {
222     dout(5) << "ERROR: can't put key: " << cpp_strerror(http_ret) << dendl;
223     return;
224   }
225   // translate internal codes into return header
226   if (http_ret == STATUS_NO_APPLY)
227     update_status = "skipped";
228   else if (http_ret == STATUS_APPLIED)
229     update_status = "applied";
230 }
231
232 void RGWOp_Metadata_Put::send_response() {
233   int http_return_code = http_ret;
234   if ((http_ret == STATUS_NO_APPLY) || (http_ret == STATUS_APPLIED))
235     http_return_code = STATUS_NO_CONTENT;
236   set_req_state_err(s, http_return_code);
237   dump_errno(s);
238   stringstream ver_stream;
239   ver_stream << "ver:" << ondisk_version.ver
240              <<",tag:" << ondisk_version.tag;
241   dump_header_if_nonempty(s, "RGWX_UPDATE_STATUS", update_status);
242   dump_header_if_nonempty(s, "RGWX_UPDATE_VERSION", ver_stream.str());
243   end_header(s);
244 }
245
246 void RGWOp_Metadata_Delete::execute() {
247   string metadata_key;
248
249   frame_metadata_key(s, metadata_key);
250   http_ret = store->meta_mgr->remove(metadata_key);
251   if (http_ret < 0) {
252     dout(5) << "ERROR: can't remove key: " << cpp_strerror(http_ret) << dendl;
253     return;
254   }
255   http_ret = 0;
256 }
257
258 void RGWOp_Metadata_Lock::execute() {
259   string duration_str, lock_id;
260   string metadata_key;
261
262   frame_metadata_key(s, metadata_key);
263
264   http_ret = 0;
265
266   duration_str = s->info.args.get("length");
267   lock_id      = s->info.args.get("lock_id");
268
269   if ((!s->info.args.exists("key")) ||
270       (duration_str.empty()) ||
271       lock_id.empty()) {
272     dout(5) << "Error invalid parameter list" << dendl;
273     http_ret = -EINVAL;
274     return;
275   }
276
277   int dur;
278   string err;
279
280   dur = strict_strtol(duration_str.c_str(), 10, &err);
281   if (!err.empty() || dur <= 0) {
282     dout(5) << "invalid length param " << duration_str << dendl;
283     http_ret = -EINVAL;
284     return;
285   }
286   http_ret = store->meta_mgr->lock_exclusive(metadata_key, make_timespan(dur), lock_id);
287   if (http_ret == -EBUSY)
288     http_ret = -ERR_LOCKED;
289 }
290
291 void RGWOp_Metadata_Unlock::execute() {
292   string lock_id;
293   string metadata_key;
294
295   frame_metadata_key(s, metadata_key);
296
297   http_ret = 0;
298
299   lock_id = s->info.args.get("lock_id");
300
301   if ((!s->info.args.exists("key")) ||
302       lock_id.empty()) {
303     dout(5) << "Error invalid parameter list" << dendl;
304     http_ret = -EINVAL;
305     return;
306   }
307
308   http_ret = store->meta_mgr->unlock(metadata_key, lock_id);
309 }
310
311 RGWOp *RGWHandler_Metadata::op_get() {
312   if (s->info.args.exists("key"))
313     return new RGWOp_Metadata_Get;
314   else
315     return new RGWOp_Metadata_List;
316 }
317
318 RGWOp *RGWHandler_Metadata::op_put() {
319   return new RGWOp_Metadata_Put;
320 }
321
322 RGWOp *RGWHandler_Metadata::op_delete() {
323   return new RGWOp_Metadata_Delete;
324 }
325
326 RGWOp *RGWHandler_Metadata::op_post() {
327   if (s->info.args.exists("lock"))
328     return new RGWOp_Metadata_Lock;
329   else if (s->info.args.exists("unlock"))
330     return new RGWOp_Metadata_Unlock;
331
332   return NULL;
333 }