]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
osd: new pool safeguard flags: nodelete, nopgchange, nosizechange 3409/head
authorMykola Golub <mgolub@mirantis.com>
Mon, 19 Jan 2015 14:41:05 +0000 (16:41 +0200)
committerMykola Golub <mgolub@mirantis.com>
Mon, 19 Jan 2015 19:50:28 +0000 (21:50 +0200)
* 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 <mgolub@mirantis.com>
doc/rados/operations/pools.rst
qa/workunits/cephtool/test.sh
src/common/config_opts.h
src/mon/MonCommands.h
src/mon/OSDMonitor.cc
src/osd/OSDMap.cc
src/osd/osd_types.h
src/test/mon/misc.sh

index efa75e95fadf187e0365e49244a0a74a9c6c93c1..056b43e3e3d2a05b4c44c178a993ae1d5de5b26f 100644 (file)
@@ -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.
index 09c1086c77f8463520212abfaaec33240863a214..ff376a0a7adbaf7b076293e85f94a8553329d66b 100755 (executable)
@@ -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'
index eb84ac6e9882a2cab4a0c4f36d10ec23aacecad8..fb27e93c8637fbe849f5ab1531242243a7062250 100644 (file)
@@ -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)
index 6292e302d6ac1ff9fac1696103be1bc2a2df7385..6da1ef6a30e717c87eba69bdddad133c15267e45 100644 (file)
@@ -606,7 +606,7 @@ COMMAND("osd pool get " \
        "get pool parameter <var>", "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 <var> to <val>", "osd", "rw", "cli,rest")
index 10e49a17c7f02d95a4fe35ac67cb5cd9ae141a00..b205deef77695042e1fbd58027e05d8a8db399d6 100644 (file)
@@ -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<string,cmd_vartype> &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<string,cmd_vartype> &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<string,cmd_vartype> &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<string,cmd_vartype> &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<string,cmd_vartype> &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;
 }
index 5a9370802f4a7ab2f2536709c82a2e713fe6a07e..9a1ff2ee2f76dc64990aa09a6d92493e9101113b 100644 (file)
@@ -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;
index 7b814c59a49dbc196a75b25932d8df0c738e4522..7810bce69669091a245456dadf09520cda02b8b5 100644 (file)
@@ -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 {
index 04fb188d5914ab8d5a1e2f2bfebe06ea75bb189d..0351bd48a79a8427120b063c0d9bc97f18a5e312 100755 (executable)
@@ -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}')