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.