]>
Commit | Line | Data |
---|---|---|
11fdf7f2 | 1 | #!/usr/bin/env bash |
7c673cae FG |
2 | # |
3 | # Copyright (C) 2015 Red Hat <contact@redhat.com> | |
4 | # | |
5 | # Author: Kefu Chai <kchai@redhat.com> | |
6 | # | |
7 | # This program is free software; you can redistribute it and/or modify | |
8 | # it under the terms of the GNU Library Public License as published by | |
9 | # the Free Software Foundation; either version 2, or (at your option) | |
10 | # any later version. | |
11 | # | |
12 | # This program is distributed in the hope that it will be useful, | |
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | # GNU Library Public License for more details. | |
16 | # | |
17 | ||
18 | verbose= | |
19 | ||
20 | test -d ../src && export PATH=$PATH:. | |
21 | ||
31f18b77 FG |
22 | if ! which jq ; then |
23 | echo "Missing jq binary!" | |
7c673cae FG |
24 | exit 1 |
25 | fi | |
26 | ||
27 | if [ `uname` = FreeBSD ]; then | |
28 | GETOPT=/usr/local/bin/getopt | |
29 | else | |
30 | GETOPT=getopt | |
31 | fi | |
32 | ||
33 | function osdmap_get() { | |
34 | local store_path=$1 | |
35 | local query=$2 | |
36 | local epoch=${3:+-v $3} | |
37 | local osdmap=`mktemp` | |
38 | ||
39 | $CEPH_BIN/ceph-monstore-tool $store_path get osdmap -- \ | |
40 | $epoch -o $osdmap > /dev/null || return | |
41 | ||
31f18b77 FG |
42 | echo $($CEPH_BIN/osdmaptool --dump json $osdmap 2> /dev/null | \ |
43 | jq "$query") | |
7c673cae FG |
44 | |
45 | rm -f $osdmap | |
46 | } | |
47 | ||
48 | function test_crush() { | |
49 | local store_path=$1 | |
50 | local epoch=$2 | |
51 | local max_osd=$3 | |
52 | local crush=$4 | |
53 | local osdmap=`mktemp` | |
54 | ||
55 | $CEPH_BIN/ceph-monstore-tool $store_path get osdmap -- \ | |
56 | -v $epoch -o $osdmap > /dev/null | |
57 | $CEPH_BIN/osdmaptool --export-crush $crush $osdmap &> /dev/null | |
58 | ||
59 | if $CEPH_BIN/crushtool --test --check $max_osd -i $crush > /dev/null; then | |
60 | good=true | |
61 | else | |
62 | good=false | |
63 | fi | |
64 | rm -f $osdmap | |
65 | $good || return 1 | |
66 | } | |
67 | ||
68 | function die() { | |
69 | local retval=$? | |
70 | echo "$@" >&2 | |
71 | exit $retval | |
72 | } | |
73 | ||
74 | function usage() { | |
75 | [ $# -gt 0 ] && echo -e "\n$@" | |
76 | cat <<EOF | |
77 | ||
78 | Usage: $0 [options ...] <mon-store> | |
79 | ||
80 | Search backward for a latest known-good epoch in monstore. Rewrite the osdmap | |
81 | epochs after it with the crush map in the found epoch if asked to do so. By | |
82 | default, print out the crush map in the good epoch. | |
83 | ||
84 | [-h|--help] display this message | |
85 | [--out] write the found crush map to given file (default: stdout) | |
86 | [--rewrite] rewrite the monitor storage with the found crush map | |
87 | [--verbose] be more chatty | |
88 | EOF | |
89 | [ $# -gt 0 ] && exit 1 | |
90 | exit 0 | |
91 | } | |
92 | ||
93 | function main() { | |
94 | local temp | |
95 | temp=$($GETOPT -o h --long verbose,help,mon-store:,out:,rewrite -n $0 -- "$@") || return 1 | |
96 | ||
97 | eval set -- "$temp" | |
98 | local rewrite | |
99 | while [ "$1" != "--" ]; do | |
100 | case "$1" in | |
101 | --verbose) | |
102 | verbose=true | |
103 | # set -xe | |
104 | # PS4='${FUNCNAME[0]}: $LINENO: ' | |
105 | shift;; | |
106 | -h|--help) | |
107 | usage | |
108 | return 0;; | |
109 | --out) | |
110 | output=$2 | |
111 | shift 2;; | |
112 | --osdmap-epoch) | |
113 | osdmap_epoch=$2 | |
114 | shift 2;; | |
115 | --rewrite) | |
116 | rewrite=true | |
117 | shift;; | |
118 | *) | |
119 | usage "unexpected argument $1" | |
120 | shift;; | |
121 | esac | |
122 | done | |
123 | shift | |
124 | ||
125 | local store_path="$1" | |
126 | test $store_path || usage "I need the path to mon-store." | |
127 | ||
128 | # try accessing the store; if it fails, likely means a mon is running | |
129 | local last_osdmap_epoch | |
130 | local max_osd | |
31f18b77 | 131 | last_osdmap_epoch=$(osdmap_get $store_path ".epoch") || \ |
7c673cae FG |
132 | die "error accessing mon store at $store_path" |
133 | # get the max_osd # in last osdmap epoch, crushtool will use it to check | |
134 | # the crush maps in previous osdmaps | |
31f18b77 | 135 | max_osd=$(osdmap_get $store_path ".max_osd" $last_osdmap_epoch) |
7c673cae FG |
136 | |
137 | local good_crush | |
138 | local good_epoch | |
139 | test $verbose && echo "the latest osdmap epoch is $last_osdmap_epoch" | |
140 | for epoch in `seq $last_osdmap_epoch -1 1`; do | |
141 | local crush_path=`mktemp` | |
142 | test $verbose && echo "checking crush map #$epoch" | |
143 | if test_crush $store_path $epoch $max_osd $crush_path; then | |
144 | test $verbose && echo "crush map version #$epoch works with osdmap epoch #$osdmap_epoch" | |
145 | good_epoch=$epoch | |
146 | good_crush=$crush_path | |
147 | break | |
148 | fi | |
149 | rm -f $crush_path | |
150 | done | |
151 | ||
152 | if test $good_epoch; then | |
153 | echo "good crush map found at epoch $epoch/$last_osdmap_epoch" | |
154 | else | |
155 | echo "Unable to find a crush map for osdmap version #$osdmap_epoch." 2>&1 | |
156 | return 1 | |
157 | fi | |
158 | ||
159 | if test $good_epoch -eq $last_osdmap_epoch; then | |
160 | echo "and mon store has no faulty crush maps." | |
161 | elif test $output; then | |
162 | $CEPH_BIN/crushtool --decompile $good_crush --outfn $output | |
163 | elif test $rewrite; then | |
164 | $CEPH_BIN/ceph-monstore-tool $store_path rewrite-crush -- \ | |
165 | --crush $good_crush \ | |
166 | --good-epoch $good_epoch | |
167 | else | |
168 | echo | |
169 | $CEPH_BIN/crushtool --decompile $good_crush | |
170 | fi | |
171 | rm -f $good_crush | |
172 | } | |
173 | ||
174 | main "$@" |