Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / test / rgw / test_rgw_common.h
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 "common/ceph_json.h"
16 #include "common/Formatter.h"
17 #include "rgw/rgw_common.h"
18 #include "rgw/rgw_rados.h"
19
20 #ifndef CEPH_TEST_RGW_COMMON_H
21 #define CEPH_TEST_RGW_COMMON_H
22
23 struct old_rgw_bucket {
24   std::string tenant;
25   std::string name;
26   std::string data_pool;
27   std::string data_extra_pool; /* if not set, then we should use data_pool instead */
28   std::string index_pool;
29   std::string marker;
30   std::string bucket_id;
31
32   std::string oid; /*
33                     * runtime in-memory only info. If not empty, points to the bucket instance object
34                     */
35
36   old_rgw_bucket() { }
37   // cppcheck-suppress noExplicitConstructor
38   old_rgw_bucket(const std::string& s) : name(s) {
39     data_pool = index_pool = s;
40     marker = "";
41   }
42   old_rgw_bucket(const char *n) : name(n) {
43     data_pool = index_pool = n;
44     marker = "";
45   }
46   old_rgw_bucket(const char *t, const char *n, const char *dp, const char *ip, const char *m, const char *id, const char *h) :
47     tenant(t), name(n), data_pool(dp), index_pool(ip), marker(m), bucket_id(id) {}
48
49   void encode(bufferlist& bl) const {
50      ENCODE_START(8, 3, bl);
51     ::encode(name, bl);
52     ::encode(data_pool, bl);
53     ::encode(marker, bl);
54     ::encode(bucket_id, bl);
55     ::encode(index_pool, bl);
56     ::encode(data_extra_pool, bl);
57     ::encode(tenant, bl);
58     ENCODE_FINISH(bl);
59   }
60   void decode(bufferlist::iterator& bl) {
61     DECODE_START_LEGACY_COMPAT_LEN(8, 3, 3, bl);
62     ::decode(name, bl);
63     ::decode(data_pool, bl);
64     if (struct_v >= 2) {
65       ::decode(marker, bl);
66       if (struct_v <= 3) {
67         uint64_t id;
68         ::decode(id, bl);
69         char buf[16];
70         snprintf(buf, sizeof(buf), "%llu", (long long)id);
71         bucket_id = buf;
72       } else {
73         ::decode(bucket_id, bl);
74       }
75     }
76     if (struct_v >= 5) {
77       ::decode(index_pool, bl);
78     } else {
79       index_pool = data_pool;
80     }
81     if (struct_v >= 7) {
82       ::decode(data_extra_pool, bl);
83     }
84     if (struct_v >= 8) {
85       ::decode(tenant, bl);
86     }
87     DECODE_FINISH(bl);
88   }
89
90   // format a key for the bucket/instance. pass delim=0 to skip a field
91   std::string get_key(char tenant_delim = '/',
92                       char id_delim = ':') const;
93
94   const std::string& get_data_extra_pool() {
95     if (data_extra_pool.empty()) {
96       return data_pool;
97     }
98     return data_extra_pool;
99   }
100
101   void dump(Formatter *f) const;
102   void decode_json(JSONObj *obj);
103   static void generate_test_instances(list<old_rgw_bucket*>& o);
104
105   bool operator<(const old_rgw_bucket& b) const {
106     return name.compare(b.name) < 0;
107   }
108 };
109 WRITE_CLASS_ENCODER(old_rgw_bucket)
110
111 class old_rgw_obj {
112   std::string orig_obj;
113   std::string loc;
114   std::string object;
115   std::string instance;
116 public:
117   const std::string& get_object() const { return object; }
118   const std::string& get_orig_obj() const { return orig_obj; }
119   const std::string& get_loc() const { return loc; }
120   const std::string& get_instance() const { return instance; }
121   old_rgw_bucket bucket;
122   std::string ns;
123
124   bool in_extra_data; /* in-memory only member, does not serialize */
125
126   // Represents the hash index source for this object once it is set (non-empty)
127   std::string index_hash_source;
128
129   old_rgw_obj() : in_extra_data(false) {}
130   old_rgw_obj(old_rgw_bucket& b, const std::string& o) : in_extra_data(false) {
131     init(b, o);
132   }
133   old_rgw_obj(old_rgw_bucket& b, const rgw_obj_key& k) : in_extra_data(false) {
134     from_index_key(b, k);
135   }
136   void init(old_rgw_bucket& b, const std::string& o) {
137     bucket = b;
138     set_obj(o);
139     reset_loc();
140   }
141   void init_ns(old_rgw_bucket& b, const std::string& o, const std::string& n) {
142     bucket = b;
143     set_ns(n);
144     set_obj(o);
145     reset_loc();
146   }
147   int set_ns(const char *n) {
148     if (!n)
149       return -EINVAL;
150     std::string ns_str(n);
151     return set_ns(ns_str);
152   }
153   int set_ns(const std::string& n) {
154     if (n[0] == '_')
155       return -EINVAL;
156     ns = n;
157     set_obj(orig_obj);
158     return 0;
159   }
160   int set_instance(const std::string& i) {
161     if (i[0] == '_')
162       return -EINVAL;
163     instance = i;
164     set_obj(orig_obj);
165     return 0;
166   }
167
168   int clear_instance() {
169     return set_instance(string());
170   }
171
172   void set_loc(const std::string& k) {
173     loc = k;
174   }
175
176   void reset_loc() {
177     loc.clear();
178     /*
179      * For backward compatibility. Older versions used to have object locator on all objects,
180      * however, the orig_obj was the effective object locator. This had the same effect as not
181      * having object locator at all for most objects but the ones that started with underscore as
182      * these were escaped.
183      */
184     if (orig_obj[0] == '_' && ns.empty()) {
185       loc = orig_obj;
186     }
187   }
188
189   bool have_null_instance() {
190     return instance == "null";
191   }
192
193   bool have_instance() {
194     return !instance.empty();
195   }
196
197   bool need_to_encode_instance() {
198     return have_instance() && !have_null_instance();
199   }
200
201   void set_obj(const std::string& o) {
202     object.reserve(128);
203
204     orig_obj = o;
205     if (ns.empty() && !need_to_encode_instance()) {
206       if (o.empty()) {
207         return;
208       }
209       if (o.size() < 1 || o[0] != '_') {
210         object = o;
211         return;
212       }
213       object = "_";
214       object.append(o);
215     } else {
216       object = "_";
217       object.append(ns);
218       if (need_to_encode_instance()) {
219         object.append(string(":") + instance);
220       }
221       object.append("_");
222       object.append(o);
223     }
224     reset_loc();
225   }
226
227   /*
228    * get the object's key name as being referred to by the bucket index.
229    */
230   std::string get_index_key_name() const {
231     if (ns.empty()) {
232       if (orig_obj.size() < 1 || orig_obj[0] != '_') {
233         return orig_obj;
234       }
235       return std::string("_") + orig_obj;
236     };
237
238     char buf[ns.size() + 16];
239     snprintf(buf, sizeof(buf), "_%s_", ns.c_str());
240     return std::string(buf) + orig_obj;
241   };
242
243   void from_index_key(old_rgw_bucket& b, const rgw_obj_key& key) {
244     if (key.name[0] != '_') {
245       init(b, key.name);
246       set_instance(key.instance);
247       return;
248     }
249     if (key.name[1] == '_') {
250       init(b, key.name.substr(1));
251       set_instance(key.instance);
252       return;
253     }
254     ssize_t pos = key.name.find('_', 1);
255     if (pos < 0) {
256       /* shouldn't happen, just use key */
257       init(b, key.name);
258       set_instance(key.instance);
259       return;
260     }
261
262     init_ns(b, key.name.substr(pos + 1), key.name.substr(1, pos -1));
263     set_instance(key.instance);
264   }
265
266   void get_index_key(rgw_obj_key *key) const {
267     key->name = get_index_key_name();
268     key->instance = instance;
269   }
270
271   static void parse_ns_field(string& ns, std::string& instance) {
272     int pos = ns.find(':');
273     if (pos >= 0) {
274       instance = ns.substr(pos + 1);
275       ns = ns.substr(0, pos);
276     } else {
277       instance.clear();
278     }
279   }
280
281   std::string& get_hash_object() {
282     return index_hash_source.empty() ? orig_obj : index_hash_source;
283   }
284   /**
285    * Translate a namespace-mangled object name to the user-facing name
286    * existing in the given namespace.
287    *
288    * If the object is part of the given namespace, it returns true
289    * and cuts down the name to the unmangled version. If it is not
290    * part of the given namespace, it returns false.
291    */
292   static bool translate_raw_obj_to_obj_in_ns(string& obj, std::string& instance, std::string& ns) {
293     if (obj[0] != '_') {
294       if (ns.empty()) {
295         return true;
296       }
297       return false;
298     }
299
300     std::string obj_ns;
301     bool ret = parse_raw_oid(obj, &obj, &instance, &obj_ns);
302     if (!ret) {
303       return ret;
304     }
305
306     return (ns == obj_ns);
307   }
308
309   static bool parse_raw_oid(const std::string& oid, std::string *obj_name, std::string *obj_instance, std::string *obj_ns) {
310     obj_instance->clear();
311     obj_ns->clear();
312     if (oid[0] != '_') {
313       *obj_name = oid;
314       return true;
315     }
316
317     if (oid.size() >= 2 && oid[1] == '_') {
318       *obj_name = oid.substr(1);
319       return true;
320     }
321
322     if (oid[0] != '_' || oid.size() < 3) // for namespace, min size would be 3: _x_
323       return false;
324
325     int pos = oid.find('_', 1);
326     if (pos <= 1) // if it starts with __, it's not in our namespace
327       return false;
328
329     *obj_ns = oid.substr(1, pos - 1);
330     parse_ns_field(*obj_ns, *obj_instance);
331
332     *obj_name = oid.substr(pos + 1);
333     return true;
334   }
335
336   /**
337    * Given a mangled object name and an empty namespace string, this
338    * function extracts the namespace into the string and sets the object
339    * name to be the unmangled version.
340    *
341    * It returns true after successfully doing so, or
342    * false if it fails.
343    */
344   static bool strip_namespace_from_object(string& obj, std::string& ns, std::string& instance) {
345     ns.clear();
346     instance.clear();
347     if (obj[0] != '_') {
348       return true;
349     }
350
351     size_t pos = obj.find('_', 1);
352     if (pos == std::string::npos) {
353       return false;
354     }
355
356     if (obj[1] == '_') {
357       obj = obj.substr(1);
358       return true;
359     }
360
361     size_t period_pos = obj.find('.');
362     if (period_pos < pos) {
363       return false;
364     }
365
366     ns = obj.substr(1, pos-1);
367     obj = obj.substr(pos+1, std::string::npos);
368
369     parse_ns_field(ns, instance);
370     return true;
371   }
372
373   void set_in_extra_data(bool val) {
374     in_extra_data = val;
375   }
376
377   bool is_in_extra_data() const {
378     return in_extra_data;
379   }
380
381   void encode(bufferlist& bl) const {
382     ENCODE_START(5, 3, bl);
383     ::encode(bucket.name, bl);
384     ::encode(loc, bl);
385     ::encode(ns, bl);
386     ::encode(object, bl);
387     ::encode(bucket, bl);
388     ::encode(instance, bl);
389     if (!ns.empty() || !instance.empty()) {
390       ::encode(orig_obj, bl);
391     }
392     ENCODE_FINISH(bl);
393   }
394   void decode(bufferlist::iterator& bl) {
395     DECODE_START_LEGACY_COMPAT_LEN(5, 3, 3, bl);
396     ::decode(bucket.name, bl);
397     ::decode(loc, bl);
398     ::decode(ns, bl);
399     ::decode(object, bl);
400     if (struct_v >= 2)
401       ::decode(bucket, bl);
402     if (struct_v >= 4)
403       ::decode(instance, bl);
404     if (ns.empty() && instance.empty()) {
405       if (object[0] != '_') {
406         orig_obj = object;
407       } else {
408         orig_obj = object.substr(1);
409       }
410     } else {
411       if (struct_v >= 5) {
412         ::decode(orig_obj, bl);
413       } else {
414         ssize_t pos = object.find('_', 1);
415         if (pos < 0) {
416           throw buffer::error();
417         }
418         orig_obj = object.substr(pos);
419       }
420     }
421     DECODE_FINISH(bl);
422   }
423
424   bool operator==(const old_rgw_obj& o) const {
425     return (object.compare(o.object) == 0) &&
426            (bucket.name.compare(o.bucket.name) == 0) &&
427            (ns.compare(o.ns) == 0) &&
428            (instance.compare(o.instance) == 0);
429   }
430   bool operator<(const old_rgw_obj& o) const {
431     int r = bucket.name.compare(o.bucket.name);
432     if (r == 0) {
433       r = bucket.bucket_id.compare(o.bucket.bucket_id);
434       if (r == 0) {
435         r = object.compare(o.object);
436         if (r == 0) {
437           r = ns.compare(o.ns);
438           if (r == 0) {
439             r = instance.compare(o.instance);
440           }
441         }
442       }
443     }
444
445     return (r < 0);
446   }
447 };
448 WRITE_CLASS_ENCODER(old_rgw_obj)
449
450 static inline void prepend_old_bucket_marker(const old_rgw_bucket& bucket, const string& orig_oid, string& oid)
451 {
452   if (bucket.marker.empty() || orig_oid.empty()) {
453     oid = orig_oid;
454   } else {
455     oid = bucket.marker;
456     oid.append("_");
457     oid.append(orig_oid);
458   }
459 }
460
461 void test_rgw_init_env(RGWZoneGroup *zonegroup, RGWZoneParams *zone_params);
462
463 struct test_rgw_env {
464   RGWZoneGroup zonegroup;
465   RGWZoneParams zone_params;
466   rgw_data_placement_target default_placement;
467
468   test_rgw_env() {
469     test_rgw_init_env(&zonegroup, &zone_params);
470     default_placement.data_pool = rgw_pool(zone_params.placement_pools[zonegroup.default_placement].data_pool);
471     default_placement.data_extra_pool =  rgw_pool(zone_params.placement_pools[zonegroup.default_placement].data_extra_pool);
472   }
473
474   rgw_data_placement_target get_placement(const std::string& placement_id) {
475     const RGWZonePlacementInfo& pi = zone_params.placement_pools[placement_id];
476     rgw_data_placement_target pt;
477     pt.index_pool = pi.index_pool;
478     pt.data_pool = pi.data_pool;
479     pt.data_extra_pool = pi.data_extra_pool;
480     return pt;
481   }
482
483   rgw_raw_obj get_raw(const rgw_obj& obj) {
484     rgw_obj_select s(obj);
485     return s.get_raw_obj(zonegroup, zone_params);
486   }
487
488   rgw_raw_obj get_raw(const rgw_obj_select& os) {
489     return os.get_raw_obj(zonegroup, zone_params);
490   }
491 };
492
493 void test_rgw_add_placement(RGWZoneGroup *zonegroup, RGWZoneParams *zone_params, const std::string& name, bool is_default);
494 void test_rgw_populate_explicit_placement_bucket(rgw_bucket *b, const char *t, const char *n, const char *dp, const char *ip, const char *m, const char *id);
495 void test_rgw_populate_old_bucket(old_rgw_bucket *b, const char *t, const char *n, const char *dp, const char *ip, const char *m, const char *id);
496
497 std::string test_rgw_get_obj_oid(const rgw_obj& obj);
498 void test_rgw_init_explicit_placement_bucket(rgw_bucket *bucket, const char *name);
499 void test_rgw_init_old_bucket(old_rgw_bucket *bucket, const char *name);
500 void test_rgw_populate_bucket(rgw_bucket *b, const char *t, const char *n, const char *m, const char *id);
501 void test_rgw_init_bucket(rgw_bucket *bucket, const char *name);
502 rgw_obj test_rgw_create_obj(const rgw_bucket& bucket, const std::string& name, const std::string& instance, const std::string& ns);
503
504 #endif
505