1 /*
2 * Copyright (c) 2015-2016 Red Hat, Inc.
3 *
4 * All rights reserved.
5 *
6 * Author: Jan Friesse (jfriesse@redhat.com)
7 *
8 * This software licensed under BSD license, the text of which follows:
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions are met:
12 *
13 * - Redistributions of source code must retain the above copyright notice,
14 * this list of conditions and the following disclaimer.
15 * - Redistributions in binary form must reproduce the above copyright notice,
16 * this list of conditions and the following disclaimer in the documentation
17 * and/or other materials provided with the distribution.
18 * - Neither the name of the Red Hat, Inc. nor the names of its
19 * contributors may be used to endorse or promote products derived from this
20 * software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
32 * THE POSSIBILITY OF SUCH DAMAGE.
33 */
34
35 #include "qdevice-net-ipc-cmd.h"
36 #include "qdevice-log.h"
37 #include "dynar-str.h"
38 #include "qdevice-net-algorithm.h"
39 #include "utils.h"
40
41 static int
qdevice_net_ipc_cmd_status_add_header(struct dynar * outbuf,int verbose)42 qdevice_net_ipc_cmd_status_add_header(struct dynar *outbuf, int verbose)
43 {
44
45 return ((dynar_str_catf(outbuf, "Qdevice-net information\n") != -1) &&
46 (dynar_str_catf(outbuf, "----------------------\n") != -1));
47 }
48
49 static int
qdevice_net_ipc_cmd_status_add_tie_breaker(struct qdevice_net_instance * instance,struct dynar * outbuf,int verbose)50 qdevice_net_ipc_cmd_status_add_tie_breaker(struct qdevice_net_instance *instance,
51 struct dynar *outbuf, int verbose)
52 {
53
54 if (dynar_str_catf(outbuf, "Tie-breaker:\t\t") == -1) {
55 return (0);
56 }
57
58 switch (instance->tie_breaker.mode) {
59 case TLV_TIE_BREAKER_MODE_LOWEST:
60 if (dynar_str_catf(outbuf, "Node with lowest node ID") == -1) {
61 return (0);
62 }
63 break;
64 case TLV_TIE_BREAKER_MODE_HIGHEST:
65 if (dynar_str_catf(outbuf, "Node with highest node ID") == -1) {
66 return (0);
67 }
68 break;
69 case TLV_TIE_BREAKER_MODE_NODE_ID:
70 if (dynar_str_catf(outbuf, "Node with node ID "UTILS_PRI_NODE_ID,
71 instance->tie_breaker.node_id) == -1) {
72 return (0);
73 }
74 break;
75 }
76
77 return (dynar_str_catf(outbuf, "\n") != -1);
78 }
79
80 static int
qdevice_net_ipc_cmd_status_add_basic_info(struct qdevice_net_instance * instance,struct dynar * outbuf,int verbose)81 qdevice_net_ipc_cmd_status_add_basic_info(struct qdevice_net_instance *instance,
82 struct dynar *outbuf, int verbose)
83 {
84
85 if (dynar_str_catf(outbuf, "Cluster name:\t\t%s\n", instance->cluster_name) == -1) {
86 return (0);
87 }
88
89 if (dynar_str_catf(outbuf, "QNetd host:\t\t%s:%"PRIu16"\n",
90 instance->host_addr, instance->host_port) == -1) {
91 return (0);
92 }
93
94 if (verbose && instance->force_ip_version != 0) {
95 if (dynar_str_catf(outbuf, "Force IP version:\t%u\n",
96 instance->force_ip_version) == -1) {
97 return (0);
98 }
99 }
100
101 if (verbose) {
102 if ((dynar_str_catf(outbuf, "Connect timeout:\t%"PRIu32"ms\n",
103 instance->connect_timeout) == -1) ||
104 (dynar_str_catf(outbuf, "HB interval:\t\t%"PRIu32"ms\n",
105 instance->heartbeat_interval) == -1) ||
106 (dynar_str_catf(outbuf, "VQ vote timer interval:\t%"PRIu32"ms\n",
107 instance->cast_vote_timer_interval) == -1)) {
108 return (0);
109 }
110
111 if (dynar_str_catf(outbuf, "TLS:\t\t\t%s\n",
112 tlv_tls_supported_to_str(instance->tls_supported)) == -1) {
113 return (0);
114 }
115 }
116
117 if (dynar_str_catf(outbuf, "Algorithm:\t\t%s\n",
118 tlv_decision_algorithm_type_to_str(instance->decision_algorithm)) == -1) {
119 return (0);
120 }
121
122 return (1);
123 }
124
125 static int
qdevice_net_ipc_cmd_status_add_poll_timer_status(struct qdevice_net_instance * instance,struct dynar * outbuf,int verbose)126 qdevice_net_ipc_cmd_status_add_poll_timer_status(struct qdevice_net_instance *instance,
127 struct dynar *outbuf, int verbose)
128 {
129
130 if (!verbose) {
131 return (1);
132 }
133
134 if (dynar_str_catf(outbuf, "Poll timer running:\t%s",
135 (instance->cast_vote_timer != NULL ? "Yes" : "No")) == -1) {
136 return (0);
137 }
138
139 if (instance->cast_vote_timer != NULL && instance->cast_vote_timer_vote == TLV_VOTE_ACK) {
140 if (dynar_str_catf(outbuf, " (cast vote)") == -1) {
141 return (0);
142 }
143 }
144
145 return (dynar_str_catf(outbuf, "\n") != -1);
146 }
147
148 static int
qdevice_net_ipc_cmd_status_add_state(struct qdevice_net_instance * instance,struct dynar * outbuf,int verbose)149 qdevice_net_ipc_cmd_status_add_state(struct qdevice_net_instance *instance,
150 struct dynar *outbuf, int verbose)
151 {
152 const char *state;
153
154 if (instance->schedule_disconnect) {
155 state = "Disconnected";
156 } else {
157 if (instance->state == QDEVICE_NET_INSTANCE_STATE_WAITING_VOTEQUORUM_CMAP_EVENTS) {
158 state = "Connected";
159 } else {
160 if (instance->state != QDEVICE_NET_INSTANCE_STATE_WAITING_CONNECT ||
161 !instance->non_blocking_client.destroyed) {
162 state = "Connecting";
163 } else {
164 state = "Connect failed";
165 }
166 }
167 }
168
169 return (dynar_str_catf(outbuf, "State:\t\t\t%s\n", state) != -1);
170 }
171
172 static int
qdevice_net_ipc_cmd_status_add_heuristics(struct qdevice_net_instance * instance,struct dynar * outbuf,int verbose)173 qdevice_net_ipc_cmd_status_add_heuristics(struct qdevice_net_instance *instance,
174 struct dynar *outbuf, int verbose)
175 {
176 enum qdevice_heuristics_mode active_heuristics_mode;
177 int heuristics_enabled;
178
179 active_heuristics_mode = instance->qdevice_instance_ptr->heuristics_instance.mode;
180 heuristics_enabled = (active_heuristics_mode == QDEVICE_HEURISTICS_MODE_ENABLED ||
181 active_heuristics_mode == QDEVICE_HEURISTICS_MODE_SYNC);
182
183 if (!heuristics_enabled) {
184 return (1);
185 }
186
187 if (dynar_str_catf(outbuf, "Heuristics result:\t%s",
188 tlv_heuristics_to_str(instance->latest_heuristics_result)) == -1) {
189 return (0);
190 }
191
192 if (verbose) {
193 if (dynar_str_catf(outbuf, " (regular: %s, membership: %s, connect: %s)",
194 tlv_heuristics_to_str(instance->latest_regular_heuristics_result),
195 tlv_heuristics_to_str(instance->latest_vq_heuristics_result),
196 tlv_heuristics_to_str(instance->latest_connect_heuristics_result)) == -1) {
197 return (0);
198 }
199 }
200
201 return (dynar_str_catf(outbuf, "\n") != -1);
202 }
203
204 static int
qdevice_net_ipc_cmd_status_add_tls_state(struct qdevice_net_instance * instance,struct dynar * outbuf,int verbose)205 qdevice_net_ipc_cmd_status_add_tls_state(struct qdevice_net_instance *instance,
206 struct dynar *outbuf, int verbose)
207 {
208
209 if (!verbose || instance->state != QDEVICE_NET_INSTANCE_STATE_WAITING_VOTEQUORUM_CMAP_EVENTS) {
210 return (1);
211 }
212
213 if (dynar_str_catf(outbuf, "TLS active:\t\t%s", (instance->using_tls ? "Yes" : "No")) == -1) {
214 return (0);
215 }
216
217 if (instance->using_tls && instance->tls_client_cert_sent) {
218 if (dynar_str_catf(outbuf, " (client certificate sent)") == -1) {
219 return (0);
220 }
221 }
222
223 return (dynar_str_catf(outbuf, "\n") != -1);
224 }
225
226 static int
qdevice_net_ipc_cmd_status_add_times(struct qdevice_net_instance * instance,struct dynar * outbuf,int verbose)227 qdevice_net_ipc_cmd_status_add_times(struct qdevice_net_instance *instance,
228 struct dynar *outbuf, int verbose)
229 {
230 struct tm tm_res;
231
232 if (!verbose || instance->state != QDEVICE_NET_INSTANCE_STATE_WAITING_VOTEQUORUM_CMAP_EVENTS) {
233 return (1);
234 }
235
236 if (instance->connected_since_time != ((time_t) -1)) {
237 localtime_r(&instance->connected_since_time, &tm_res);
238 if (dynar_str_catf(outbuf, "Connected since:\t%04d-%02d-%02dT%02d:%02d:%02d\n",
239 tm_res.tm_year + 1900, tm_res.tm_mon + 1, tm_res.tm_mday,
240 tm_res.tm_hour, tm_res.tm_min, tm_res.tm_sec) == -1) {
241 return (0);
242 }
243 }
244
245 if (instance->last_echo_reply_received_time != ((time_t) -1)) {
246 localtime_r(&instance->last_echo_reply_received_time, &tm_res);
247 if (dynar_str_catf(outbuf, "Echo reply received:\t%04d-%02d-%02dT%02d:%02d:%02d\n",
248 tm_res.tm_year + 1900, tm_res.tm_mon + 1, tm_res.tm_mday,
249 tm_res.tm_hour, tm_res.tm_min, tm_res.tm_sec) == -1) {
250 return (0);
251 }
252 }
253
254 return (1);
255 }
256
257 int
qdevice_net_ipc_cmd_status(struct qdevice_net_instance * instance,struct dynar * outbuf,int verbose)258 qdevice_net_ipc_cmd_status(struct qdevice_net_instance *instance, struct dynar *outbuf, int verbose)
259 {
260
261 if (qdevice_net_ipc_cmd_status_add_header(outbuf, verbose) &&
262 qdevice_net_ipc_cmd_status_add_basic_info(instance, outbuf, verbose) &&
263 qdevice_net_ipc_cmd_status_add_tie_breaker(instance, outbuf, verbose) &&
264 qdevice_net_ipc_cmd_status_add_poll_timer_status(instance, outbuf, verbose) &&
265 qdevice_net_ipc_cmd_status_add_state(instance, outbuf, verbose) &&
266 qdevice_net_ipc_cmd_status_add_heuristics(instance, outbuf, verbose) &&
267 qdevice_net_ipc_cmd_status_add_tls_state(instance, outbuf, verbose) &&
268 qdevice_net_ipc_cmd_status_add_times(instance, outbuf, verbose)) {
269 return (1);
270 }
271
272 return (0);
273 }
274