]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
mon/ConfigMonitor: "ceph config assimilate-conf"
authorSage Weil <sage@redhat.com>
Sat, 6 Jan 2018 17:19:43 +0000 (11:19 -0600)
committerSage Weil <sage@redhat.com>
Tue, 6 Mar 2018 20:44:48 +0000 (14:44 -0600)
Inject as much of a ceph.conf file as we can; spit we can't take back out
to stdout.

Signed-off-by: Sage Weil <sage@redhat.com>
src/mon/ConfigMap.h
src/mon/ConfigMonitor.cc
src/mon/MonCommands.h

index 60cdc68d02a830e89c10ea6336111ee6776d47ca..02b4d9d9e7c57e94f412bc7a3ae2af49ae2e6155 100644 (file)
@@ -92,6 +92,20 @@ struct ConfigMap {
   std::map<std::string,Section> by_type;
   std::map<std::string,Section> by_id;
 
+  Section *find_section(const std::string& name) {
+    if (name == "global") {
+      return &global;
+    }
+    auto i = by_type.find(name);
+    if (i != by_type.end()) {
+      return &i->second;
+    }
+    i = by_id.find(name);
+    if (i != by_id.end()) {
+      return &i->second;
+    }
+    return nullptr;
+  }
   void clear() {
     global.clear();
     by_type.clear();
index 78e27ae56efe4c69aedea95c58cea10e9ff08991..a4a1921ccc3ca332a7ba78995fbd532eefcd95df 100644 (file)
@@ -300,6 +300,7 @@ bool ConfigMonitor::prepare_command(MonOpRequestRef op)
 
   string prefix;
   cmd_getval(g_ceph_context, cmdmap, "prefix", prefix);
+  bufferlist odata;
 
   if (prefix == "config set" ||
       prefix == "config rm") {
@@ -336,13 +337,92 @@ bool ConfigMonitor::prepare_command(MonOpRequestRef op)
       pending[key] = boost::none;
     }
     goto update;
+  } else if (prefix == "config assimilate-conf") {
+    ConfFile cf;
+    deque<string> errors;
+    bufferlist bl = m->get_data();
+    err = cf.parse_bufferlist(&bl, &errors, &ss);
+    if (err < 0) {
+      ss << "parse errors: " << errors;
+      goto reply;
+    }
+    bool updated = false;
+    ostringstream newconf;
+    for (auto i = cf.sections_begin(); i != cf.sections_end(); ++i) {
+      string section = i->first;
+      const ConfSection& s = i->second;
+      dout(20) << __func__ << " [" << section << "]" << dendl;
+      bool did_section = false;
+      for (auto& j : s.lines) {
+       Option::value_t real_value;
+       string value;
+       string errstr;
+       if (!j.key.size()) {
+         continue;
+       }
+       // a known and worthy option?
+       const Option *o = g_conf->find_option(j.key);
+       if (!o ||
+           o->flags & Option::FLAG_NO_MON_UPDATE) {
+         goto skip;
+       }
+       // normalize
+       err = o->parse_value(j.val, &real_value, &errstr, &value);
+       if (err < 0) {
+         dout(20) << __func__ << " failed to parse " << j.key << " = '"
+                  << j.val << "'" << dendl;
+         goto skip;
+       }
+       // does it conflict with an existing value?
+       {
+         const Section *s = config_map.find_section(section);
+         if (s) {
+           auto k = s->options.find(j.key);
+           if (k != s->options.end()) {
+             if (value != k->second.raw_value) {
+               dout(20) << __func__ << " have " << j.key
+                        << " = " << k->second.raw_value
+                        << " (not " << value << ")" << dendl;
+               goto skip;
+             }
+             dout(20) << __func__ << " already have " << j.key
+                      << " = " << k->second.raw_value << dendl;
+             continue;
+           }
+         }
+       }
+       dout(20) << __func__ << "  add " << j.key << " = " << value
+                << " (" << j.val << ")" << dendl;
+       {
+         string key = section + "/" + j.key;
+         bufferlist bl;
+         bl.append(value);
+         pending[key] = bl;
+         updated = true;
+       }
+       continue;
+
+       skip:
+       dout(20) << __func__ << " skip " << j.key << " = " << value
+                << " (" << j.val << ")" << dendl;
+       if (!did_section) {
+         newconf << "\n[" << section << "]\n";
+         did_section = true;
+       }
+       newconf << "\t" << j.key << " = " << j.val << "\n";
+      }
+    }
+    odata.append(newconf.str());
+    if (updated) {
+      goto update;
+    }
   } else {
     ss << "unknown command " << prefix;
     err = -EINVAL;
   }
 
 reply:
-  mon->reply_command(op, err, ss.str(), get_last_committed());
+  mon->reply_command(op, err, ss.str(), odata, get_last_committed());
   return false;
 
 update:
@@ -350,7 +430,7 @@ update:
   wait_for_finished_proposal(
     op,
     new Monitor::C_Command(
-      mon, op, 0, ss.str(),
+      mon, op, 0, ss.str(), odata,
       get_last_committed() + 1));
   return true;
 }
index ad6048d5d74280cb4f7d3b60e022458f5db51958..51ec38d9aca13bb09f6da4d49f1496472c0691d5 100644 (file)
@@ -1114,3 +1114,6 @@ COMMAND("config help " \
        "name=key,type=CephString",
        "Describe a configuration option",
        "config", "r", "cli,rest")
+COMMAND("config assimilate-conf",
+       "Assimilate options from a conf, and return a new, minimal conf file",
+       "config", "rw", "cli,rest")