mon: 'ceph osd crush add ...' to add a second link to an item

Signed-off-by: Sage Weil <sage@inktank.com>
crush: add link_bucket()

Allow an existing bucket to get linked from a new position in the tree.

Signed-off-by: Sage Weil <sage@inktank.com>
crush: prevent formation of a loop

If we are adding an item, ensure it cannot form a loop in the tree/map/
DAG.

Signed-off-by: Sage Weil <sage@inktank.com>
mon: 'ceph osd crush link ...' to add a link to an existing bucket

Allow a second reference to an existing bucket to be added.  This lets
you create a DAG instead of a tree using the CLI.

Signed-off-by: Sage Weil <sage@inktank.com>
crush: add remove_item_under()

Remove only instances of item nested beneath a particular ancestor.

Signed-off-by: Sage Weil <sage@inktank.com>
mon: add optional ancestor arg to 'ceph osd crush rm <item> [ancestor]'

Remove only instances of the item underneath a particular ancestor.

Signed-off-by: Sage Weil <sage@inktank.com>
crush: change find_roots(); add find_takes()

The find_roots() was looking for nodes referenced by 'take', but those
aren't necessarily roots, which is what the callers actually want.

Rename to find_takes() and add a real find_roots().  Not very efficient,
but we don't care.

Signed-off-by: Sage Weil <sage@inktank.com>
mon: allow removal of buckets via 'osd crush rm ...'

No reason to limit this to leaves.

Signed-off-by: Sage Weil <sage@inktank.com>
mon: add 'osd crush add-bucket <name> <type>'

This is (I think) the last missing piece to let you construct an entire
map via the CLI.  The add/set commands will construct intervening ancestor
nodes provide there is an existing ancestor to stick them under, but this
is needed to create the initial root node.

Signed-off-by: Sage Weil <sage@inktank.com>
crush: fix remove_item on bucket removal

Remove the bucket if there are no references left.

Remove the name from the map even if it is a bucket (not sure why that
condition was there in the first place!).

Signed-off-by: Sage Weil <sage@inktank.com>
crush, mon: unlink vs remove

Make an 'unlink' mode of remove that will remove a link to a bucket but
not remove the bucket itself.  This refactors remove_item[_under] and moves
some of the checks into common helpers where they are not duplicated.  Fix
callers to pass the extra arg.

Signed-off-by: Sage Weil <sage@inktank.com>
mon, crush: add some tests to build a DAG via the cli

Signed-off-by: Sage Weil <sage@inktank.com>
mon: factor out _get_pending_crush() helper

Signed-off-by: Sage Weil <sage@inktank.com>