Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / tools / rebuild_mondb.cc
1 #include "auth/cephx/CephxKeyServer.h"
2 #include "common/errno.h"
3 #include "mon/AuthMonitor.h"
4 #include "mon/MonitorDBStore.h"
5 #include "os/ObjectStore.h"
6 #include "osd/OSD.h"
7
8 static int update_auth(const string& keyring_path,
9                        const OSDSuperblock& sb,
10                        MonitorDBStore& ms);
11 static int update_monitor(const OSDSuperblock& sb, MonitorDBStore& ms);
12 static int update_osdmap(ObjectStore& fs,
13                          OSDSuperblock& sb,
14                          MonitorDBStore& ms);
15 static int update_pgmap_pg(ObjectStore& fs, MonitorDBStore& ms);
16
17 int update_mon_db(ObjectStore& fs, OSDSuperblock& sb,
18                   const string& keyring,
19                   const string& store_path)
20 {
21   MonitorDBStore ms(store_path);
22   int r = ms.create_and_open(cerr);
23   if (r < 0) {
24     cerr << "unable to open mon store: " << store_path << std::endl;
25     return r;
26   }
27   if ((r = update_auth(keyring, sb, ms)) < 0) {
28     goto out;
29   }
30   if ((r = update_osdmap(fs, sb, ms)) < 0) {
31     goto out;
32   }
33   if ((r = update_pgmap_pg(fs, ms)) < 0) {
34     goto out;
35   }
36   if ((r = update_monitor(sb, ms)) < 0) {
37     goto out;
38   }
39  out:
40   ms.close();
41   return r;
42 }
43
44 static void add_auth(KeyServerData::Incremental& auth_inc,
45                      MonitorDBStore& ms)
46 {
47   AuthMonitor::Incremental inc;
48   inc.inc_type = AuthMonitor::AUTH_DATA;
49   ::encode(auth_inc, inc.auth_data);
50   inc.auth_type = CEPH_AUTH_CEPHX;
51
52   bufferlist bl;
53   __u8 v = 1;
54   ::encode(v, bl);
55   inc.encode(bl, CEPH_FEATURES_ALL);
56
57   const string prefix("auth");
58   auto last_committed = ms.get(prefix, "last_committed") + 1;
59   auto t = make_shared<MonitorDBStore::Transaction>();
60   t->put(prefix, last_committed, bl);
61   t->put(prefix, "last_committed", last_committed);
62   auto first_committed = ms.get(prefix, "first_committed");
63   if (!first_committed) {
64     t->put(prefix, "first_committed", last_committed);
65   }
66   ms.apply_transaction(t);
67 }
68
69 static int get_auth_inc(const string& keyring_path,
70                         const OSDSuperblock& sb,
71                         KeyServerData::Incremental* auth_inc)
72 {
73   auth_inc->op = KeyServerData::AUTH_INC_ADD;
74
75   // get the name
76   EntityName entity;
77   // assuming the entity name of OSD is "osd.<osd_id>"
78   entity.set(CEPH_ENTITY_TYPE_OSD, std::to_string(sb.whoami));
79   auth_inc->name = entity;
80
81   // read keyring from disk
82   KeyRing keyring;
83   {
84     bufferlist bl;
85     string error;
86     int r = bl.read_file(keyring_path.c_str(), &error);
87     if (r < 0) {
88       if (r == -ENOENT) {
89         cout << "ignoring keyring (" << keyring_path << ")"
90              << ": " << error << std::endl;
91         return 0;
92       } else {
93         cerr << "unable to read keyring (" << keyring_path << ")"
94              << ": " << error << std::endl;
95         return r;
96       }
97     } else if (bl.length() == 0) {
98       cout << "ignoring empty keyring: " << keyring_path << std::endl;
99       return 0;
100     }
101     auto bp = bl.begin();
102     try {
103       ::decode(keyring, bp);
104     } catch (const buffer::error& e) {
105       cerr << "error decoding keyring: " << keyring_path << std::endl;
106       return -EINVAL;
107     }
108   }
109
110   // get the key
111   EntityAuth new_inc;
112   if (!keyring.get_auth(auth_inc->name, new_inc)) {
113     cerr << "key for " << auth_inc->name << " not found in keyring: "
114          << keyring_path << std::endl;
115     return -EINVAL;
116   }
117   auth_inc->auth.key = new_inc.key;
118
119   // get the caps
120   map<string,bufferlist> caps;
121   if (new_inc.caps.empty()) {
122     // fallback to default caps for an OSD
123     //   osd 'allow *' mon 'allow rwx'
124     // as suggested by document.
125     ::encode(string("allow *"), caps["osd"]);
126     ::encode(string("allow rwx"), caps["mon"]);
127   } else {
128     caps = new_inc.caps;
129   }
130   auth_inc->auth.caps = caps;
131   return 0;
132 }
133
134 // rebuild
135 //  - auth/${epoch}
136 //  - auth/first_committed
137 //  - auth/last_committed
138 static int update_auth(const string& keyring_path,
139                        const OSDSuperblock& sb,
140                        MonitorDBStore& ms)
141 {
142   // stolen from AuthMonitor::prepare_command(), where prefix is "auth add"
143   KeyServerData::Incremental auth_inc;
144   int r;
145   if ((r = get_auth_inc(keyring_path, sb, &auth_inc))) {
146     return r;
147   }
148   add_auth(auth_inc, ms);
149   return 0;
150 }
151
152 // stolen from Monitor::check_fsid()
153 static int check_fsid(const uuid_d& fsid, MonitorDBStore& ms)
154 {
155   bufferlist bl;
156   int r = ms.get("monitor", "cluster_uuid", bl);
157   if (r == -ENOENT)
158     return r;
159   string uuid(bl.c_str(), bl.length());
160   auto end = uuid.find_first_of('\n');
161   if (end != uuid.npos) {
162     uuid.resize(end);
163   }
164   uuid_d existing;
165   if (!existing.parse(uuid.c_str())) {
166     cerr << "error: unable to parse uuid" << std::endl;
167     return -EINVAL;
168   }
169   if (fsid != existing) {
170     cerr << "error: cluster_uuid " << existing << " != " << fsid << std::endl;
171     return -EEXIST;
172   }
173   return 0;
174 }
175
176 // rebuild
177 //  - monitor/cluster_uuid
178 int update_monitor(const OSDSuperblock& sb, MonitorDBStore& ms)
179 {
180   switch (check_fsid(sb.cluster_fsid, ms)) {
181   case -ENOENT:
182     break;
183   case -EINVAL:
184     return -EINVAL;
185   case -EEXIST:
186     return -EEXIST;
187   case 0:
188     return 0;
189   default:
190     ceph_abort();
191   }
192   string uuid = stringify(sb.cluster_fsid) + "\n";
193   bufferlist bl;
194   bl.append(uuid);
195   auto t = make_shared<MonitorDBStore::Transaction>();
196   t->put("monitor", "cluster_uuid", bl);
197   ms.apply_transaction(t);
198   return 0;
199 }
200
201 // rebuild
202 //  - osdmap/${epoch}
203 //  - osdmap/full_${epoch}
204 //  - osdmap/full_latest
205 //  - osdmap/first_committed
206 //  - osdmap/last_committed
207 int update_osdmap(ObjectStore& fs, OSDSuperblock& sb, MonitorDBStore& ms)
208 {
209   const string prefix("osdmap");
210   const string first_committed_name("first_committed");
211   const string last_committed_name("last_committed");
212   epoch_t first_committed = ms.get(prefix, first_committed_name);
213   epoch_t last_committed = ms.get(prefix, last_committed_name);
214   auto t = make_shared<MonitorDBStore::Transaction>();
215
216   // trim stale maps
217   unsigned ntrimmed = 0;
218   // osdmap starts at 1. if we have a "0" first_committed, then there is nothing
219   // to trim. and "1 osdmaps trimmed" in the output message is misleading. so
220   // let's make it an exception.
221   for (auto e = first_committed; first_committed && e < sb.oldest_map; e++) {
222     t->erase(prefix, e);
223     t->erase(prefix, ms.combine_strings("full", e));
224     ntrimmed++;
225   }
226   // make sure we have a non-zero first_committed. OSDMonitor relies on this.
227   // because PaxosService::put_last_committed() set it to last_committed, if it
228   // is zero. which breaks OSDMonitor::update_from_paxos(), in which we believe
229   // that latest_full should always be greater than last_committed.
230   if (first_committed == 0 && sb.oldest_map < sb.newest_map) {
231     first_committed = 1;
232   } else if (ntrimmed) {
233     first_committed += ntrimmed;
234   }
235   if (first_committed) {
236     t->put(prefix, first_committed_name, first_committed);
237     ms.apply_transaction(t);
238     t = make_shared<MonitorDBStore::Transaction>();
239   }
240
241   unsigned nadded = 0;
242
243   OSDMap osdmap;
244   for (auto e = max(last_committed+1, sb.oldest_map);
245        e <= sb.newest_map; e++) {
246     bool have_crc = false;
247     uint32_t crc = -1;
248     uint64_t features = 0;
249     // add inc maps
250     {
251       const auto oid = OSD::get_inc_osdmap_pobject_name(e);
252       bufferlist bl;
253       int nread = fs.read(coll_t::meta(), oid, 0, 0, bl);
254       if (nread <= 0) {
255         cerr << "missing " << oid << std::endl;
256         return -EINVAL;
257       }
258       t->put(prefix, e, bl);
259
260       OSDMap::Incremental inc;
261       auto p = bl.begin();
262       inc.decode(p);
263       features = inc.encode_features | CEPH_FEATURE_RESERVED;
264       if (osdmap.get_epoch() && e > 1) {
265         if (osdmap.apply_incremental(inc)) {
266           cerr << "bad fsid: "
267                << osdmap.get_fsid() << " != " << inc.fsid << std::endl;
268           return -EINVAL;
269         }
270         have_crc = inc.have_crc;
271         if (inc.have_crc) {
272           crc = inc.full_crc;
273           bufferlist fbl;
274           osdmap.encode(fbl, features);
275           if (osdmap.get_crc() != inc.full_crc) {
276             cerr << "mismatched inc crc: "
277                  << osdmap.get_crc() << " != " << inc.full_crc << std::endl;
278             return -EINVAL;
279           }
280           // inc.decode() verifies `inc_crc`, so it's been taken care of.
281         }
282       }
283     }
284     // add full maps
285     {
286       const auto oid = OSD::get_osdmap_pobject_name(e);
287       bufferlist bl;
288       int nread = fs.read(coll_t::meta(), oid, 0, 0, bl);
289       if (nread <= 0) {
290         cerr << "missing " << oid << std::endl;
291         return -EINVAL;
292       }
293       t->put(prefix, ms.combine_strings("full", e), bl);
294
295       auto p = bl.begin();
296       osdmap.decode(p);
297       if (osdmap.have_crc()) {
298         if (have_crc && osdmap.get_crc() != crc) {
299           cerr << "mismatched full/inc crc: "
300                << osdmap.get_crc() << " != " << crc << std::endl;
301           return -EINVAL;
302         }
303         uint32_t saved_crc = osdmap.get_crc();
304         bufferlist fbl;
305         osdmap.encode(fbl, features);
306         if (osdmap.get_crc() != saved_crc) {
307           cerr << "mismatched full crc: "
308                << saved_crc << " != " << osdmap.get_crc() << std::endl;
309           return -EINVAL;
310         }
311       }
312     }
313     nadded++;
314
315     // last_committed
316     t->put(prefix, last_committed_name, e);
317     // full last
318     t->put(prefix, ms.combine_strings("full", "latest"), e);
319
320     // this number comes from the default value of osd_target_transaction_size,
321     // so we won't OOM or stuff too many maps in a single transaction if OSD is
322     // keeping a large series of osdmap
323     static constexpr unsigned TRANSACTION_SIZE = 30;
324     if (t->size() >= TRANSACTION_SIZE) {
325       ms.apply_transaction(t);
326       t = make_shared<MonitorDBStore::Transaction>();
327     }
328   }
329   if (!t->empty()) {
330     ms.apply_transaction(t);
331   }
332   t.reset();
333
334   string osd_name("osd.");
335   osd_name += std::to_string(sb.whoami);
336   cout << std::left << setw(8)
337        << osd_name << ": "
338        << ntrimmed << " osdmaps trimmed, "
339        << nadded << " osdmaps added." << std::endl;
340   return 0;
341 }
342
343 // rebuild
344 //  - pgmap_pg/${pgid}
345 int update_pgmap_pg(ObjectStore& fs, MonitorDBStore& ms)
346 {
347   // pgmap/${epoch} is the incremental of: stamp, pgmap_pg, pgmap_osd
348   // if PGMonitor fails to read it, it will fall back to the pgmap_pg, i.e.
349   // the fullmap.
350   vector<coll_t> collections;
351   int r = fs.list_collections(collections);
352   if (r < 0) {
353     cerr << "failed to list pgs: "  << cpp_strerror(r) << std::endl;
354     return r;
355   }
356   const string prefix("pgmap_pg");
357   // in general, there are less than 100 PGs per OSD, so no need to apply
358   // transaction in batch.
359   auto t = make_shared<MonitorDBStore::Transaction>();
360   unsigned npg = 0;
361   for (const auto& coll : collections) {
362     spg_t pgid;
363     if (!coll.is_pg(&pgid))
364       continue;
365     bufferlist bl;
366     pg_info_t info(pgid);
367     PastIntervals past_intervals;
368     __u8 struct_v;
369     r = PG::read_info(&fs, pgid, coll, bl, info, past_intervals, struct_v);
370     if (r < 0) {
371       cerr << "failed to read_info: " << cpp_strerror(r) << std::endl;
372       return r;
373     }
374     if (struct_v < PG::cur_struct_v) {
375       cerr << "incompatible pg_info: v" << struct_v << std::endl;
376       return -EINVAL;
377     }
378     version_t latest_epoch = 0;
379     r = ms.get(prefix, stringify(pgid.pgid), bl);
380     if (r >= 0) {
381       pg_stat_t pg_stat;
382       auto bp = bl.begin();
383       ::decode(pg_stat, bp);
384       latest_epoch = pg_stat.reported_epoch;
385     }
386     if (info.stats.reported_epoch > latest_epoch) {
387       bufferlist bl;
388       ::encode(info.stats, bl);
389       t->put(prefix, stringify(pgid.pgid), bl);
390       npg++;
391     }
392   }
393   ms.apply_transaction(t);
394   cout << std::left << setw(10)
395        << " " << npg << " pgs added." << std::endl;
396   return 0;
397 }