};
+// cct config watcher
+class CephContextObs : public md_config_obs_t {
+ CephContext *cct;
+
+public:
+ CephContextObs(CephContext *cct) : cct(cct) {}
+
+ const char** get_tracked_conf_keys() const {
+ static const char *KEYS[] = {
+ "enable_experimental_unrecoverable_data_corrupting_features",
+ NULL
+ };
+ return KEYS;
+ }
+
+ void handle_conf_change(const md_config_t *conf,
+ const std::set <std::string> &changed) {
+ ceph_spin_lock(&cct->_feature_lock);
+ get_str_set(conf->enable_experimental_unrecoverable_data_corrupting_features,
+ cct->_experimental_features);
+ ceph_spin_unlock(&cct->_feature_lock);
+ }
+};
+
+bool CephContext::check_experimental_feature_enabled(std::string feat)
+{
+ ceph_spin_lock(&_feature_lock);
+ bool enabled = _experimental_features.count(feat);
+ ceph_spin_unlock(&_feature_lock);
+
+ if (enabled) {
+ lderr(this) << "WARNING: experimental feature '" << feat << "' is enabled" << dendl;
+ lderr(this) << "Please be aware that this feature is experimental, untested," << dendl;
+ lderr(this) << "unsupported, and may result in data corruption, data loss," << dendl;
+ lderr(this) << "and/or irreparable damage to your cluster. Do not use" << dendl;
+ lderr(this) << "feature with important data." << dendl;
+ } else {
+ lderr(this) << "*** experimental feature '" << feat << "' is not enabled ***" << dendl;
+ lderr(this) << "This feature is marked as experimental, which means it" << dendl;
+ lderr(this) << " - is untested" << dendl;
+ lderr(this) << " - is unsupported" << dendl;
+ lderr(this) << " - may corrupt your data" << dendl;
+ lderr(this) << " - may break your cluster is an unrecoverable fashion" << dendl;
+ lderr(this) << "To enable this feature, add this to your ceph.conf:" << dendl;
+ lderr(this) << " enable experimental unrecoverable data corrupting features = " << feat << dendl;
+ }
+ return enabled;
+}
+
// perfcounter hooks
class CephContextHook : public AdminSocketHook {
{
ceph_spin_init(&_service_thread_lock);
ceph_spin_init(&_associated_objs_lock);
+ ceph_spin_init(&_feature_lock);
_log = new ceph::log::Log(&_conf->subsys);
_log->start();
_log_obs = new LogObs(_log);
_conf->add_observer(_log_obs);
+ _cct_obs = new CephContextObs(this);
+ _conf->add_observer(_cct_obs);
+
_perf_counters_collection = new PerfCountersCollection(this);
_admin_socket = new AdminSocket(this);
_heartbeat_map = new HeartbeatMap(this);
delete _log_obs;
_log_obs = NULL;
+ _conf->remove_observer(_cct_obs);
+ delete _cct_obs;
+ _cct_obs = NULL;
+
_log->stop();
delete _log;
_log = NULL;
delete _conf;
ceph_spin_destroy(&_service_thread_lock);
ceph_spin_destroy(&_associated_objs_lock);
+ ceph_spin_destroy(&_feature_lock);
delete _crypto_none;
delete _crypto_aes;
#include <iostream>
#include <stdint.h>
#include <string>
+#include <set>
#include "include/buffer.h"
#include "include/atomic.h"
class md_config_obs_t;
struct md_config_t;
class CephContextHook;
+class CephContextObs;
class CryptoNone;
class CryptoAES;
class CryptoHandler;
*/
CryptoHandler *get_crypto_handler(int type);
+ /// check if experimental feature is enable, and emit appropriate warnings
+ bool check_experimental_feature_enabled(std::string feature);
+
private:
CephContext(const CephContext &rhs);
CephContext &operator=(const CephContext &rhs);
// crypto
CryptoNone *_crypto_none;
CryptoAES *_crypto_aes;
+
+ // experimental
+ CephContextObs *_cct_obs;
+ ceph_spinlock_t _feature_lock;
+ std::set<std::string> _experimental_features;
+
+ friend class CephContextObs;
};
#endif
#include "include/msgr.h"
#include "common/ceph_context.h"
#include "common/config.h"
+#include "log/Log.h"
TEST(CephContext, do_command)
{
cct->put();
}
+TEST(CephContext, experimental_features)
+{
+ CephContext *cct = (new CephContext(CEPH_ENTITY_TYPE_CLIENT))->get();
+
+ ASSERT_FALSE(cct->check_experimental_feature_enabled("foo"));
+ ASSERT_FALSE(cct->check_experimental_feature_enabled("bar"));
+ ASSERT_FALSE(cct->check_experimental_feature_enabled("baz"));
+
+ cct->_conf->set_val("enable_experimental_unrecoverable_data_corrupting_features",
+ "foo,bar");
+ cct->_conf->apply_changes(&cout);
+ ASSERT_TRUE(cct->check_experimental_feature_enabled("foo"));
+ ASSERT_TRUE(cct->check_experimental_feature_enabled("bar"));
+ ASSERT_FALSE(cct->check_experimental_feature_enabled("baz"));
+
+ cct->_conf->set_val("enable_experimental_unrecoverable_data_corrupting_features",
+ "foo bar");
+ cct->_conf->apply_changes(&cout);
+ ASSERT_TRUE(cct->check_experimental_feature_enabled("foo"));
+ ASSERT_TRUE(cct->check_experimental_feature_enabled("bar"));
+ ASSERT_FALSE(cct->check_experimental_feature_enabled("baz"));
+
+ cct->_conf->set_val("enable_experimental_unrecoverable_data_corrupting_features",
+ "baz foo");
+ cct->_conf->apply_changes(&cout);
+ ASSERT_TRUE(cct->check_experimental_feature_enabled("foo"));
+ ASSERT_FALSE(cct->check_experimental_feature_enabled("bar"));
+ ASSERT_TRUE(cct->check_experimental_feature_enabled("baz"));
+
+ cct->_log->flush();
+}
+
/*
* Local Variables:
* compile-command: "cd ../.. ;