pyldb: avoid segfault when adding an element with no name
[vlendec/samba-autobuild/.git] / ctdb / tools / ctdb_natgw
1 #!/bin/sh
2
3 if [ -z "$CTDB_BASE" ] ; then
4     export CTDB_BASE="/usr/local/etc/ctdb"
5 fi
6
7 . "${CTDB_BASE}/functions"
8
9 load_script_options "failover" "11.natgw"
10
11 # Default NAT gateway nodes file location
12 [ -n "$CTDB_NATGW_NODES" ] || CTDB_NATGW_NODES="${CTDB_BASE}/natgw_nodes"
13
14 if [ -z "$CTDB" ] ; then
15         CTDB=ctdb
16 fi
17
18 ############################################################
19
20 usage ()
21 {
22 cat <<EOF
23 $0 <option>
24
25 <option> is one of:
26   master     Display node number and private IP address of master node
27   list       List private IP addresses of nodes in group, annotate master
28   status     Show status of nodes in NAT gateway group
29 EOF
30     exit 1
31 }
32
33 nodestatus_X=""
34 # Fields are:
35 # Node|IP|Disconnected|Banned|Disabled|Unhealthy|Stopped|Inactive|PartiallyOnline|ThisNode
36 get_nodestatus_X ()
37 {
38     # Result is cached in global variable nodestatus_X
39     [ -n "$nodestatus_X" ] || \
40         nodestatus_X=$($CTDB -X nodestatus all |
41                               sed -e '1d' -e 's@^|@@' -e 's@|$@@')
42 }
43
44 get_nodestatus ()
45 {
46     # Result is cached in global variable nodestatus
47     [ -n "$nodestatus" ] || nodestatus=$($CTDB nodestatus all)
48     [ $? -ne 255 ] # ctdb nodestatus returns 255 on failure
49 }
50
51 get_natgw_nodes ()
52 {
53     # Result is cached in global variable natgw_nodes
54     if [ -n "$natgw_nodes" ] ; then
55         return
56     fi
57
58     if [ ! -r "$CTDB_NATGW_NODES" ] ; then
59         return 1
60     fi
61
62     natgw_nodes=$(cat "$CTDB_NATGW_NODES") || return 1
63
64     # Sanity check file contents here
65     while read _ip _options ; do
66         # Skip comments
67         case "$_ip" in
68             \#*) continue ;;
69         esac
70         case "$_options" in
71             slave-only|"") : ;;
72             *) die "${prog}: Invalid options \"${_options}\" in  \"$CTDB_NATGW_NODES\""
73         esac
74     done <<EOF
75 $natgw_nodes
76 EOF
77
78     return 0
79 }
80
81 # Print the PNN and IP address of the NAT gateway master node
82 find_master ()
83 {
84     get_natgw_nodes || \
85         die "${prog}: NAT gateway nodes file \"$CTDB_NATGW_NODES\" not found"
86     get_nodestatus_X  || \
87         die "${prog}: Unable to get status of nodes"
88
89     # $_ms is an @-delimited list of nodes that are allowed to be the master
90     _ms="@"
91     while read _ip _options ; do
92         case "$_options" in
93             "") _ms="${_ms}${_ip}@" ;;
94         esac
95     done <<EOF
96 $natgw_nodes
97 EOF
98
99     # Now filter by $ms and by status of nodes...
100
101     # Note that the 3 awk invocations below have "||" between them, so
102     # the first to succeed will select the master node.
103
104     # First try for a fully active and healthy node, so must not be
105     # DISABLED, UNHEALTHY or INACTIVE (last covers DISCONNECTED,
106     # BANNED or STOPPED)
107     awk -F '|' -v ms="$_ms" \
108         'BEGIN { ret = 2 }
109          ms ~ "@" $2 "@" &&
110              $5 == 0 && $6 == 0 && $8 == 0 { print $1, $2 ; ret=0 ; exit }
111          END { exit ret }' <<EOF ||
112 $nodestatus_X
113 EOF
114     # Not found?  UNHEALTHY/BANNED will do, so node must not be
115     # DISCONNECTED, DISABLED or STOPPED
116     awk -F '|' -v ms="$_ms" \
117         'BEGIN { ret = 2 }
118          ms ~ "@" $2 "@" &&
119              $3 == 0 && $5 == 0 && $7 == 0 { print $1, $2 ; ret=0 ; exit }
120          END { exit ret }' <<EOF ||
121 $nodestatus_X
122 EOF
123     # Not found?  STOPPED will do, so node must not be DISCONNECTED or
124     # DISABLED
125     awk -F '|' -v ms="$_ms" \
126         'BEGIN { ret = 2 }
127          ms ~ "@" $2 "@" &&
128              $3 == 0 && $5 == 0 { print $1, $2 ; ret=0 ; exit }
129          END { exit ret }' <<EOF
130 $nodestatus_X
131 EOF
132 }
133
134 # List all nodes in the NAT gateway group, annotating the master node
135 nodes_list ()
136 {
137     get_natgw_nodes || \
138         die "${prog}: NAT gateway nodes file \"$CTDB_NATGW_NODES\" not found"
139     # Intentional word splitting here
140     # shellcheck disable=SC2046
141     set -- $(find_master)  || \
142         die "${prog}: Unable to determine NAT gateway master node"
143     _master_ip="$2"
144
145     # Annotate the master node
146     while read _ip _options ; do
147         if [ "$_ip" = "$_master_ip" ] ; then
148             _options="MASTER${_options:+,}${_options}"
149         fi
150         # There is no other way to do this and keep shellcheck happy.
151         # The tab character must be in the format string and the
152         # format string must contain no variables.  Some shells will
153         # expand a tab if it is in an argument but others won't.
154         if [ -n "$_options" ] ; then
155                 printf '%s\t%s\n' "$_ip" "$_options"
156         else
157                 echo "$_ip"
158         fi
159     done <<EOF
160 $natgw_nodes
161 EOF
162 }
163
164 # Print the status of all nodes in the NAT gateway group, along with a count
165 nodes_status ()
166 {
167     get_natgw_nodes || \
168         die "${prog}: NAT gateway nodes file \"$CTDB_NATGW_NODES\" not found"
169     get_nodestatus || \
170         die "${prog}: Unable to get status of nodes"
171
172     # $_ns is a @-delimited list of nodes in the NAT gateway group
173     _ns="@"
174     while read _ip _options ; do
175         _ns="${_ns}${_ip}@"
176     done <<EOF
177 $natgw_nodes
178 EOF
179
180     # Print status of nodes in $_ns, along with node count
181     awk -v ns="$_ns" 'ns ~ "@" $2 "@" { print $0 }' <<EOF
182 $nodestatus
183 EOF
184 }
185
186 prog=$(basename "$0")
187 cmd="$1"
188
189 case "$cmd" in
190     master)    find_master ;;
191     list)      nodes_list ;;
192     status)    nodes_status ;;
193     *)         usage ;;
194 esac