"set new maximum osd value", "osd", "rw", "cli,rest")
COMMAND("osd pause", "pause osd", "osd", "rw", "cli,rest")
COMMAND("osd unpause", "unpause osd", "osd", "rw", "cli,rest")
+COMMAND("osd erasure-code-profile set " \
+ "name=name,type=CephString,goodchars=[A-Za-z0-9-_.] " \
+ "name=profile,type=CephString,n=N,req=false,goodchars=[A-Za-z0-9-_.=]", \
+ "create erasure code profile <name> with [<key[=value]> ...] pairs. Add a --force at the end to override an existing profile (VERY DANGEROUS)", \
+ "osd", "rw", "cli,rest")
+COMMAND("osd erasure-code-profile get " \
+ "name=name,type=CephString,goodchars=[A-Za-z0-9-_.]", \
+ "get erasure code profile <name>", \
+ "osd", "r", "cli,rest")
+COMMAND("osd erasure-code-profile rm " \
+ "name=name,type=CephString,goodchars=[A-Za-z0-9-_.]", \
+ "remove erasure code profile <name>", \
+ "osd", "rw", "cli,rest")
+COMMAND("osd erasure-code-profile ls", \
+ "list all erasure code profiles", \
+ "osd", "r", "cli,rest")
COMMAND("osd set " \
"name=key,type=CephChoices,strings=pause|noup|nodown|noout|noin|nobackfill|norecover|noscrub|nodeep-scrub|notieragent", \
"set <key>", "osd", "rw", "cli,rest")
f->flush(rs);
rs << "\n";
rdata.append(rs.str());
+ } else if (prefix == "osd erasure-code-profile ls") {
+ const map<string,map<string,string> > &profiles =
+ osdmap.get_erasure_code_profiles();
+ if (f)
+ f->open_array_section("erasure-code-profiles");
+ for(map<string,map<string,string> >::const_iterator i = profiles.begin();
+ i != profiles.end();
+ i++) {
+ if (f)
+ f->dump_string("profile", i->first.c_str());
+ else
+ rdata.append(i->first + "\n");
+ }
+ if (f) {
+ f->close_section();
+ ostringstream rs;
+ f->flush(rs);
+ rs << "\n";
+ rdata.append(rs.str());
+ }
+ } else if (prefix == "osd erasure-code-profile get") {
+ string name;
+ cmd_getval(g_ceph_context, cmdmap, "name", name);
+ if (!osdmap.has_erasure_code_profile(name)) {
+ ss << "unknown erasure code profile '" << name << "'";
+ r = -ENOENT;
+ goto reply;
+ }
+ const map<string,string> &profile = osdmap.get_erasure_code_profile(name);
+ if (f)
+ f->open_object_section("profile");
+ for (map<string,string>::const_iterator i = profile.begin();
+ i != profile.end();
+ i++) {
+ if (f)
+ f->dump_string(i->first.c_str(), i->second.c_str());
+ else
+ rdata.append(i->first + "=" + i->second + "\n");
+ }
+ if (f) {
+ f->close_section();
+ ostringstream rs;
+ f->flush(rs);
+ rs << "\n";
+ rdata.append(rs.str());
+ }
} else {
// try prepare update
return false;
return 0;
}
-int OSDMonitor::prepare_pool_properties(const unsigned pool_type,
- const vector<string> &properties,
- map<string,string> *properties_map,
- stringstream &ss)
+bool OSDMonitor::erasure_code_profile_in_use(const map<int64_t, pg_pool_t> &pools,
+ const string &profile,
+ ostream &ss)
+{
+ bool found = false;
+ for (map<int64_t, pg_pool_t>::const_iterator p = pools.begin();
+ p != pools.end();
+ ++p) {
+ if (p->second.erasure_code_profile == profile) {
+ ss << osdmap.pool_name[p->first] << " ";
+ found = true;
+ }
+ }
+ if (found) {
+ ss << "pool(s) are using the erasure code profile '" << profile << "'";
+ }
+ return found;
+}
+
+int OSDMonitor::parse_erasure_code_profile(const vector<string> &erasure_code_profile,
+ map<string,string> *erasure_code_profile_map,
+ stringstream &ss)
{
if (pool_type == pg_pool_t::TYPE_ERASURE) {
int r = get_str_map(g_conf->osd_pool_default_erasure_code_properties,
get_last_committed() + 1));
return true;
+ } else if (prefix == "osd erasure-code-profile rm") {
+ string name;
+ cmd_getval(g_ceph_context, cmdmap, "name", name);
+
+ if (erasure_code_profile_in_use(pending_inc.new_pools, name, ss))
+ goto wait;
+
+ if (erasure_code_profile_in_use(osdmap.pools, name, ss)) {
+ err = -EBUSY;
+ goto reply;
+ }
+
+ if (osdmap.has_erasure_code_profile(name) ||
+ pending_inc.new_erasure_code_profiles.count(name)) {
+ if (osdmap.has_erasure_code_profile(name)) {
+ pending_inc.old_erasure_code_profiles.push_back(name);
+ } else {
+ dout(20) << "erasure code profile rm " << name << ": creation canceled" << dendl;
+ pending_inc.new_erasure_code_profiles.erase(name);
+ }
+
+ getline(ss, rs);
+ wait_for_finished_proposal(new Monitor::C_Command(mon, m, 0, rs,
+ get_last_committed() + 1));
+ return true;
+ } else {
+ ss << "erasure-code-profile " << name << " does not exist";
+ err = 0;
+ goto reply;
+ }
+
+ } else if (prefix == "osd erasure-code-profile set") {
+ string name;
+ cmd_getval(g_ceph_context, cmdmap, "name", name);
+ vector<string> profile;
+ cmd_getval(g_ceph_context, cmdmap, "profile", profile);
+ bool force;
+ if (profile.size() > 0 && profile.back() == "--force") {
+ profile.pop_back();
+ force = true;
+ } else {
+ force = false;
+ }
+ map<string,string> profile_map;
+ err = parse_erasure_code_profile(profile, &profile_map, ss);
+ if (err)
+ goto reply;
+
+ if (osdmap.has_erasure_code_profile(name) && !force) {
+ err = -EPERM;
+ ss << "will not override erasure code profile " << name;
+ goto reply;
+ }
+
+ if (pending_inc.has_erasure_code_profile(name)) {
+ dout(20) << "erasure code profile " << name << " try again" << dendl;
+ goto wait;
+ } else {
+ dout(20) << "erasure code profile " << name << " set" << dendl;
+ pending_inc.set_erasure_code_profile(name, profile_map);
+ }
+
+ getline(ss, rs);
+ wait_for_finished_proposal(new Monitor::C_Command(mon, m, 0, rs,
+ get_last_committed() + 1));
+ return true;
+
} else if (prefix == "osd crush rule create-erasure") {
err = check_cluster_features(CEPH_FEATURE_CRUSH_V2, ss);
if (err == -EAGAIN)
const map<string,string> &properties,
int *crush_ruleset,
stringstream &ss);
+ bool erasure_code_profile_in_use(const map<int64_t, pg_pool_t> &pools,
+ const string &profile,
+ ostream &ss);
+ int parse_erasure_code_profile(const vector<string> &erasure_code_profile,
+ map<string,string> *erasure_code_profile_map,
+ stringstream &ss);
int prepare_pool_size(const unsigned pool_type,
const map<string,string> &properties,
unsigned *size,
test/mon/osd-pool-create.sh \
test/mon/misc.sh \
test/mon/osd-crush.sh \
+ test/mon/osd-erasure-code-profile.sh \
test/mon/mkfs.sh \
test/ceph-disk.sh \
test/mon/mon-handle-forward.sh \
--- /dev/null
+#!/bin/bash
+#
+# Copyright (C) 2014 Cloudwatt <libre.licensing@cloudwatt.com>
+#
+# Author: Loic Dachary <loic@dachary.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Library Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Library Public License for more details.
+#
+source test/mon/mon-test-helpers.sh
+
+function run() {
+ local dir=$1
+
+ export CEPH_ARGS
+ CEPH_ARGS+="--fsid=$(uuidgen) --auth-supported=none "
+ CEPH_ARGS+="--mon-host=127.0.0.1 "
+
+ local id=a
+ call_TEST_functions $dir $id --public-addr 127.0.0.1 || return 1
+}
+
+function SHARE_MON_TEST_set() {
+ local dir=$1
+ local id=$2
+
+ local profile=myprofile
+ #
+ # no key=value pairs : use the default configuration
+ #
+ ./ceph osd erasure-code-profile set $profile 2>&1 || return 1
+ ./ceph osd erasure-code-profile get $profile | \
+ grep plugin=jerasure || return 1
+ ./ceph osd erasure-code-profile rm $profile
+ #
+ # key=value pairs override the default
+ #
+ ./ceph osd erasure-code-profile set $profile \
+ key=value plugin=example || return 1
+ ./ceph osd erasure-code-profile get $profile | \
+ grep -e key=value -e plugin=example || return 1
+ #
+ # --force is required to override an existing profile
+ #
+ ! ./ceph osd erasure-code-profile set $profile > $dir/out 2>&1 || return 1
+ grep 'will not override' $dir/out || return 1
+ ./ceph osd erasure-code-profile set $profile key=other --force || return 1
+ ./ceph osd erasure-code-profile get $profile | \
+ grep key=other || return 1
+
+ ./ceph osd erasure-code-profile rm $profile # cleanup
+}
+
+function SHARE_MON_TEST_set_pending() {
+ local dir=$1
+ local id=$2
+
+ # try again if the profile is pending
+ local profile=profile
+ # add to the pending OSD map without triggering a paxos proposal
+ result=$(echo '{"prefix":"osdmonitor_prepare_command","prepare":"osd erasure-code-profile set","name":"'$profile'"}' | nc -U $dir/$id/ceph-mon.$id.asok | cut --bytes=5-)
+ test $result = true || return 1
+ ./ceph osd erasure-code-profile set $profile --force || return 1
+ grep "$profile try again" $dir/$id/log || return 1
+
+ ./ceph osd erasure-code-profile rm $profile # cleanup
+}
+
+function SHARE_MON_TEST_ls() {
+ local dir=$1
+ local id=$2
+
+ local profile=myprofile
+ ! ./ceph osd erasure-code-profile ls | grep $profile || return 1
+ ./ceph osd erasure-code-profile set $profile 2>&1 || return 1
+ ./ceph osd erasure-code-profile ls | grep $profile || return 1
+ ./ceph --format xml osd erasure-code-profile ls | \
+ grep "<profile>$profile</profile>" || return 1
+
+ ./ceph osd erasure-code-profile rm $profile # cleanup
+}
+
+function SHARE_MON_TEST_rm() {
+ local dir=$1
+ local id=$2
+
+ local profile=myprofile
+ ./ceph osd erasure-code-profile set $profile 2>&1 || return 1
+ ./ceph osd erasure-code-profile ls | grep $profile || return 1
+ ./ceph osd erasure-code-profile rm $profile || return 1
+ ! ./ceph osd erasure-code-profile ls | grep $profile || return 1
+ ./ceph osd erasure-code-profile rm WRONG 2>&1 | \
+ grep "WRONG does not exist" || return 1
+
+ ./ceph osd erasure-code-profile set $profile || return 1
+ ./ceph osd pool create poolname 12 12 erasure $profile || return 1
+ ! ./ceph osd erasure-code-profile rm $profile > $dir/out 2>&1 || return 1
+ grep "poolname.*using.*$profile" $dir/out || return 1
+ ./ceph osd pool delete poolname poolname --yes-i-really-really-mean-it || return 1
+ ./ceph osd erasure-code-profile rm $profile || return 1
+
+ ./ceph osd erasure-code-profile rm $profile # cleanup
+}
+
+function SHARE_MON_TEST_rm_pending() {
+ local dir=$1
+ local id=$2
+
+ # try again if the profile is pending
+ local profile=myprofile
+ # add to the pending OSD map without triggering a paxos proposal
+ result=$(echo '{"prefix":"osdmonitor_prepare_command","prepare":"osd erasure-code-profile set","name":"'$profile'"}' | nc -U $dir/$id/ceph-mon.$id.asok | cut --bytes=5-)
+ test $result = true || return 1
+ ./ceph osd erasure-code-profile rm $profile || return 1
+ grep "$profile: creation canceled" $dir/$id/log || return 1
+}
+
+function SHARE_MON_TEST_get() {
+ local dir=$1
+ local id=$2
+
+ local default_profile=default
+ ./ceph osd erasure-code-profile get $default_profile | \
+ grep plugin=jerasure || return 1
+ ./ceph --format xml osd erasure-code-profile get $default_profile | \
+ grep '<plugin>jerasure</plugin>' || return 1
+ ! ./ceph osd erasure-code-profile get WRONG > $dir/out 2>&1 || return 1
+ grep -q "unknown erasure code profile 'WRONG'" $dir/out || return 1
+}
+
+function TEST_format_invalid() {
+ local dir=$1
+
+ local profile=profile
+ # osd_pool_default_erasure-code-profile is
+ # valid JSON but not of the expected type
+ run_mon $dir a --public-addr 127.0.0.1 \
+ --osd_pool_default_erasure-code-profile 1
+ ! ./ceph osd erasure-code-profile set $profile > $dir/out 2>&1 || return 1
+ cat $dir/out
+ grep 'must be a JSON object' $dir/out || return 1
+}
+
+function TEST_format_json() {
+ local dir=$1
+
+ # osd_pool_default_erasure-code-profile is JSON
+ expected='"plugin":"example"'
+ run_mon $dir a --public-addr 127.0.0.1 \
+ --osd_pool_default_erasure-code-profile "{$expected}"
+ ./ceph --format json osd erasure-code-profile get default | \
+ grep "$expected" || return 1
+}
+
+function TEST_format_plain() {
+ local dir=$1
+
+ # osd_pool_default_erasure-code-profile is plain text
+ expected='"plugin":"example"'
+ run_mon $dir a --public-addr 127.0.0.1 \
+ --osd_pool_default_erasure-code-profile "plugin=example"
+ ./ceph --format json osd erasure-code-profile get default | \
+ grep "$expected" || return 1
+}
+
+main osd-erasure-code-profile
+
+# Local Variables:
+# compile-command: "cd ../.. ; make -j4 && test/mon/osd-erasure-code-profile.sh"
+# End:
def test_unpause(self):
self.check_no_arg('osd', 'unpause')
+ def test_erasure_code_profile_set(self):
+ self.assert_valid_command(['osd', 'erasure-code-profile', 'set',
+ 'name'])
+ self.assert_valid_command(['osd', 'erasure-code-profile', 'set',
+ 'name', 'A=B'])
+ self.assert_valid_command(['osd', 'erasure-code-profile', 'set',
+ 'name', 'A=B', 'C=D'])
+ assert_equal({}, validate_command(sigdict, ['osd',
+ 'erasure-code-profile',
+ 'set']))
+ assert_equal({}, validate_command(sigdict, ['osd',
+ 'erasure-code-profile',
+ 'set',
+ '!!!!']))
+ assert_equal({}, validate_command(sigdict, ['osd',
+ 'erasure-code-profile',
+ 'set',
+ 'name',
+ '!!!!']))
+
+ def test_erasure_code_profile_get(self):
+ self.assert_valid_command(['osd', 'erasure-code-profile', 'get',
+ 'name'])
+ assert_equal({}, validate_command(sigdict, ['osd',
+ 'erasure-code-profile',
+ 'get']))
+ assert_equal({}, validate_command(sigdict, ['osd',
+ 'erasure-code-profile',
+ 'get',
+ '!!!!']))
+
+ def test_erasure_code_profile_rm(self):
+ self.assert_valid_command(['osd', 'erasure-code-profile', 'rm',
+ 'name'])
+ assert_equal({}, validate_command(sigdict, ['osd',
+ 'erasure-code-profile',
+ 'rm']))
+ assert_equal({}, validate_command(sigdict, ['osd',
+ 'erasure-code-profile',
+ 'rm',
+ '!!!!']))
+
+ def test_erasure_code_profile_ls(self):
+ self.assert_valid_command(['osd', 'erasure-code-profile', 'ls'])
+ assert_equal({}, validate_command(sigdict, ['osd',
+ 'erasure-code-profile',
+ 'ls',
+ 'toomany']))
+
def test_set_unset(self):
for action in ('set', 'unset'):
for flag in ('pause', 'noup', 'nodown', 'noout', 'noin',