Record predicted device failure time.
Signed-off-by: Sage Weil <sage@redhat.com>
cmd_getval(g_ceph_context, cmdctx->cmdmap, "devid", devid);
int r = 0;
ostringstream rs;
- if (!daemon_state.with_device(devid, [&f, &rs] (const DeviceState& dev) {
+ if (!daemon_state.with_device(devid,
+ [&f, &rs] (const DeviceState& dev) {
if (f) {
f->open_object_section("device");
f->dump_string("devid", dev.devid);
f->dump_string("daemon", to_string(i));
}
f->close_section();
+ if (dev.expected_failure != utime_t()) {
+ f->dump_stream("expected_failure") << dev.expected_failure;
+ f->dump_stream("expected_failure_stamp")
+ << dev.expected_failure_stamp;
+ }
f->close_section();
} else {
rs << "device " << dev.devid << "\n";
rs << "host " << dev.server << "\n";
- rs << "daemons " << dev.daemons << "\n";
+ set<string> d;
+ for (auto& j : dev.daemons) {
+ d.insert(to_string(j));
+ }
+ rs << "daemons " << d << "\n";
+ if (dev.expected_failure != utime_t()) {
+ rs << "expected_failure " << dev.expected_failure
+ << " (as of " << dev.expected_failure_stamp << ")\n";
+ }
}
})) {
ss << "device " << devid << " not found";
}
cmdctx->reply(r, ss);
return true;
+ } else if (prefix == "device set-predicted-failure") {
+ string devid;
+ cmd_getval(g_ceph_context, cmdctx->cmdmap, "devid", devid);
+ string when_str;
+ cmd_getval(g_ceph_context, cmdctx->cmdmap, "when", when_str);
+ utime_t when;
+ if (!when.parse(when_str)) {
+ ss << "unable to parse datetime '" << when_str << "'";
+ r = -EINVAL;
+ cmdctx->reply(r, ss);
+ } else {
+ map<string,string> meta;
+ daemon_state.with_device_create(devid, [when, &meta] (DeviceState& dev) {
+ dev.set_expected_failure(when, ceph_clock_now());
+ meta = dev.metadata;
+ });
+ json_spirit::Object json_object;
+ for (auto& i : meta) {
+ json_spirit::Config::add(json_object, i.first, i.second);
+ }
+ bufferlist json;
+ json.append(json_spirit::write(json_object));
+ const string cmd =
+ "{"
+ "\"prefix\": \"config-key set\", "
+ "\"key\": \"device/" + devid + "\""
+ "}";
+ auto on_finish = new ReplyOnFinish(cmdctx);
+ monc->start_mon_command({cmd}, json, nullptr, nullptr, on_finish);
+ }
+ return true;
+ } else if (prefix == "device rm-predicted-failure") {
+ string devid;
+ cmd_getval(g_ceph_context, cmdctx->cmdmap, "devid", devid);
+ map<string,string> meta;
+ if (daemon_state.with_device_write(devid, [&meta] (DeviceState& dev) {
+ dev.rm_expected_failure();
+ meta = dev.metadata;
+ })) {
+ string cmd;
+ bufferlist json;
+ if (meta.empty()) {
+ cmd =
+ "{"
+ "\"prefix\": \"config-key rm\", "
+ "\"key\": \"device/" + devid + "\""
+ "}";
+ } else {
+ json_spirit::Object json_object;
+ for (auto& i : meta) {
+ json_spirit::Config::add(json_object, i.first, i.second);
+ }
+ json.append(json_spirit::write(json_object));
+ cmd =
+ "{"
+ "\"prefix\": \"config-key set\", "
+ "\"key\": \"device/" + devid + "\""
+ "}";
+ }
+ auto on_finish = new ReplyOnFinish(cmdctx);
+ monc->start_mon_command({cmd}, json, nullptr, nullptr, on_finish);
+ } else {
+ cmdctx->reply(0, ss);
+ }
+ return true;
} else {
// fall back to feeding command to PGMap
r = cluster_state.with_pgmap([&](const PGMap& pg_map) {
#include "DaemonState.h"
#include "MgrSession.h"
+#include "include/stringify.h"
#define dout_context g_ceph_context
#define dout_subsys ceph_subsys_mgr
#undef dout_prefix
#define dout_prefix *_dout << "mgr " << __func__ << " "
+void DeviceState::set_metadata(map<string,string>&& m)
+{
+ metadata = std::move(m);
+ auto p = metadata.find("expected_failure");
+ if (p != metadata.end()) {
+ expected_failure.parse(p->second);
+ }
+ p = metadata.find("expected_failure_stamp");
+ if (p != metadata.end()) {
+ expected_failure_stamp.parse(p->second);
+ }
+}
+
+void DeviceState::set_expected_failure(utime_t when, utime_t now)
+{
+ expected_failure = when;
+ expected_failure_stamp = now;
+ metadata["expected_failure"] = stringify(expected_failure);
+ metadata["expected_failure_stamp"] = stringify(expected_failure_stamp);
+}
+
+void DeviceState::rm_expected_failure()
+{
+ expected_failure = utime_t();
+ expected_failure_stamp = utime_t();
+ metadata.erase("expected_failure");
+ metadata.erase("expected_failure_stamp");
+}
+
void DaemonStateIndex::insert(DaemonStatePtr dm)
{
RWLock::WLocker l(lock);
std::map<string,string> metadata; ///< persistent metadata
+ utime_t expected_failure; ///< when device failure is expected
+ utime_t expected_failure_stamp; ///< when expected_failure was recorded
+
DeviceState(const std::string& n) : devid(n) {}
void set_metadata(map<string,string>&& m);
+ void set_expected_failure(utime_t when, utime_t now);
+ void rm_expected_failure();
+
/// true of we can be safely forgotten/removed from memory
bool empty() const {
return daemons.empty() && metadata.empty();
}
template<typename Callback, typename...Args>
- auto with_device(const std::string& dev,
+ bool with_device(const std::string& dev,
Callback&& cb, Args&&... args) const {
RWLock::RLocker l(lock);
auto p = devices.find(dev);
return true;
}
+ template<typename Callback, typename...Args>
+ bool with_device_write(const std::string& dev,
+ Callback&& cb, Args&&... args) {
+ RWLock::WLocker l(lock);
+ auto p = devices.find(dev);
+ if (p == devices.end()) {
+ return false;
+ }
+ std::forward<Callback>(cb)(*p->second, std::forward<Args>(args)...);
+ if (p->second->empty()) {
+ _erase_device(p->second);
+ }
+ return true;
+ }
+
+ template<typename Callback, typename...Args>
+ void with_device_create(const std::string& dev,
+ Callback&& cb, Args&&... args) {
+ RWLock::WLocker l(lock);
+ auto d = _get_or_create_device(dev);
+ std::forward<Callback>(cb)(*d, std::forward<Args>(args)...);
+ }
+
template<typename Callback, typename...Args>
void with_devices(Callback&& cb, Args&&... args) const {
RWLock::RLocker l(lock);
COMMAND("device ls-by-host name=host,type=CephString",
"Show devices on a host",
"mgr", "r", "cli,rest")
+COMMAND("device set-predicted-failure name=devid,type=CephString name=when,type=CephString",
+ "Set predicted device failure time",
+ "mgr", "rw", "cli,rest")
+COMMAND("device rm-predicted-failure name=devid,type=CephString",
+ "Clear predicted device failure time",
+ "mgr", "rw", "cli,rest")