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.