Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / test / encoding / ceph_dencoder.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) 2015 Red Hat
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
16 #include <errno.h>
17 #include "include/types.h"
18 #include "ceph_ver.h"
19 #include "include/encoding.h"
20 #include "include/ceph_features.h"
21 #include "common/ceph_argparse.h"
22 #include "common/Formatter.h"
23 #include "common/errno.h"
24 #include "msg/Message.h"
25 #include "include/assert.h"
26
27 #define TYPE(t)
28 #define TYPE_STRAYDATA(t)
29 #define TYPE_NONDETERMINISTIC(t)
30 #define TYPE_FEATUREFUL(t)
31 #define TYPE_FEATUREFUL_STRAYDATA(t)
32 #define TYPE_FEATUREFUL_NONDETERMINISTIC(t)
33 #define TYPE_FEATUREFUL_NOCOPY(t)
34 #define TYPE_NOCOPY(t)
35 #define MESSAGE(t)
36 #include "types.h"
37 #undef TYPE
38 #undef TYPE_STRAYDATA
39 #undef TYPE_NONDETERMINISTIC
40 #undef TYPE_NOCOPY
41 #undef TYPE_FEATUREFUL
42 #undef TYPE_FEATUREFUL_STRAYDATA
43 #undef TYPE_FEATUREFUL_NONDETERMINISTIC
44 #undef TYPE_FEATUREFUL_NOCOPY
45 #undef MESSAGE
46
47 #define MB(m) ((m) * 1024 * 1024)
48
49 void usage(ostream &out)
50 {
51   out << "usage: ceph-dencoder [commands ...]" << std::endl;
52   out << "\n";
53   out << "  version             print version string (to stdout)\n";
54   out << "\n";
55   out << "  import <encfile>    read encoded data from encfile\n";
56   out << "  export <outfile>    write encoded data to outfile\n";
57   out << "\n";
58   out << "  set_features <num>  set feature bits used for encoding\n";
59   out << "  get_features        print feature bits (int) to stdout\n";
60   out << "\n";
61   out << "  list_types          list supported types\n";
62   out << "  type <classname>    select in-memory type\n";
63   out << "  skip <num>          skip <num> leading bytes before decoding\n";
64   out << "  decode              decode into in-memory object\n";
65   out << "  encode              encode in-memory object\n";
66   out << "  dump_json           dump in-memory object as json (to stdout)\n";
67   out << "  hexdump             print encoded data in hex\n";
68   out << "\n";
69   out << "  copy                copy object (via operator=)\n";
70   out << "  copy_ctor           copy object (via copy ctor)\n";
71   out << "\n";
72   out << "  count_tests         print number of generated test objects (to stdout)\n";
73   out << "  select_test <n>     select generated test object as in-memory object\n";
74   out << "  is_deterministic    exit w/ success if type encodes deterministically\n";
75 }
76 struct Dencoder {
77   virtual ~Dencoder() {}
78   virtual string decode(bufferlist bl, uint64_t seek) = 0;
79   virtual void encode(bufferlist& out, uint64_t features) = 0;
80   virtual void dump(ceph::Formatter *f) = 0;
81   virtual void copy() {
82     cerr << "copy operator= not supported" << std::endl;
83   }
84   virtual void copy_ctor() {
85     cerr << "copy ctor not supported" << std::endl;
86   }
87   virtual void generate() = 0;
88   virtual int num_generated() = 0;
89   virtual string select_generated(unsigned n) = 0;
90   virtual bool is_deterministic() = 0;
91   //virtual void print(ostream& out) = 0;
92 };
93
94 template<class T>
95 class DencoderBase : public Dencoder {
96 protected:
97   T* m_object;
98   list<T*> m_list;
99   bool stray_okay;
100   bool nondeterministic;
101
102 public:
103   DencoderBase(bool stray_okay, bool nondeterministic)
104     : m_object(new T),
105       stray_okay(stray_okay),
106       nondeterministic(nondeterministic) {}
107   ~DencoderBase() override {
108     delete m_object;
109   }
110
111   string decode(bufferlist bl, uint64_t seek) override {
112     bufferlist::iterator p = bl.begin();
113     p.seek(seek);
114     try {
115       ::decode(*m_object, p);
116     }
117     catch (buffer::error& e) {
118       return e.what();
119     }
120     if (!stray_okay && !p.end()) {
121       ostringstream ss;
122       ss << "stray data at end of buffer, offset " << p.get_off();
123       return ss.str();
124     }
125     return string();
126   }
127
128   void encode(bufferlist& out, uint64_t features) override = 0;
129
130   void dump(ceph::Formatter *f) override {
131     m_object->dump(f);
132   }
133   void generate() override {
134     T::generate_test_instances(m_list);
135   }
136   int num_generated() override {
137     return m_list.size();
138   }
139   string select_generated(unsigned i) override {
140     // allow 0- or 1-based (by wrapping)
141     if (i == 0)
142       i = m_list.size();
143     if ((i == 0) || (i > m_list.size()))
144       return "invalid id for generated object";
145     m_object = *(std::next(m_list.begin(), i-1));
146     return string();
147   }
148
149   bool is_deterministic() override {
150     return !nondeterministic;
151   }
152 };
153
154 template<class T>
155 class DencoderImplNoFeatureNoCopy : public DencoderBase<T> {
156 public:
157   DencoderImplNoFeatureNoCopy(bool stray_ok, bool nondeterministic)
158     : DencoderBase<T>(stray_ok, nondeterministic) {}
159   void encode(bufferlist& out, uint64_t features) override {
160     out.clear();
161     ::encode(*this->m_object, out);
162   }
163 };
164
165 template<class T>
166 class DencoderImplNoFeature : public DencoderImplNoFeatureNoCopy<T> {
167 public:
168   DencoderImplNoFeature(bool stray_ok, bool nondeterministic)
169     : DencoderImplNoFeatureNoCopy<T>(stray_ok, nondeterministic) {}
170   void copy() override {
171     T *n = new T;
172     *n = *this->m_object;
173     delete this->m_object;
174     this->m_object = n;
175   }
176   void copy_ctor() override {
177     T *n = new T(*this->m_object);
178     delete this->m_object;
179     this->m_object = n;
180   }
181 };
182
183 template<class T>
184 class DencoderImplFeaturefulNoCopy : public DencoderBase<T> {
185 public:
186   DencoderImplFeaturefulNoCopy(bool stray_ok, bool nondeterministic)
187     : DencoderBase<T>(stray_ok, nondeterministic) {}
188   void encode(bufferlist& out, uint64_t features) override {
189     out.clear();
190     ::encode(*(this->m_object), out, features);
191   }
192 };
193
194 template<class T>
195 class DencoderImplFeatureful : public DencoderImplFeaturefulNoCopy<T> {
196 public:
197   DencoderImplFeatureful(bool stray_ok, bool nondeterministic)
198     : DencoderImplFeaturefulNoCopy<T>(stray_ok, nondeterministic) {}
199   void copy() override {
200     T *n = new T;
201     *n = *this->m_object;
202     delete this->m_object;
203     this->m_object = n;
204   }
205   void copy_ctor() override {
206     T *n = new T(*this->m_object);
207     delete this->m_object;
208     this->m_object = n;
209   }
210 };
211
212 template<class T>
213 class MessageDencoderImpl : public Dencoder {
214   T *m_object;
215   list<T*> m_list;
216
217 public:
218   MessageDencoderImpl() {
219     m_object = new T;
220   }
221   ~MessageDencoderImpl() override {
222     m_object->put();
223   }
224
225   string decode(bufferlist bl, uint64_t seek) override {
226     bufferlist::iterator p = bl.begin();
227     p.seek(seek);
228     try {
229       Message *n = decode_message(g_ceph_context, 0, p);
230       if (!n)
231         throw std::runtime_error("failed to decode");
232       if (n->get_type() != m_object->get_type()) {
233         stringstream ss;
234         ss << "decoded type " << n->get_type() << " instead of expected " << m_object->get_type();
235         throw std::runtime_error(ss.str());
236       }
237       m_object->put();
238       m_object = static_cast<T *>(n);
239     }
240     catch (buffer::error& e) {
241       return e.what();
242     }
243     if (!p.end()) {
244       ostringstream ss;
245       ss << "stray data at end of buffer, offset " << p.get_off();
246       return ss.str();
247     }
248     return string();
249   }
250
251   void encode(bufferlist& out, uint64_t features) override {
252     out.clear();
253     encode_message(m_object, features, out);
254   }
255
256   void dump(ceph::Formatter *f) override {
257     m_object->dump(f);
258   }
259   void generate() override {
260     //T::generate_test_instances(m_list);
261   }
262   int num_generated() override {
263     return m_list.size();
264   }
265   string select_generated(unsigned i) override {
266     // allow 0- or 1-based (by wrapping)
267     if (i == 0)
268       i = m_list.size();
269     if ((i == 0) || (i > m_list.size()))
270       return "invalid id for generated object";
271     m_object->put();
272     m_object = *(std::next(m_list.begin(), i-1));
273     return string();
274   }
275   bool is_deterministic() override {
276     return true;
277   }
278
279   //void print(ostream& out) {
280   //out << m_object << std::endl;
281   //}
282 };
283
284   
285
286 int main(int argc, const char **argv)
287 {
288   // dencoders
289   map<string,Dencoder*> dencoders;
290
291 #define T_STR(x) #x
292 #define T_STRINGIFY(x) T_STR(x)
293 #define TYPE(t) dencoders[T_STRINGIFY(t)] = new DencoderImplNoFeature<t>(false, false);
294 #define TYPE_STRAYDATA(t) dencoders[T_STRINGIFY(t)] = new DencoderImplNoFeature<t>(true, false);
295 #define TYPE_NONDETERMINISTIC(t) dencoders[T_STRINGIFY(t)] = new DencoderImplNoFeature<t>(false, true);
296 #define TYPE_FEATUREFUL(t) dencoders[T_STRINGIFY(t)] = new DencoderImplFeatureful<t>(false, false);
297 #define TYPE_FEATUREFUL_STRAYDATA(t) dencoders[T_STRINGIFY(t)] = new DencoderImplFeatureful<t>(true, false);
298 #define TYPE_FEATUREFUL_NONDETERMINISTIC(t) dencoders[T_STRINGIFY(t)] = new DencoderImplFeatureful<t>(false, true);
299 #define TYPE_FEATUREFUL_NOCOPY(t) dencoders[T_STRINGIFY(t)] = new DencoderImplFeaturefulNoCopy<t>(false, false);
300 #define TYPE_NOCOPY(t) dencoders[T_STRINGIFY(t)] = new DencoderImplNoFeatureNoCopy<t>(false, false);
301 #define MESSAGE(t) dencoders[T_STRINGIFY(t)] = new MessageDencoderImpl<t>;
302 #include "types.h"
303 #undef TYPE
304 #undef TYPE_STRAYDATA
305 #undef TYPE_NONDETERMINISTIC
306 #undef TYPE_NOCOPY
307 #undef TYPE_FEATUREFUL
308 #undef TYPE_FEATUREFUL_STRAYDATA
309 #undef TYPE_FEATUREFUL_NONDETERMINISTIC
310 #undef TYPE_FEATUREFUL_NOCOPY
311 #undef T_STR
312 #undef T_STRINGIFY
313
314   vector<const char*> args;
315   argv_to_vec(argc, argv, args);
316   env_to_vec(args);
317
318   Dencoder *den = NULL;
319   uint64_t features = CEPH_FEATURES_SUPPORTED_DEFAULT;
320   bufferlist encbl;
321   uint64_t skip = 0;
322
323   if (args.empty()) {
324     cerr << "-h for help" << std::endl;
325     exit(1);
326   }
327   for (std::vector<const char*>::iterator i = args.begin(); i != args.end(); ++i) {
328     string err;
329
330     if (*i == string("help") || *i == string("-h") || *i == string("--help")) {
331       usage(cout);
332       exit(0);
333     } else if (*i == string("version")) {
334       cout << CEPH_GIT_NICE_VER << std::endl;
335     } else if (*i == string("list_types")) {
336       for (map<string,Dencoder*>::iterator p = dencoders.begin();
337            p != dencoders.end();
338            ++p)
339         cout << p->first << std::endl;
340       exit(0);
341     } else if (*i == string("type")) {
342       ++i;
343       if (i == args.end()) {
344         cerr << "expecting type" << std::endl;
345         exit(1);
346       }
347       string cname = *i;
348       if (!dencoders.count(cname)) {
349         cerr << "class '" << cname << "' unknown" << std::endl;
350         exit(1);
351       }
352       den = dencoders[cname];
353       den->generate();
354     } else if (*i == string("skip")) {
355       ++i;
356       if (i == args.end()) {
357         cerr << "expecting byte count" << std::endl;
358         exit(1);
359       }
360       skip = atoi(*i);
361     } else if (*i == string("get_features")) {
362       cout << CEPH_FEATURES_SUPPORTED_DEFAULT << std::endl;
363       exit(0);
364     } else if (*i == string("set_features")) {
365       ++i;
366       if (i == args.end()) {
367         cerr << "expecting features" << std::endl;
368         exit(1);
369       }
370       features = atoll(*i);
371     } else if (*i == string("encode")) {
372       if (!den) {
373         cerr << "must first select type with 'type <name>'" << std::endl;
374         exit(1);
375       }
376       den->encode(encbl, features | CEPH_FEATURE_RESERVED); // hack for OSDMap
377     } else if (*i == string("decode")) {
378       if (!den) {
379         cerr << "must first select type with 'type <name>'" << std::endl;
380         exit(1);
381       }
382       err = den->decode(encbl, skip);
383     } else if (*i == string("copy_ctor")) {
384       if (!den) {
385         cerr << "must first select type with 'type <name>'" << std::endl;
386         exit(1);
387       }
388       den->copy_ctor();
389     } else if (*i == string("copy")) {
390       if (!den) {
391         cerr << "must first select type with 'type <name>'" << std::endl;
392         exit(1);
393       }
394       den->copy();
395     } else if (*i == string("dump_json")) {
396       if (!den) {
397         cerr << "must first select type with 'type <name>'" << std::endl;
398         exit(1);
399       }
400       JSONFormatter jf(true);
401       jf.open_object_section("object");
402       den->dump(&jf);
403       jf.close_section();
404       jf.flush(cout);
405       cout << std::endl;
406
407     } else if (*i == string("hexdump")) {
408       encbl.hexdump(cout);
409     } else if (*i == string("import")) {
410       ++i;
411       if (i == args.end()) {
412         cerr << "expecting filename" << std::endl;
413         exit(1);
414       }
415       int r;
416       if (*i == string("-")) {
417         *i = "stdin";
418         // Read up to 1mb if stdin specified
419         r = encbl.read_fd(STDIN_FILENO, MB(1));
420       } else {
421         r = encbl.read_file(*i, &err);
422       }
423       if (r < 0) {
424         cerr << "error reading " << *i << ": " << err << std::endl;
425         exit(1);
426       }
427
428     } else if (*i == string("export")) {
429       ++i;
430       if (i == args.end()) {
431         cerr << "expecting filename" << std::endl;
432         exit(1);
433       }
434       int fd = ::open(*i, O_WRONLY|O_CREAT|O_TRUNC, 0644);
435       if (fd < 0) {
436         cerr << "error opening " << *i << " for write: " << cpp_strerror(errno) << std::endl;
437         exit(1);
438       }
439       int r = encbl.write_fd(fd);
440       if (r < 0) {
441         cerr << "error writing " << *i << ": " << cpp_strerror(errno) << std::endl;
442         exit(1);
443       }
444       ::close(fd);
445
446     } else if (*i == string("count_tests")) {
447       if (!den) {
448         cerr << "must first select type with 'type <name>'" << std::endl;
449         exit(1);
450       }
451       cout << den->num_generated() << std::endl;
452     } else if (*i == string("select_test")) {
453       if (!den) {
454         cerr << "must first select type with 'type <name>'" << std::endl;
455         exit(1);
456       }
457       ++i;
458       if (i == args.end()) {
459         cerr << "expecting instance number" << std::endl;
460         exit(1);
461       }
462       int n = atoi(*i);
463       err = den->select_generated(n);
464     } else if (*i == string("is_deterministic")) {
465       if (!den) {
466         cerr << "must first select type with 'type <name>'" << std::endl;
467         exit(1);
468       }
469       if (den->is_deterministic())
470         exit(0);
471       else
472         exit(1);
473     } else {
474       cerr << "unknown option '" << *i << "'" << std::endl;
475       exit(1);
476     }      
477     if (err.length()) {
478       cerr << "error: " << err << std::endl;
479       exit(1);
480     }
481   }
482   return 0;
483 }