From: Mykola Golub Date: Mon, 19 Jan 2015 14:41:05 +0000 (+0200) Subject: osd: new pool safeguard flags: nodelete, nopgchange, nosizechange X-Git-Tag: v0.93~228^2 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=refs%2Fpull%2F3409%2Fhead;p=ceph.git osd: new pool safeguard flags: nodelete, nopgchange, nosizechange * nodelete - pool can't be deleted * nopgchange - pool's pg and pgp num can't be changed * nosizechange - pool's size and min size can't be changed This is intended to help some poor admin to avoid a very bad day. Fixes: #9792 (but in a different way than it was proposed there) Signed-off-by: Mykola Golub --- diff --git a/doc/rados/operations/pools.rst b/doc/rados/operations/pools.rst index efa75e95fadf..056b43e3e3d2 100644 --- a/doc/rados/operations/pools.rst +++ b/doc/rados/operations/pools.rst @@ -274,6 +274,30 @@ You may set values for the following keys: :Version: Version ``0.48`` Argonaut and above. +``nodelete`` + +:Description: Set/Unset NODELETE flag on a given pool. +:Type: Integer +:Valid Range: 1 sets flag, 0 unsets flag +:Version: Version ``FIXME`` + + +``nopgchange`` + +:Description: Set/Unset NOPGCHANGE flag on a given pool. +:Type: Integer +:Valid Range: 1 sets flag, 0 unsets flag +:Version: Version ``FIXME`` + + +``nosizechange`` + +:Description: Set/Unset NOSIZECHANGE flag on a given pool. +:Type: Integer +:Valid Range: 1 sets flag, 0 unsets flag +:Version: Version ``FIXME`` + + ``hit_set_type`` :Description: Enables hit set tracking for cache pools. diff --git a/qa/workunits/cephtool/test.sh b/qa/workunits/cephtool/test.sh index 09c1086c77f8..ff376a0a7adb 100755 --- a/qa/workunits/cephtool/test.sh +++ b/qa/workunits/cephtool/test.sh @@ -1135,13 +1135,32 @@ function test_mon_osd_pool_set() ceph --format=xml osd pool get $TEST_POOL_GETSET auid | grep $auid ceph osd pool set $TEST_POOL_GETSET auid 0 - ceph osd pool set $TEST_POOL_GETSET hashpspool true - ceph osd pool set $TEST_POOL_GETSET hashpspool false - ceph osd pool set $TEST_POOL_GETSET hashpspool 0 - ceph osd pool set $TEST_POOL_GETSET hashpspool 1 - expect_false ceph osd pool set $TEST_POOL_GETSET hashpspool asdf - expect_false ceph osd pool set $TEST_POOL_GETSET hashpspool 2 + for flag in hashpspool nodelete nopgchange nosizechange; do + ceph osd pool set $TEST_POOL_GETSET $flag false + ceph osd pool set $TEST_POOL_GETSET $flag true + ceph osd pool set $TEST_POOL_GETSET $flag 1 + ceph osd pool set $TEST_POOL_GETSET $flag 0 + expect_false ceph osd pool set $TEST_POOL_GETSET $flag asdf + expect_false ceph osd pool set $TEST_POOL_GETSET $flag 2 + done + ceph osd pool set $TEST_POOL_GETSET nopgchange 1 + expect_false ceph osd pool set $TEST_POOL_GETSET pg_num 10 + expect_false ceph osd pool set $TEST_POOL_GETSET pgp_num 10 + ceph osd pool set $TEST_POOL_GETSET nopgchange 0 + ceph osd pool set $TEST_POOL_GETSET pg_num 10 + ceph osd pool set $TEST_POOL_GETSET pgp_num 10 + + ceph osd pool set $TEST_POOL_GETSET nosizechange 1 + expect_false ceph osd pool set $TEST_POOL_GETSET size 2 + expect_false ceph osd pool set $TEST_POOL_GETSET min_size 2 + ceph osd pool set $TEST_POOL_GETSET nosizechange 0 + ceph osd pool set $TEST_POOL_GETSET size 2 + ceph osd pool set $TEST_POOL_GETSET min_size 2 + + ceph osd pool set $TEST_POOL_GETSET nodelete 1 + expect_false ceph osd pool delete $TEST_POOL_GETSET $TEST_POOL_GETSET --yes-i-really-really-mean-it + ceph osd pool set $TEST_POOL_GETSET nodelete 0 ceph osd pool delete $TEST_POOL_GETSET $TEST_POOL_GETSET --yes-i-really-really-mean-it ceph osd pool get rbd crush_ruleset | grep 'crush_ruleset: 0' diff --git a/src/common/config_opts.h b/src/common/config_opts.h index eb84ac6e9882..fb27e93c8637 100644 --- a/src/common/config_opts.h +++ b/src/common/config_opts.h @@ -497,6 +497,9 @@ OPTION(osd_erasure_code_plugins, OPT_STR, ) // list of erasure code plugins OPTION(osd_pool_default_flags, OPT_INT, 0) // default flags for new pools OPTION(osd_pool_default_flag_hashpspool, OPT_BOOL, true) // use new pg hashing to prevent pool/pg overlap +OPTION(osd_pool_default_flag_nodelete, OPT_BOOL, false) // pool can't be deleted +OPTION(osd_pool_default_flag_nopgchange, OPT_BOOL, false) // pool's pg and pgp num can't be changed +OPTION(osd_pool_default_flag_nosizechange, OPT_BOOL, false) // pool's size and min size can't be changed OPTION(osd_pool_default_hit_set_bloom_fpp, OPT_FLOAT, .05) OPTION(osd_pool_default_cache_target_dirty_ratio, OPT_FLOAT, .4) OPTION(osd_pool_default_cache_target_full_ratio, OPT_FLOAT, .8) diff --git a/src/mon/MonCommands.h b/src/mon/MonCommands.h index 6292e302d6ac..6da1ef6a30e7 100644 --- a/src/mon/MonCommands.h +++ b/src/mon/MonCommands.h @@ -606,7 +606,7 @@ COMMAND("osd pool get " \ "get pool parameter ", "osd", "r", "cli,rest") COMMAND("osd pool set " \ "name=pool,type=CephPoolname " \ - "name=var,type=CephChoices,strings=size|min_size|crash_replay_interval|pg_num|pgp_num|crush_ruleset|hashpspool|hit_set_type|hit_set_period|hit_set_count|hit_set_fpp|debug_fake_ec_pool|target_max_bytes|target_max_objects|cache_target_dirty_ratio|cache_target_full_ratio|cache_min_flush_age|cache_min_evict_age|auid|min_read_recency_for_promote " \ + "name=var,type=CephChoices,strings=size|min_size|crash_replay_interval|pg_num|pgp_num|crush_ruleset|hashpspool|nodelete|nopgchange|nosizechange|hit_set_type|hit_set_period|hit_set_count|hit_set_fpp|debug_fake_ec_pool|target_max_bytes|target_max_objects|cache_target_dirty_ratio|cache_target_full_ratio|cache_min_flush_age|cache_min_evict_age|auid|min_read_recency_for_promote " \ "name=val,type=CephString " \ "name=force,type=CephChoices,strings=--yes-i-really-mean-it,req=false", \ "set pool parameter to ", "osd", "rw", "cli,rest") diff --git a/src/mon/OSDMonitor.cc b/src/mon/OSDMonitor.cc index 10e49a17c7f0..b205deef7769 100644 --- a/src/mon/OSDMonitor.cc +++ b/src/mon/OSDMonitor.cc @@ -3689,7 +3689,13 @@ int OSDMonitor::prepare_new_pool(string& name, uint64_t auid, pi->type = pool_type; pi->flags = g_conf->osd_pool_default_flags; if (g_conf->osd_pool_default_flag_hashpspool) - pi->flags |= pg_pool_t::FLAG_HASHPSPOOL; + pi->set_flag(pg_pool_t::FLAG_HASHPSPOOL); + if (g_conf->osd_pool_default_flag_nodelete) + pi->set_flag(pg_pool_t::FLAG_NODELETE); + if (g_conf->osd_pool_default_flag_nopgchange) + pi->set_flag(pg_pool_t::FLAG_NOPGCHANGE); + if (g_conf->osd_pool_default_flag_nosizechange) + pi->set_flag(pg_pool_t::FLAG_NOSIZECHANGE); pi->size = size; pi->min_size = min_size; @@ -3836,6 +3842,10 @@ int OSDMonitor::prepare_command_pool_set(map &cmdmap, } if (var == "size") { + if (p.has_flag(pg_pool_t::FLAG_NOSIZECHANGE)) { + ss << "pool size change is disabled; you must unset nosizechange flag for the pool first"; + return -EPERM; + } if (p.type == pg_pool_t::TYPE_ERASURE) { ss << "can not change the size of an erasure-coded pool"; return -ENOTSUP; @@ -3852,6 +3862,10 @@ int OSDMonitor::prepare_command_pool_set(map &cmdmap, if (n < p.min_size) p.min_size = n; } else if (var == "min_size") { + if (p.has_flag(pg_pool_t::FLAG_NOSIZECHANGE)) { + ss << "pool min size change is disabled; you must unset nosizechange flag for the pool first"; + return -EPERM; + } if (interr.length()) { ss << "error parsing integer value '" << val << "': " << interr; return -EINVAL; @@ -3893,6 +3907,10 @@ int OSDMonitor::prepare_command_pool_set(map &cmdmap, } p.crash_replay_interval = n; } else if (var == "pg_num") { + if (p.has_flag(pg_pool_t::FLAG_NOPGCHANGE)) { + ss << "pool pg_num change is disabled; you must unset nopgchange flag for the pool first"; + return -EPERM; + } if (interr.length()) { ss << "error parsing integer value '" << val << "': " << interr; return -EINVAL; @@ -3930,6 +3948,10 @@ int OSDMonitor::prepare_command_pool_set(map &cmdmap, } p.set_pg_num(n); } else if (var == "pgp_num") { + if (p.has_flag(pg_pool_t::FLAG_NOPGCHANGE)) { + ss << "pool pgp_num change is disabled; you must unset nopgchange flag for the pool first"; + return -EPERM; + } if (interr.length()) { ss << "error parsing integer value '" << val << "': " << interr; return -EINVAL; @@ -3961,12 +3983,14 @@ int OSDMonitor::prepare_command_pool_set(map &cmdmap, return -ENOENT; } p.crush_ruleset = n; - } else if (var == "hashpspool") { + } else if (var == "hashpspool" || var == "nodelete" || var == "nopgchange" || + var == "nosizechange") { + uint64_t flag = pg_pool_t::get_flag_by_name(var); // make sure we only compare against 'n' if we didn't receive a string if (val == "true" || (interr.empty() && n == 1)) { - p.flags |= pg_pool_t::FLAG_HASHPSPOOL; + p.set_flag(flag); } else if (val == "false" || (interr.empty() && n == 0)) { - p.flags &= ~pg_pool_t::FLAG_HASHPSPOOL; + p.unset_flag(flag); } else { ss << "expecting value 'true', 'false', '0', or '1'"; return -EINVAL; @@ -6483,6 +6507,11 @@ int OSDMonitor::_check_remove_pool(int64_t pool, const pg_pool_t *p, return -EPERM; } + if (p->has_flag(pg_pool_t::FLAG_NODELETE)) { + *ss << "pool deletion is disabled; you must unset nodelete flag for the pool first"; + return -EPERM; + } + *ss << "pool '" << poolstr << "' removed"; return 0; } diff --git a/src/osd/OSDMap.cc b/src/osd/OSDMap.cc index 5a9370802f4a..9a1ff2ee2f76 100644 --- a/src/osd/OSDMap.cc +++ b/src/osd/OSDMap.cc @@ -2695,7 +2695,13 @@ int OSDMap::build_simple(CephContext *cct, epoch_t e, uuid_d &fsid, pools[pool].type = pg_pool_t::TYPE_REPLICATED; pools[pool].flags = cct->_conf->osd_pool_default_flags; if (cct->_conf->osd_pool_default_flag_hashpspool) - pools[pool].flags |= pg_pool_t::FLAG_HASHPSPOOL; + pools[pool].set_flag(pg_pool_t::FLAG_HASHPSPOOL); + if (cct->_conf->osd_pool_default_flag_nodelete) + pools[pool].set_flag(pg_pool_t::FLAG_NODELETE); + if (cct->_conf->osd_pool_default_flag_nopgchange) + pools[pool].set_flag(pg_pool_t::FLAG_NOPGCHANGE); + if (cct->_conf->osd_pool_default_flag_nosizechange) + pools[pool].set_flag(pg_pool_t::FLAG_NOSIZECHANGE); pools[pool].size = cct->_conf->osd_pool_default_size; pools[pool].min_size = cct->_conf->get_osd_pool_default_min_size(); pools[pool].crush_ruleset = default_replicated_ruleset; diff --git a/src/osd/osd_types.h b/src/osd/osd_types.h index 7b814c59a49d..7810bce69669 100644 --- a/src/osd/osd_types.h +++ b/src/osd/osd_types.h @@ -822,6 +822,9 @@ struct pg_pool_t { FLAG_FULL = 1<<1, // pool is full FLAG_DEBUG_FAKE_EC_POOL = 1<<2, // require ReplicatedPG to act like an EC pg FLAG_INCOMPLETE_CLONES = 1<<3, // may have incomplete clones (bc we are/were an overlay) + FLAG_NODELETE = 1<<4, // pool can't be deleted + FLAG_NOPGCHANGE = 1<<5, // pool's pg and pgp num can't be changed + FLAG_NOSIZECHANGE = 1<<6, // pool's size and min size can't be changed }; static const char *get_flag_name(int f) { @@ -830,6 +833,9 @@ struct pg_pool_t { case FLAG_FULL: return "full"; case FLAG_DEBUG_FAKE_EC_POOL: return "require_local_rollback"; case FLAG_INCOMPLETE_CLONES: return "incomplete_clones"; + case FLAG_NODELETE: return "nodelete"; + case FLAG_NOPGCHANGE: return "nopgchange"; + case FLAG_NOSIZECHANGE: return "nosizechange"; default: return "???"; } } @@ -847,6 +853,23 @@ struct pg_pool_t { string get_flags_string() const { return get_flags_string(flags); } + static uint64_t get_flag_by_name(const string& name) { + if (name == "hashpspool") + return FLAG_HASHPSPOOL; + if (name == "full") + return FLAG_FULL; + if (name == "require_local_rollback") + return FLAG_DEBUG_FAKE_EC_POOL; + if (name == "incomplete_clones") + return FLAG_INCOMPLETE_CLONES; + if (name == "nodelete") + return FLAG_NODELETE; + if (name == "nopgchange") + return FLAG_NOPGCHANGE; + if (name == "nosizechange") + return FLAG_NOSIZECHANGE; + return 0; + } typedef enum { CACHEMODE_NONE = 0, ///< no caching @@ -1020,6 +1043,8 @@ public: uint64_t get_flags() const { return flags; } bool has_flag(uint64_t f) const { return flags & f; } + void set_flag(uint64_t f) { flags |= f; } + void unset_flag(uint64_t f) { flags &= ~f; } /// This method will later return true for ec pools as well bool ec_pool() const { diff --git a/src/test/mon/misc.sh b/src/test/mon/misc.sh index 04fb188d5914..0351bd48a79a 100755 --- a/src/test/mon/misc.sh +++ b/src/test/mon/misc.sh @@ -40,19 +40,27 @@ function run() { TEST_POOL=rbd function TEST_osd_pool_get_set() { - local dir=$1 - ./ceph osd dump | grep 'pool 0' | grep hashpspool || return 1 - ./ceph osd pool set $TEST_POOL hashpspool 0 || return 1 - ! ./ceph osd dump | grep 'pool 0' | grep hashpspool || return 1 - ./ceph osd pool set $TEST_POOL hashpspool 1 || return 1 - ./ceph osd dump | grep 'pool 0' | grep hashpspool || return 1 - ./ceph osd pool set $TEST_POOL hashpspool false || return 1 - ! ./ceph osd dump | grep 'pool 0' | grep hashpspool || return 1 - ./ceph osd pool set $TEST_POOL hashpspool false || return 1 - # check that setting false twice does not toggle to true (bug) - ! ./ceph osd dump | grep 'pool 0' | grep hashpspool || return 1 - ./ceph osd pool set $TEST_POOL hashpspool true || return 1 - ./ceph osd dump | grep 'pool 0' | grep hashpspool || return 1 + local dir=$1 flag + for flag in hashpspool nodelete nopgchange nosizechange; do + if [ $flag = hashpspool ]; then + ./ceph osd dump | grep 'pool 0' | grep $flag || return 1 + else + ! ./ceph osd dump | grep 'pool 0' | grep $flag || return 1 + fi + ./ceph osd pool set $TEST_POOL $flag 0 || return 1 + ! ./ceph osd dump | grep 'pool 0' | grep $flag || return 1 + ./ceph osd pool set $TEST_POOL $flag 1 || return 1 + ./ceph osd dump | grep 'pool 0' | grep $flag || return 1 + ./ceph osd pool set $TEST_POOL $flag false || return 1 + ! ./ceph osd dump | grep 'pool 0' | grep $flag || return 1 + ./ceph osd pool set $TEST_POOL $flag false || return 1 + # check that setting false twice does not toggle to true (bug) + ! ./ceph osd dump | grep 'pool 0' | grep $flag || return 1 + ./ceph osd pool set $TEST_POOL $flag true || return 1 + ./ceph osd dump | grep 'pool 0' | grep $flag || return 1 + # cleanup + ./ceph osd pool set $TEST_POOL $flag 0 || return 1 + done local size=$(./ceph osd pool get $TEST_POOL size|awk '{print $2}') local min_size=$(./ceph osd pool get $TEST_POOL min_size|awk '{print $2}')