The crushtool utility can be used to test Ceph crush rules before applying them to a cluster.
$ crushtool --outfn crushmap --build --num_osds 10 \
host straw 2 rack straw 2 default straw 0
# id weight type name reweight
-9 10 default default
-6 4 rack rack0
-1 2 host host0
0 1 osd.0 1
1 1 osd.1 1
-2 2 host host1
2 1 osd.2 1
3 1 osd.3 1
-7 4 rack rack1
-3 2 host host2
4 1 osd.4 1
5 1 osd.5 1
-4 2 host host3
6 1 osd.6 1
7 1 osd.7 1
-8 2 rack rack2
-5 2 host host4
8 1 osd.8 1
9 1 osd.9 1
Creates a crushmap from scratch (–build). It assumes there is a total of 10 OSDs available ( –num_osds 10 ). It then places two OSDs in each host ( host straw 2 ). The resulting hosts (five of them) are then placed in racks, at most two per racks ( rack straw 2 ). All racks are placed in the default root (that’s what the zero stands for : all of them) ( default straw 0 ). The last rack only has one host because there is an odd number of hosts available.
The crush rule to be tested can be injected in the crushmap with
crushtool --outfn crushmap --build --num_osds 10 host straw 2 rack straw 2 default straw 0
crushtool -d crushmap -o crushmap.txt
cat >> crushmap.txt <<EOF
rule myrule {
ruleset 1
type replicated
min_size 1
max_size 10
step take default
step choose firstn 2 type rack
step chooseleaf firstn 2 type host
step emit
}
EOF
crushtool -c crushmap.txt -o crushmap
This crushmap should be able to provide two OSDs ( for placement groups for instance ) and it can be verified with the –test option.
$ crushtool -i crushmap --test --show-statistics --rule 1 --min-x 1 --max-x 2 --num-rep 2
rule 1 (myrule), x = 1..2, numrep = 2..2
CRUSH rule 1 x 1 [0,2]
CRUSH rule 1 x 2 [7,4]
rule 1 (myrule) num_rep 2 result size == 2: 2/2
The –rule 1 designates the rule that was injected. The –rule 0 is the default rule that is created by default. The x can be thought of as the unique name of the placement group for which OSDs are reclaimed. The –min-x 1 –max-x 2 varies the value of x from 1 to 2 therefore trying the rule only twice. –min-x 1 –max-x 2048 would create 2048 lines. Each line shows the value of x after the rule number. In rule 1 x 2 the 1 is the rule number and the 2 is the value of x. The last line shows that for all values of x (2/2 i.e. 2 values of x out of 2), when asked to provide 2 OSDs (num_rep 2) the crush rule was able to provide 2 (result size == 2).
If asked for 4 OSDs, the same crush rule may fail because it has barely enough resources to satisfy the requirements.
$ crushtool -i crushmap --test --show-statistics --rule 1 --min-x 1 --max-x 2 --num-rep 4
rule 1 (myrule), x = 1..2, numrep = 4..4
CRUSH rule 1 x 1 [0,2,9]
CRUSH rule 1 x 2 [7,4,1,3]
rule 1 (myrule) num_rep 4 result size == 3: 1/2
rule 1 (myrule) num_rep 4 result size == 4: 1/2
The statistics at the end shows that one of the two mappings failed: the result size == 3 is lower than the required number num_rep 4. If asked for more OSDs than the rule can provide, the rule will always fail.
crushtool -i crushmap --test --show-statistics --rule 1 --min-x 1 --max-x 2 --num-rep 5
rule 1 (myrule), x = 1..2, numrep = 5..5
CRUSH rule 1 x 1 [0,2,9]
CRUSH rule 1 x 2 [7,4,1,3]
rule 1 (myrule) num_rep 5 result size == 3: 1/2
rule 1 (myrule) num_rep 5 result size == 4: 1/2
More examples of crushtool usage can be found in the crushtool directory of the Ceph sources.