1 /*
2 * $Header$
3 *
4 * Handles watchdog connection, and protocol communication with pgpool-II
5 *
6 * pgpool: a language independent connection pool server for PostgreSQL
7 * written by Tatsuo Ishii
8 *
9 * Copyright (c) 2003-2015 PgPool Global Development Group
10 *
11 * Permission to use, copy, modify, and distribute this software and
12 * its documentation for any purpose and without fee is hereby
13 * granted, provided that the above copyright notice appear in all
14 * copies and that both that copyright notice and this permission
15 * notice appear in supporting documentation, and that the name of the
16 * author not be used in advertising or publicity pertaining to
17 * distribution of the software without specific, written prior
18 * permission. The author makes no representations about the
19 * suitability of this software for any purpose. It is provided "as
20 * is" without express or implied warranty.
21 *
22 */
23 #include <string.h>
24 #include <stdlib.h>
25
26 #include "utils/elog.h"
27 #include "utils/json_writer.h"
28 #include "utils/json.h"
29 #include "pool_config.h"
30 #include "watchdog/watchdog.h"
31 #include "watchdog/wd_json_data.h"
32 #include "watchdog/wd_ipc_defines.h"
33 #include "pool.h"
34
35
get_pool_config_from_json(char * json_data,int data_len)36 POOL_CONFIG* get_pool_config_from_json(char* json_data, int data_len)
37 {
38 int i;
39 json_value *root = NULL;
40 json_value *value = NULL;
41 POOL_CONFIG *config = palloc0(sizeof(POOL_CONFIG));
42 config->backend_desc = palloc0(sizeof(BackendDesc));
43
44 root = json_parse(json_data,data_len);
45 /* The root node must be object */
46 if (root == NULL || root->type != json_object)
47 goto ERROR_EXIT;
48
49 if (json_get_int_value_for_key(root, "num_init_children", &config->num_init_children))
50 goto ERROR_EXIT;
51 if (json_get_int_value_for_key(root, "listen_backlog_multiplier", &config->listen_backlog_multiplier))
52 goto ERROR_EXIT;
53 if (json_get_int_value_for_key(root, "child_life_time", &config->child_life_time))
54 goto ERROR_EXIT;
55 if (json_get_int_value_for_key(root, "connection_life_time", &config->connection_life_time))
56 goto ERROR_EXIT;
57 if (json_get_int_value_for_key(root, "child_max_connections", &config->child_max_connections))
58 goto ERROR_EXIT;
59 if (json_get_int_value_for_key(root, "client_idle_limit", &config->client_idle_limit))
60 goto ERROR_EXIT;
61 if (json_get_int_value_for_key(root, "max_pool", &config->max_pool))
62 goto ERROR_EXIT;
63 if (json_get_bool_value_for_key(root, "replication_mode", &config->replication_mode))
64 goto ERROR_EXIT;
65 if (json_get_bool_value_for_key(root, "enable_pool_hba", &config->enable_pool_hba))
66 goto ERROR_EXIT;
67 if (json_get_int_value_for_key(root, "load_balance_mode", (int*)&config->load_balance_mode))
68 goto ERROR_EXIT;
69 if (json_get_bool_value_for_key(root, "replication_stop_on_mismatch", &config->replication_stop_on_mismatch))
70 goto ERROR_EXIT;
71 if (json_get_bool_value_for_key(root, "failover_if_affected_tuples_mismatch", &config->failover_if_affected_tuples_mismatch))
72 goto ERROR_EXIT;
73 if (json_get_bool_value_for_key(root, "replicate_select", &config->replicate_select))
74 goto ERROR_EXIT;
75 if (json_get_int_value_for_key(root, "master_slave_mode", (int*)&config->master_slave_mode))
76 goto ERROR_EXIT;
77 if (json_get_bool_value_for_key(root, "connection_cache", &config->connection_cache))
78 goto ERROR_EXIT;
79 if (json_get_int_value_for_key(root, "health_check_timeout", &config->health_check_timeout))
80 goto ERROR_EXIT;
81 if (json_get_int_value_for_key(root, "health_check_period", &config->health_check_period))
82 goto ERROR_EXIT;
83 if (json_get_int_value_for_key(root, "health_check_max_retries", &config->health_check_max_retries))
84 goto ERROR_EXIT;
85 if (json_get_int_value_for_key(root, "health_check_retry_delay", &config->health_check_retry_delay))
86 goto ERROR_EXIT;
87 if (json_get_bool_value_for_key(root, "fail_over_on_backend_error", &config->fail_over_on_backend_error))
88 goto ERROR_EXIT;
89 if (json_get_int_value_for_key(root, "recovery_timeout", &config->recovery_timeout))
90 goto ERROR_EXIT;
91 if (json_get_int_value_for_key(root, "search_primary_node_timeout", &config->search_primary_node_timeout))
92 goto ERROR_EXIT;
93 if (json_get_int_value_for_key(root, "client_idle_limit_in_recovery", &config->client_idle_limit_in_recovery))
94 goto ERROR_EXIT;
95 if (json_get_bool_value_for_key(root, "insert_lock", &config->insert_lock))
96 goto ERROR_EXIT;
97 if (json_get_bool_value_for_key(root, "memory_cache_enabled", &config->memory_cache_enabled))
98 goto ERROR_EXIT;
99 if (json_get_bool_value_for_key(root, "use_watchdog", &config->use_watchdog))
100 goto ERROR_EXIT;
101 if (json_get_bool_value_for_key(root, "clear_memqcache_on_escalation", &config->clear_memqcache_on_escalation))
102 goto ERROR_EXIT;
103 if (json_get_int_value_for_key(root, "wd_port", &config->wd_port))
104 goto ERROR_EXIT;
105 if (json_get_int_value_for_key(root, "wd_priority", &config->wd_priority))
106 goto ERROR_EXIT;
107 if (json_get_int_value_for_key(root, "master_slave_sub_mode", (int*)&config->master_slave_sub_mode))
108 goto ERROR_EXIT;
109
110
111 /* backend_desc array */
112 value = json_get_value_for_key(root,"backend_desc");
113 if (value == NULL || value->type != json_array)
114 goto ERROR_EXIT;
115
116 config->backend_desc->num_backends = value->u.array.length;
117 for (i = 0; i < config->backend_desc->num_backends; i++)
118 {
119 json_value *arr_value = value->u.array.values[i];
120 char *ptr;
121 if (json_get_int_value_for_key(arr_value, "backend_port", &config->backend_desc->backend_info[i].backend_port))
122 goto ERROR_EXIT;
123 ptr = json_get_string_value_for_key(arr_value, "backend_hostname");
124 if (ptr == NULL)
125 goto ERROR_EXIT;
126 strncpy(config->backend_desc->backend_info[i].backend_hostname, ptr,sizeof(config->backend_desc->backend_info[i].backend_hostname) -1);
127 }
128
129 /* wd_remote_nodes array */
130 value = json_get_value_for_key(root,"wd_remote_nodes");
131 if (value == NULL || value->type != json_array)
132 goto ERROR_EXIT;
133
134 config->wd_remote_nodes.num_wd = value->u.array.length;
135 for (i = 0; i < config->wd_remote_nodes.num_wd; i++)
136 {
137 json_value *arr_value = value->u.array.values[i];
138 char *ptr;
139 if (json_get_int_value_for_key(arr_value, "wd_port", &config->wd_remote_nodes.wd_remote_node_info[i].wd_port))
140 goto ERROR_EXIT;
141 if (json_get_int_value_for_key(arr_value, "pgpool_port", &config->wd_remote_nodes.wd_remote_node_info[i].pgpool_port))
142 goto ERROR_EXIT;
143 ptr = json_get_string_value_for_key(arr_value, "hostname");
144 if (ptr == NULL)
145 goto ERROR_EXIT;
146 strncpy(config->wd_remote_nodes.wd_remote_node_info[i].hostname, ptr,sizeof(config->wd_remote_nodes.wd_remote_node_info[i].hostname) -1);
147 }
148
149 json_value_free(root);
150 return config;
151
152 ERROR_EXIT:
153 if (root)
154 json_value_free(root);
155 if (config->backend_desc)
156 pfree(config->backend_desc);
157 pfree(config);
158 return NULL;
159 }
160
get_pool_config_json(void)161 char* get_pool_config_json(void)
162 {
163 int i;
164 char* json_str;
165
166 JsonNode* jNode = jw_create_with_object(true);
167
168 jw_put_int(jNode, "num_init_children", pool_config->num_init_children);
169 jw_put_int(jNode, "listen_backlog_multiplier", pool_config->listen_backlog_multiplier);
170 jw_put_int(jNode, "child_life_time", pool_config->child_life_time);
171 jw_put_int(jNode, "connection_life_time", pool_config->connection_life_time);
172 jw_put_int(jNode, "child_max_connections", pool_config->child_max_connections);
173 jw_put_int(jNode, "client_idle_limit", pool_config->client_idle_limit);
174 jw_put_int(jNode, "max_pool", pool_config->max_pool);
175 jw_put_bool(jNode, "replication_mode", pool_config->replication_mode);
176 jw_put_bool(jNode, "enable_pool_hba", pool_config->enable_pool_hba);
177 jw_put_int(jNode, "load_balance_mode", pool_config->load_balance_mode);
178 jw_put_bool(jNode, "replication_stop_on_mismatch", pool_config->replication_stop_on_mismatch);
179 jw_put_bool(jNode, "failover_if_affected_tuples_mismatch", pool_config->failover_if_affected_tuples_mismatch);
180 jw_put_bool(jNode, "replicate_select", pool_config->replicate_select);
181 jw_put_int(jNode, "master_slave_mode", pool_config->master_slave_mode);
182 jw_put_bool(jNode, "connection_cache", pool_config->connection_cache);
183 jw_put_int(jNode, "health_check_timeout", pool_config->health_check_timeout);
184 jw_put_int(jNode, "health_check_period", pool_config->health_check_period);
185 jw_put_int(jNode, "health_check_max_retries", pool_config->health_check_max_retries);
186 jw_put_int(jNode, "health_check_retry_delay", pool_config->health_check_retry_delay);
187 jw_put_bool(jNode, "fail_over_on_backend_error", pool_config->fail_over_on_backend_error);
188 jw_put_int(jNode, "recovery_timeout", pool_config->recovery_timeout);
189 jw_put_int(jNode, "search_primary_node_timeout", pool_config->search_primary_node_timeout);
190 jw_put_int(jNode, "client_idle_limit_in_recovery", pool_config->client_idle_limit_in_recovery);
191 jw_put_bool(jNode, "insert_lock", pool_config->insert_lock);
192 jw_put_bool(jNode, "memory_cache_enabled", pool_config->memory_cache_enabled);
193 jw_put_bool(jNode, "use_watchdog", pool_config->use_watchdog);
194 jw_put_bool(jNode, "clear_memqcache_on_escalation", pool_config->clear_memqcache_on_escalation);
195 jw_put_int(jNode, "wd_port", pool_config->wd_port);
196 jw_put_int(jNode, "wd_priority", pool_config->wd_priority);
197 jw_put_int(jNode, "master_slave_sub_mode", pool_config->master_slave_sub_mode);
198
199 /* Array of backends */
200 jw_start_array(jNode, "backend_desc");
201 for (i=0; i < pool_config->backend_desc->num_backends; i++)
202 {
203 jw_start_object(jNode, "BackendInfo");
204 jw_put_string(jNode, "backend_hostname",pool_config->backend_desc->backend_info[i].backend_hostname);
205 jw_put_int(jNode, "backend_port", pool_config->backend_desc->backend_info[i].backend_port);
206 jw_end_element(jNode);
207 }
208 jw_end_element(jNode); /* backend_desc array End */
209
210 /* Array of wd_remote_nodes */
211 jw_start_array(jNode, "wd_remote_nodes");
212 for (i=0; i < pool_config->wd_remote_nodes.num_wd; i++)
213 {
214 jw_start_object(jNode, "WdRemoteNodesConfig");
215 jw_put_string(jNode, "hostname",pool_config->wd_remote_nodes.wd_remote_node_info[i].hostname);
216 jw_put_int(jNode, "wd_port", pool_config->wd_remote_nodes.wd_remote_node_info[i].wd_port);
217 jw_put_int(jNode, "pgpool_port", pool_config->wd_remote_nodes.wd_remote_node_info[i].pgpool_port);
218 jw_end_element(jNode);
219 }
220 jw_end_element(jNode); /* wd_remote_nodes array End */
221
222 jw_finish_document(jNode);
223 json_str = pstrdup(jw_get_json_string(jNode));
224 jw_destroy(jNode);
225 return json_str;
226 }
227
228 /* The function returns the simple JSON string that contains
229 * only one KEY,VALUE along with the authkey key value if provided
230 */
get_simple_request_json(char * key,char * value,unsigned int sharedKey,char * authKey)231 char* get_simple_request_json(char *key, char* value, unsigned int sharedKey, char* authKey)
232 {
233 char* json_str;
234
235 JsonNode* jNode = jw_create_with_object(true);
236
237 jw_put_int(jNode, WD_IPC_SHARED_KEY, sharedKey); /* put the shared key*/
238
239 if (authKey != NULL && strlen(authKey) > 0)
240 jw_put_string(jNode, WD_IPC_AUTH_KEY, authKey); /* put the auth key*/
241
242 jw_put_string(jNode, key, value);
243 jw_finish_document(jNode);
244 json_str = pstrdup(jw_get_json_string(jNode));
245 jw_destroy(jNode);
246 return json_str;
247 }
248
get_data_request_json(char * request_type,unsigned int sharedKey,char * authKey)249 char* get_data_request_json(char* request_type, unsigned int sharedKey, char* authKey)
250 {
251 return get_simple_request_json(WD_JSON_KEY_DATA_REQ_TYPE, request_type, sharedKey, authKey);
252 }
253
parse_data_request_json(char * json_data,int data_len,char ** request_type)254 bool parse_data_request_json(char* json_data, int data_len, char** request_type)
255 {
256 json_value *root;
257 char* ptr;
258
259 *request_type = NULL;
260
261 root = json_parse(json_data,data_len);
262
263 /* The root node must be object */
264 if (root == NULL || root->type != json_object)
265 {
266 json_value_free(root);
267 ereport(LOG,
268 (errmsg("watchdog is unable to parse data request json"),
269 errdetail("invalid json data \"%s\"",json_data)));
270 return false;
271 }
272 ptr = json_get_string_value_for_key(root, WD_JSON_KEY_DATA_REQ_TYPE);
273 if (ptr == NULL)
274 {
275 json_value_free(root);
276 ereport(LOG,
277 (errmsg("watchdog is unable to parse data request json"),
278 errdetail("request name node not found in json data \"%s\"",json_data)));
279 return false;
280 }
281 *request_type = pstrdup(ptr);
282 json_value_free(root);
283 return true;
284 }
285
286
287 /* The function reads the backend node status from shared memory
288 * and creates a json packet from it
289 */
get_backend_node_status_json(WatchdogNode * wdNode)290 char* get_backend_node_status_json(WatchdogNode* wdNode)
291 {
292 int i;
293 char* json_str;
294 JsonNode* jNode = jw_create_with_object(true);
295
296 jw_start_array(jNode, "BackendNodeStatusList");
297
298 for (i=0;i< pool_config->backend_desc->num_backends;i++)
299 {
300 BACKEND_STATUS backend_status = pool_config->backend_desc->backend_info[i].backend_status;
301 jw_put_int_value(jNode, backend_status);
302 }
303 /* put the primary node id */
304 jw_end_element(jNode);
305 jw_put_int(jNode, "PrimaryNodeId", Req_info->primary_node_id);
306 jw_put_string(jNode, "NodeName",wdNode->nodeName);
307
308 jw_finish_document(jNode);
309 json_str = pstrdup(jw_get_json_string(jNode));
310 jw_destroy(jNode);
311 return json_str;
312 }
313
get_pg_backend_node_status_from_json(char * json_data,int data_len)314 WDPGBackendStatus* get_pg_backend_node_status_from_json(char* json_data, int data_len)
315 {
316 json_value *root = NULL;
317 json_value *value = NULL;
318 char *ptr;
319 int i;
320 WDPGBackendStatus* backendStatus = NULL;
321
322 root = json_parse(json_data,data_len);
323 /* The root node must be object */
324 if (root == NULL || root->type != json_object)
325 return NULL;
326
327 /* backend status array */
328 value = json_get_value_for_key(root,"BackendNodeStatusList");
329 if (value == NULL || value->type != json_array)
330 return NULL;
331
332 if (value->u.array.length <=0 || value->u.array.length > MAX_NUM_BACKENDS )
333 return NULL;
334
335 backendStatus = palloc(sizeof(WDPGBackendStatus));
336 backendStatus->node_count = value->u.array.length;
337
338 for (i = 0; i < backendStatus->node_count; i++)
339 {
340 backendStatus->backend_status[i] = value->u.array.values[i]->u.integer;
341 }
342
343 if (json_get_int_value_for_key(root, "PrimaryNodeId", &backendStatus->primary_node_id))
344 {
345 ereport(ERROR,
346 (errmsg("invalid json data"),
347 errdetail("unable to find Watchdog Node ID")));
348 }
349
350 ptr = json_get_string_value_for_key(root, "NodeName");
351 if (ptr)
352 {
353 strncpy(backendStatus->nodeName, ptr, sizeof(backendStatus->nodeName) -1);
354 }
355 else
356 {
357 backendStatus->nodeName[0] = 0;
358 }
359
360 return backendStatus;
361 }
362
get_beacon_message_json(WatchdogNode * wdNode)363 char* get_beacon_message_json(WatchdogNode* wdNode)
364 {
365 char* json_str;
366 struct timeval current_time;
367 long seconds_since_current_state;
368 long seconds_since_node_startup;
369
370 gettimeofday(¤t_time,NULL);
371
372 seconds_since_current_state = WD_TIME_DIFF_SEC(current_time, wdNode->current_state_time);
373 seconds_since_node_startup = WD_TIME_DIFF_SEC(current_time, wdNode->startup_time);
374
375 JsonNode* jNode = jw_create_with_object(true);
376
377 jw_put_int(jNode, "State", wdNode->state);
378 jw_put_long(jNode, "SecondsSinceStartup", seconds_since_node_startup);
379 jw_put_long(jNode, "SecondsSinceCurrentState", seconds_since_current_state);
380 jw_put_int(jNode, "QuorumStatus", wdNode->quorum_status);
381 jw_put_int(jNode, "AliveNodeCount", wdNode->standby_nodes_count);
382 jw_put_bool(jNode, "Escalated", wdNode->escalated == 0?false:true);
383
384 jw_finish_document(jNode);
385 json_str = pstrdup(jw_get_json_string(jNode));
386 jw_destroy(jNode);
387 return json_str;
388 }
389
get_watchdog_node_info_json(WatchdogNode * wdNode,char * authkey)390 char* get_watchdog_node_info_json(WatchdogNode* wdNode, char* authkey)
391 {
392 char* json_str;
393 long seconds_since_current_state;
394 long seconds_since_node_startup;
395 struct timeval current_time;
396
397 gettimeofday(¤t_time,NULL);
398
399 seconds_since_current_state = WD_TIME_DIFF_SEC(current_time, wdNode->current_state_time);
400 seconds_since_node_startup = WD_TIME_DIFF_SEC(current_time, wdNode->startup_time);
401
402 JsonNode* jNode = jw_create_with_object(true);
403
404 jw_put_string(jNode, "PGPOOL_VERSION", VERSION);
405 jw_put_string(jNode, "DATA_VERSION_MAJOR", WD_MESSAGE_DATA_VERSION_MAJOR);
406 jw_put_string(jNode, "DATA_VERSION_MINOR", WD_MESSAGE_DATA_VERSION_MINOR);
407
408 jw_put_int(jNode, "State", wdNode->state);
409 jw_put_int(jNode, "WdPort", wdNode->wd_port);
410 jw_put_int(jNode, "PgpoolPort", wdNode->pgpool_port);
411 jw_put_int(jNode, "WdPriority", wdNode->wd_priority);
412
413 jw_put_string(jNode, "NodeName",wdNode->nodeName);
414 jw_put_string(jNode, "HostName",wdNode->hostname);
415 jw_put_string(jNode, "VIP",wdNode->delegate_ip);
416
417 jw_put_long(jNode, "SecondsSinceStartup", seconds_since_node_startup);
418 jw_put_long(jNode, "SecondsSinceCurrentState", seconds_since_current_state);
419 jw_put_int(jNode, "QuorumStatus", wdNode->quorum_status);
420 jw_put_int(jNode, "AliveNodeCount", wdNode->standby_nodes_count);
421 jw_put_bool(jNode, "Escalated", wdNode->escalated == 0?false:true);
422
423 if(authkey)
424 jw_put_string(jNode, "authkey",authkey);
425
426 jw_finish_document(jNode);
427 json_str = pstrdup(jw_get_json_string(jNode));
428 jw_destroy(jNode);
429 return json_str;
430
431 }
432
get_watchdog_node_from_json(char * json_data,int data_len,char ** authkey)433 WatchdogNode* get_watchdog_node_from_json(char* json_data, int data_len, char** authkey)
434 {
435 json_value *root = NULL;
436 char* ptr;
437 WatchdogNode* wdNode = palloc0(sizeof(WatchdogNode));
438
439 root = json_parse(json_data,data_len);
440 /* The root node must be object */
441 if (root == NULL || root->type != json_object)
442 goto ERROR_EXIT;
443
444 if (json_get_long_value_for_key(root, "StartupTimeSecs", &wdNode->startup_time.tv_sec))
445 {
446 bool escalated;
447 long seconds_since_node_startup;
448 long seconds_since_current_state;
449 struct timeval current_time;
450
451 gettimeofday(¤t_time,NULL);
452
453 /*The new version does not have StartupTimeSecs Key */
454 if (json_get_long_value_for_key(root, "SecondsSinceStartup", &seconds_since_node_startup))
455 goto ERROR_EXIT;
456 if (json_get_long_value_for_key(root, "SecondsSinceCurrentState", &seconds_since_current_state))
457 goto ERROR_EXIT;
458 if (json_get_bool_value_for_key(root, "Escalated", &escalated))
459 goto ERROR_EXIT;
460 if (json_get_int_value_for_key(root, "QuorumStatus", &wdNode->quorum_status))
461 goto ERROR_EXIT;
462 if (json_get_int_value_for_key(root, "AliveNodeCount", &wdNode->standby_nodes_count))
463 goto ERROR_EXIT;
464
465 if (escalated)
466 wdNode->escalated = 1;
467 else
468 wdNode->escalated = 0;
469
470 /* create the time */
471 wdNode->current_state_time.tv_sec = current_time.tv_sec - seconds_since_current_state;
472 wdNode->startup_time.tv_sec = current_time.tv_sec - seconds_since_node_startup;
473 wdNode->current_state_time.tv_usec = wdNode->startup_time.tv_usec = 0;
474 }
475 else
476 {
477 /* we do this to know that we got the info from older version*/
478 wdNode->current_state_time.tv_sec = 0;
479 }
480
481 if (json_get_int_value_for_key(root, "State", (int*)&wdNode->state))
482 goto ERROR_EXIT;
483 if (json_get_int_value_for_key(root, "WdPort", &wdNode->wd_port))
484 goto ERROR_EXIT;
485 if (json_get_int_value_for_key(root, "PgpoolPort", &wdNode->pgpool_port))
486 goto ERROR_EXIT;
487 if (json_get_int_value_for_key(root, "WdPriority", &wdNode->wd_priority))
488 goto ERROR_EXIT;
489
490
491 ptr = json_get_string_value_for_key(root, "NodeName");
492 if (ptr == NULL)
493 goto ERROR_EXIT;
494 strncpy(wdNode->nodeName, ptr, sizeof(wdNode->nodeName) -1);
495
496 ptr = json_get_string_value_for_key(root, "HostName");
497 if (ptr == NULL)
498 goto ERROR_EXIT;
499 strncpy(wdNode->hostname, ptr, sizeof(wdNode->hostname) -1);
500
501 ptr = json_get_string_value_for_key(root, "VIP");
502 if (ptr == NULL)
503 goto ERROR_EXIT;
504 strncpy(wdNode->delegate_ip, ptr, sizeof(wdNode->delegate_ip) -1);
505
506 ptr = json_get_string_value_for_key(root, "DATA_VERSION_MAJOR");
507 if (ptr == NULL)
508 wdNode->wd_data_major_version = 1;
509 else
510 wdNode->wd_data_major_version = atoi(ptr);
511
512 ptr = json_get_string_value_for_key(root, "DATA_VERSION_MINOR");
513 if (ptr == NULL)
514 wdNode->wd_data_minor_version = 0;
515 else
516 wdNode->wd_data_minor_version = atoi(ptr);
517
518 ptr = json_get_string_value_for_key(root, "PGPOOL_VERSION");
519 if (ptr != NULL)
520 strncpy(wdNode->pgp_version, ptr, sizeof(wdNode->pgp_version) - 1);
521 else
522 wdNode->pgp_version[0] = '0';
523
524 if (authkey)
525 {
526 ptr = json_get_string_value_for_key(root, "authkey");
527 if (ptr != NULL)
528 *authkey = pstrdup(ptr);
529 else
530 *authkey = NULL;
531 }
532
533 return wdNode;
534
535 ERROR_EXIT:
536 if (root)
537 json_value_free(root);
538 pfree(wdNode);
539 return NULL;
540 }
541
parse_beacon_message_json(char * json_data,int data_len,int * state,long * seconds_since_node_startup,long * seconds_since_current_state,int * quorumStatus,int * standbyNodesCount,bool * escalated)542 bool parse_beacon_message_json(char* json_data, int data_len,
543 int* state,
544 long* seconds_since_node_startup,
545 long* seconds_since_current_state,
546 int* quorumStatus,
547 int* standbyNodesCount,
548 bool* escalated)
549 {
550 json_value *root = NULL;
551
552 root = json_parse(json_data,data_len);
553 /* The root node must be object */
554 if (root == NULL || root->type != json_object)
555 goto ERROR_EXIT;
556
557 if (json_get_int_value_for_key(root, "State", state))
558 goto ERROR_EXIT;
559 if (json_get_long_value_for_key(root, "SecondsSinceStartup", seconds_since_node_startup))
560 goto ERROR_EXIT;
561 if (json_get_long_value_for_key(root, "SecondsSinceCurrentState", seconds_since_current_state))
562 goto ERROR_EXIT;
563 if (json_get_bool_value_for_key(root, "Escalated", escalated))
564 goto ERROR_EXIT;
565 if (json_get_int_value_for_key(root, "QuorumStatus", quorumStatus))
566 goto ERROR_EXIT;
567 if (json_get_int_value_for_key(root, "AliveNodeCount", standbyNodesCount))
568 goto ERROR_EXIT;
569
570 if (root)
571 json_value_free(root);
572
573 return true;
574
575 ERROR_EXIT:
576 if (root)
577 json_value_free(root);
578 return false;
579 }
580
get_lifecheck_node_status_change_json(int nodeID,int nodeStatus,char * message,char * authKey)581 char* get_lifecheck_node_status_change_json(int nodeID, int nodeStatus, char* message, char* authKey)
582 {
583 char* json_str;
584 JsonNode* jNode = jw_create_with_object(true);
585
586 if (authKey != NULL && strlen(authKey) > 0)
587 jw_put_string(jNode, WD_IPC_AUTH_KEY, authKey); /* put the auth key*/
588
589 /* add the node ID */
590 jw_put_int(jNode, "NodeID", nodeID);
591 /* add the node status */
592 jw_put_int(jNode, "NodeStatus",nodeStatus);
593 /* add the node message if any */
594 if (message)
595 jw_put_string(jNode, "Message", message);
596
597 jw_finish_document(jNode);
598 json_str = pstrdup(jw_get_json_string(jNode));
599 jw_destroy(jNode);
600 return json_str;
601 }
602
parse_node_status_json(char * json_data,int data_len,int * nodeID,int * nodeStatus,char ** message)603 bool parse_node_status_json(char* json_data, int data_len, int* nodeID, int* nodeStatus, char** message)
604 {
605 json_value* root;
606 char* ptr = NULL;
607 root = json_parse(json_data,data_len);
608
609 /* The root node must be object */
610 if (root == NULL || root->type != json_object)
611 goto ERROR_EXIT;
612
613 if (json_get_int_value_for_key(root, "NodeID", nodeID))
614 goto ERROR_EXIT;
615
616 if (json_get_int_value_for_key(root, "NodeStatus", nodeStatus))
617 goto ERROR_EXIT;
618
619 ptr = json_get_string_value_for_key(root, "Message");
620 if (ptr != NULL)
621 *message = pstrdup(ptr);
622
623 json_value_free(root);
624 return true;
625
626 ERROR_EXIT:
627 if (root)
628 json_value_free(root);
629 return false;
630 }
631
get_WDNodeInfo_from_wd_node_json(json_value * source)632 WDNodeInfo* get_WDNodeInfo_from_wd_node_json(json_value* source)
633 {
634 char* ptr;
635 WDNodeInfo* wdNodeInfo = palloc0(sizeof(WDNodeInfo));
636 if (source->type != json_object)
637 ereport(ERROR,
638 (errmsg("invalid json data"),
639 errdetail("node is not of object type")));
640
641 if (json_get_int_value_for_key(source, "ID", &wdNodeInfo->id))
642 {
643 ereport(ERROR,
644 (errmsg("invalid json data"),
645 errdetail("unable to find Watchdog Node ID")));
646 }
647
648 ptr = json_get_string_value_for_key(source, "NodeName");
649 if (ptr == NULL)
650 {
651 ereport(ERROR,
652 (errmsg("invalid json data"),
653 errdetail("unable to find Watchdog Node Name")));
654 }
655 strncpy(wdNodeInfo->nodeName, ptr, sizeof(wdNodeInfo->nodeName) -1);
656
657 ptr = json_get_string_value_for_key(source, "HostName");
658 if (ptr == NULL)
659 {
660 ereport(ERROR,
661 (errmsg("invalid json data"),
662 errdetail("unable to find Watchdog Host Name")));
663 }
664 strncpy(wdNodeInfo->hostName, ptr, sizeof(wdNodeInfo->hostName) -1);
665
666 ptr = json_get_string_value_for_key(source, "DelegateIP");
667 if (ptr == NULL)
668 {
669 ereport(ERROR,
670 (errmsg("invalid json data"),
671 errdetail("unable to find Watchdog delegate IP")));
672 }
673 strncpy(wdNodeInfo->delegate_ip, ptr, sizeof(wdNodeInfo->delegate_ip) -1);
674
675 if (json_get_int_value_for_key(source, "WdPort", &wdNodeInfo->wd_port))
676 {
677 ereport(ERROR,
678 (errmsg("invalid json data"),
679 errdetail("unable to find WdPort")));
680 }
681
682 if (json_get_int_value_for_key(source, "PgpoolPort", &wdNodeInfo->pgpool_port))
683 {
684 ereport(ERROR,
685 (errmsg("invalid json data"),
686 errdetail("unable to find PgpoolPort")));
687 }
688
689 if (json_get_int_value_for_key(source, "State", &wdNodeInfo->state))
690 {
691 ereport(ERROR,
692 (errmsg("invalid json data"),
693 errdetail("unable to find state")));
694 }
695
696 ptr = json_get_string_value_for_key(source, "StateName");
697 if (ptr == NULL)
698 {
699 ereport(ERROR,
700 (errmsg("invalid json data"),
701 errdetail("unable to find Watchdog State Name")));
702 }
703 strncpy(wdNodeInfo->stateName, ptr, sizeof(wdNodeInfo->stateName) -1);
704
705 if (json_get_int_value_for_key(source, "Priority", &wdNodeInfo->wd_priority))
706 {
707 ereport(ERROR,
708 (errmsg("invalid json data"),
709 errdetail("unable to find state")));
710 }
711
712 return wdNodeInfo;
713
714 }
715
get_wd_node_function_json(char * func_name,int * node_id_set,int count,unsigned int sharedKey,char * authKey)716 char* get_wd_node_function_json(char* func_name, int *node_id_set, int count, unsigned int sharedKey, char* authKey)
717 {
718 char* json_str;
719 int i;
720 JsonNode* jNode = jw_create_with_object(true);
721
722 jw_put_int(jNode, WD_IPC_SHARED_KEY, sharedKey); /* put the shared key*/
723
724 if (authKey != NULL && strlen(authKey) > 0)
725 jw_put_string(jNode, WD_IPC_AUTH_KEY, authKey); /* put the auth key*/
726
727 jw_put_string(jNode, "Function", func_name);
728 jw_put_int(jNode, "NodeCount", count);
729 if (count > 0)
730 {
731 jw_start_array(jNode, "NodeIdList");
732 for (i=0; i < count; i++) {
733 jw_put_int_value(jNode, node_id_set[i]);
734 }
735 jw_end_element(jNode);
736 }
737 jw_finish_document(jNode);
738 json_str = pstrdup(jw_get_json_string(jNode));
739 jw_destroy(jNode);
740 return json_str;
741 }
742
parse_wd_node_function_json(char * json_data,int data_len,char ** func_name,int ** node_id_set,int * count)743 bool parse_wd_node_function_json(char* json_data, int data_len, char** func_name, int **node_id_set, int *count)
744 {
745 json_value *root, *value;
746 char* ptr;
747 int node_count = 0;
748 int i;
749
750 *node_id_set = NULL;
751 *func_name = NULL;
752 *count = 0;
753
754 root = json_parse(json_data,data_len);
755
756 /* The root node must be object */
757 if (root == NULL || root->type != json_object)
758 {
759 json_value_free(root);
760 ereport(LOG,
761 (errmsg("watchdog is unable to parse node function json"),
762 errdetail("invalid json data \"%.*s\"",data_len,json_data)));
763 return false;
764 }
765 ptr = json_get_string_value_for_key(root, "Function");
766 if (ptr == NULL)
767 {
768 json_value_free(root);
769 ereport(LOG,
770 (errmsg("watchdog is unable to parse node function json"),
771 errdetail("function node not found in json data \"%s\"",json_data)));
772 return false;
773 }
774 *func_name = pstrdup(ptr);
775 /* If it is a node function ?*/
776 if (json_get_int_value_for_key(root, "NodeCount", &node_count))
777 {
778 /*node count not found, But we don't care much about this*/
779 json_value_free(root);
780 return true;
781 }
782 if (node_count <= 0)
783 {
784 json_value_free(root);
785 return true;
786 }
787 *count = node_count;
788
789 value = json_get_value_for_key(root,"NodeIdList");
790 if (value == NULL)
791 {
792 json_value_free(root);
793 ereport(LOG,
794 (errmsg("invalid json data"),
795 errdetail("unable to find NodeIdList node from data")));
796 return false;
797 }
798 if (value->type != json_array)
799 {
800 json_value_free(root);
801 ereport(WARNING,
802 (errmsg("invalid json data"),
803 errdetail("NodeIdList node does not contains Array")));
804 return false;
805 }
806 if (node_count != value->u.array.length)
807 {
808 json_value_free(root);
809 ereport(WARNING,
810 (errmsg("invalid json data"),
811 errdetail("NodeIdList array contains %d nodes while expecting %d",value->u.array.length, node_count)));
812 return false;
813 }
814
815 *node_id_set = palloc(sizeof(int) * node_count);
816 for (i = 0; i < node_count; i++)
817 {
818 *node_id_set[i] = value->u.array.values[i]->u.integer;
819 }
820 json_value_free(root);
821 return true;
822 }
823
get_wd_simple_message_json(char * message)824 char* get_wd_simple_message_json(char* message)
825 {
826 char* json_str;
827 JsonNode* jNode = jw_create_with_object(true);
828
829 jw_put_string(jNode, "MESSAGE", message);
830 jw_finish_document(jNode);
831 json_str = pstrdup(jw_get_json_string(jNode));
832 jw_destroy(jNode);
833 return json_str;
834 }
835
836