Преглед изворни кода

qnetd: Add support for IPC list command

Signed-off-by: Jan Friesse <jfriesse@redhat.com>
Jan Friesse пре 9 година
родитељ
комит
4e79df8f84

+ 0 - 17
qdevices/qdevice-net-algorithm.c

@@ -311,20 +311,3 @@ qdevice_net_algorithm_register_all(void)
 
 	return (0);
 }
-
-const char *
-qdevice_net_algorithm_type_to_str(enum tlv_decision_algorithm_type algo_type)
-{
-
-	switch (algo_type) {
-	case TLV_DECISION_ALGORITHM_TYPE_TEST: return ("Test"); break;
-	case TLV_DECISION_ALGORITHM_TYPE_FFSPLIT: return ("Fifty-Fifty split"); break;
-	case TLV_DECISION_ALGORITHM_TYPE_2NODELMS: return ("2 Node LMS"); break;
-	case TLV_DECISION_ALGORITHM_TYPE_LMS: return ("LMS"); break;
-	/*
-	 * Default is not defined intentionally. Compiler shows warning when new model is added
-	 */
-	}
-
-	return ("Unknown algorithm");
-}

+ 0 - 3
qdevices/qdevice-net-algorithm.h

@@ -126,9 +126,6 @@ extern int		 qdevice_net_algorithm_register(
 
 extern int		 qdevice_net_algorithm_register_all(void);
 
-extern const char 	*qdevice_net_algorithm_type_to_str(
-    enum tlv_decision_algorithm_type algo_type);
-
 #ifdef __cplusplus
 }
 #endif

+ 3 - 0
qdevices/qdevice-net-cast-vote-timer.c

@@ -60,6 +60,7 @@ qdevice_net_cast_vote_timer_callback(void *data1, void *data2)
 	case TLV_VOTE_ASK_LATER:
 	case TLV_VOTE_WAIT_FOR_REPLY:
 	case TLV_VOTE_NO_CHANGE:
+	case TLV_VOTE_UNDEFINED:
 		/*
 		 * Shouldn't happen
 		 */
@@ -98,6 +99,8 @@ qdevice_net_cast_vote_timer_update(struct qdevice_net_instance *instance, enum t
 	case_processed = 0;
 
 	switch (vote) {
+	case TLV_VOTE_UNDEFINED:
+		break;
 	case TLV_VOTE_ACK:
 	case TLV_VOTE_NACK:
 		case_processed = 1;

+ 1 - 1
qdevices/qdevice-net-ipc-cmd.c

@@ -115,7 +115,7 @@ qdevice_net_ipc_cmd_status_add_basic_info(struct qdevice_net_instance *instance,
 	}
 
 	if (dynar_str_catf(outbuf, "Algorithm:\t\t%s\n",
-	    qdevice_net_algorithm_type_to_str(instance->decision_algorithm)) == -1) {
+	    tlv_decision_algorithm_type_to_str(instance->decision_algorithm)) == -1) {
 		return (0);
 	}
 

+ 19 - 0
qdevices/qnetd-client-msg-received.c

@@ -784,6 +784,9 @@ qnetd_client_msg_received_node_list(struct qnetd_instance *instance, struct qnet
 
 			return (-1);
 		}
+		client->config_version_set = msg->config_version_set;
+		client->config_version = msg->config_version;
+
 		break;
 	case TLV_NODE_LIST_TYPE_MEMBERSHIP:
 		case_processed = 1;
@@ -818,6 +821,14 @@ qnetd_client_msg_received_node_list(struct qnetd_instance *instance, struct qnet
 		exit(1);
 	}
 
+	/*
+	 * Store result vote
+	 */
+	client->last_sent_vote = result_vote;
+	if (result_vote == TLV_VOTE_ACK || result_vote == TLV_VOTE_NACK) {
+		client->last_sent_ack_nack_vote = result_vote;
+	}
+
 	send_buffer = send_buffer_list_get_new(&client->send_buffer_list);
 	if (send_buffer == NULL) {
 		qnetd_log(LOG_ERR, "Can't alloc node list reply msg from list. "
@@ -888,6 +899,14 @@ qnetd_client_msg_received_ask_for_vote(struct qnetd_instance *instance, struct q
 		return (0);
 	}
 
+	/*
+	 * Store result vote
+	 */
+	client->last_sent_vote = result_vote;
+	if (result_vote == TLV_VOTE_ACK || result_vote == TLV_VOTE_NACK) {
+		client->last_sent_ack_nack_vote = result_vote;
+	}
+
 	qnetd_log_debug_ask_for_vote_received(client, msg->seq_number);
 
 	reply_error_code = qnetd_algorithm_ask_for_vote_received(client, msg->seq_number,

+ 8 - 0
qdevices/qnetd-client-send.c

@@ -75,6 +75,14 @@ qnetd_client_send_vote_info(struct qnetd_client *client, uint32_t msg_seq_number
 {
 	struct send_buffer_list_entry *send_buffer;
 
+        /*
+	 * Store result vote
+	 */
+	client->last_sent_vote = vote;
+	if (vote == TLV_VOTE_ACK || vote == TLV_VOTE_NACK) {
+		client->last_sent_ack_nack_vote = vote;
+	}
+
 	qnetd_log_debug_send_vote_info(client, msg_seq_number, vote);
 
 	send_buffer = send_buffer_list_get_new(&client->send_buffer_list);

+ 4 - 0
qdevices/qnetd-client.h

@@ -72,6 +72,8 @@ struct qnetd_client {
 	enum tlv_reply_error_code skipping_msg_reason;
 	void *algorithm_data;
 	struct node_list configuration_node_list;
+	uint8_t config_version_set;
+	uint64_t config_version;
 	struct node_list last_membership_node_list;
 	struct node_list last_quorum_node_list;
 	struct tlv_ring_id last_ring_id;
@@ -83,6 +85,8 @@ struct qnetd_client {
 	int schedule_disconnect;
 	uint32_t dpd_time_since_last_check;
 	uint32_t dpd_msg_received_since_last_check;
+	enum tlv_vote last_sent_vote;
+	enum tlv_vote last_sent_ack_nack_vote;
 	TAILQ_ENTRY(qnetd_client) entries;
 	TAILQ_ENTRY(qnetd_client) cluster_entries;
 };

+ 204 - 0
qdevices/qnetd-ipc-cmd.c

@@ -81,3 +81,207 @@ qnetd_ipc_cmd_status(struct qnetd_instance *instance, struct dynar *outbuf, int
 
 	return (0);
 }
+
+static int
+qnetd_ipc_cmd_add_tie_breaker(const struct qnetd_client *client,
+    struct dynar *outbuf)
+{
+
+	if (dynar_str_catf(outbuf, "    Tie-breaker:\t") == -1) {
+		return (0);
+	}
+
+	switch (client->tie_breaker.mode) {
+	case TLV_TIE_BREAKER_MODE_LOWEST:
+		if (dynar_str_catf(outbuf, "Node with lowest node ID") == -1) {
+			return (0);
+		}
+		break;
+	case TLV_TIE_BREAKER_MODE_HIGHEST:
+		if (dynar_str_catf(outbuf, "Node with highest node ID") == -1) {
+			return (0);
+		}
+		break;
+	case TLV_TIE_BREAKER_MODE_NODE_ID:
+		if (dynar_str_catf(outbuf, "Node with node ID "UTILS_PRI_NODE_ID,
+		    client->tie_breaker.node_id) == -1) {
+			return (0);
+		}
+		break;
+	}
+
+	return (dynar_str_catf(outbuf, "\n") != -1);
+}
+
+static int
+qnetd_ipc_cmd_list_add_node_list(struct dynar *outbuf, int verbose, const struct node_list *nlist)
+{
+	struct node_list_entry *node_info;
+	int i;
+
+	i = 0;
+
+	TAILQ_FOREACH(node_info, nlist, entries) {
+		if (i != 0) {
+			if (dynar_str_catf(outbuf, ", ") == -1) {
+				return (-1);
+			}
+		}
+
+		if (dynar_str_catf(outbuf, UTILS_PRI_NODE_ID, node_info->node_id) == -1) {
+			return (-1);
+		}
+
+		if (node_info->data_center_id != 0) {
+			if (dynar_str_catf(outbuf, " (" UTILS_PRI_DATACENTER_ID ")",
+			    node_info->data_center_id) == -1) {
+				return (-1);
+			}
+
+		}
+
+		i++;
+	}
+
+	return (0);
+}
+
+static int
+qnetd_ipc_cmd_list_add_client_info(const struct qnetd_client *client, struct dynar *outbuf,
+    int verbose, size_t client_no)
+{
+
+	if (dynar_str_catf(outbuf, "    Node ID "UTILS_PRI_NODE_ID":\n",
+	    client->node_id) == -1) {
+		return (-1);
+	}
+
+	if (dynar_str_catf(outbuf, "        Client address:\t\t%s\n",
+	    client->addr_str) == -1) {
+		return (-1);
+	}
+
+	if (verbose) {
+		if (dynar_str_catf(outbuf, "        HB interval:\t\t%"PRIu32"ms\n",
+		    client->heartbeat_interval) == -1) {
+			return (-1);
+		}
+	}
+
+	if (client->config_version_set) {
+		if (dynar_str_catf(outbuf, "        Configuration version:\t"
+		    UTILS_PRI_CONFIG_VERSION"\n", client->config_version) == -1) {
+			return (-1);
+		}
+	}
+
+	if (!node_list_is_empty(&client->configuration_node_list)) {
+		if ((dynar_str_catf(outbuf, "        Configured node list:\t") == -1) ||
+		    (qnetd_ipc_cmd_list_add_node_list(outbuf, verbose,
+		    &client->configuration_node_list) == -1) ||
+		    (dynar_str_catf(outbuf, "\n") == -1)) {
+			return (-1);
+		}
+	}
+
+	if (verbose) {
+		if (dynar_str_catf(outbuf, "        Ring ID:\t\t"UTILS_PRI_RING_ID"\n",
+		    client->last_ring_id.node_id, client->last_ring_id.seq) == -1) {
+			return (-1);
+		}
+	}
+
+	if (!node_list_is_empty(&client->last_membership_node_list)) {
+		if ((dynar_str_catf(outbuf, "        Membership node list:\t") == -1) ||
+		    (qnetd_ipc_cmd_list_add_node_list(outbuf, verbose,
+		    &client->last_membership_node_list) == -1) ||
+		    (dynar_str_catf(outbuf, "\n") == -1)) {
+			return (-1);
+		}
+	}
+
+	if (verbose) {
+		if (dynar_str_catf(outbuf, "        TLS active:\t\t%s",
+		    (client->tls_started ? "Yes" : "No")) == -1) {
+			return (-1);
+		}
+
+		if (client->tls_started && client->tls_peer_certificate_verified) {
+			if (dynar_str_catf(outbuf, " (client certificate verified)") == -1) {
+				return (-1);
+			}
+		}
+
+		if (dynar_str_catf(outbuf, "\n") == -1) {
+			return (-1);
+		}
+	}
+
+	if (client->last_sent_vote != TLV_VOTE_UNDEFINED) {
+		if (dynar_str_catf(outbuf, "        Vote:\t\t\t%s",
+		    tlv_vote_to_str(client->last_sent_vote)) == -1) {
+			return (-1);
+		}
+
+		if (client->last_sent_ack_nack_vote != TLV_VOTE_UNDEFINED) {
+			if (dynar_str_catf(outbuf, " (%s)",
+			    tlv_vote_to_str(client->last_sent_ack_nack_vote)) == -1) {
+				return (-1);
+			}
+		}
+
+		if (dynar_str_catf(outbuf, "\n") == -1) {
+			return (-1);
+		}
+	}
+
+	return (0);
+}
+
+int
+qnetd_ipc_cmd_list(struct qnetd_instance *instance, struct dynar *outbuf, int verbose,
+    const char *cluster_name)
+{
+	struct qnetd_cluster *cluster;
+	struct qnetd_client *client;
+	size_t cluster_no, client_no;
+
+	cluster_no = 0;
+	TAILQ_FOREACH(cluster, &instance->clusters, entries) {
+		if (cluster_name != NULL && strcmp(cluster_name, "") != 0 &&
+		    strcmp(cluster_name, cluster->cluster_name) != 0) {
+			continue ;
+		}
+
+		if (dynar_str_catf(outbuf, "Cluster \"%s\":\n", cluster->cluster_name) == -1) {
+			return (-1);
+		}
+
+		client_no = 0;
+
+		TAILQ_FOREACH(client, &cluster->client_list, cluster_entries) {
+			if (client_no == 0) {
+				if (dynar_str_catf(outbuf, "    Algorithm:\t\t%s\n",
+				    tlv_decision_algorithm_type_to_str(
+				    client->decision_algorithm)) == -1) {
+					return (-1);
+				}
+
+				if (!qnetd_ipc_cmd_add_tie_breaker(client, outbuf)) {
+					return (-1);
+				}
+			}
+
+			if (qnetd_ipc_cmd_list_add_client_info(client, outbuf, verbose,
+			    client_no) == -1) {
+				return (-1);
+			}
+
+			client_no++;
+                }
+
+                cluster_no++;
+	}
+
+	return (0);
+}

+ 3 - 0
qdevices/qnetd-ipc-cmd.h

@@ -45,6 +45,9 @@ extern "C" {
 extern int	qnetd_ipc_cmd_status(struct qnetd_instance *instance,
     struct dynar *outbuf, int verbose);
 
+extern int	qnetd_ipc_cmd_list(struct qnetd_instance *instance,
+    struct dynar *outbuf, int verbose, const char *cluster_name);
+
 #ifdef __cplusplus
 }
 #endif

+ 45 - 7
qdevices/qnetd-ipc.c

@@ -223,6 +223,7 @@ qnetd_ipc_parse_line(struct qnetd_instance *instance, struct unix_socket_client
 	char *str;
 	struct qnetd_ipc_user_data *ipc_user_data;
 	int verbose;
+	char *cluster_name;
 
 	ipc_user_data = (struct qnetd_ipc_user_data *)client->user_data;
 
@@ -230,15 +231,10 @@ qnetd_ipc_parse_line(struct qnetd_instance *instance, struct unix_socket_client
 	token = dynar_simple_lex_token_next(&lex);
 
 	verbose = 0;
+	cluster_name = NULL;
 
 	if (token == NULL) {
-		qnetd_log(LOG_ERR, "Can't alloc memory for simple lex");
-
-		if (qnetd_ipc_send_error(instance, client, "Command too long") != 0) {
-			client->schedule_disconnect = 1;
-		}
-
-		return;
+		goto exit_err_low_mem;
 	}
 
 	str = dynar_data(token);
@@ -257,6 +253,10 @@ qnetd_ipc_parse_line(struct qnetd_instance *instance, struct unix_socket_client
 		}
 	} else if (strcasecmp(str, "status") == 0) {
 		token = dynar_simple_lex_token_next(&lex);
+		if (token == NULL) {
+			goto exit_err_low_mem;
+		}
+
 		str = dynar_data(token);
 
 		if (token != NULL && strcmp(str, "") != 0) {
@@ -274,6 +274,35 @@ qnetd_ipc_parse_line(struct qnetd_instance *instance, struct unix_socket_client
 				client->schedule_disconnect = 1;
 			}
 		}
+	} else if (strcasecmp(str, "list") == 0) {
+		while (((token = dynar_simple_lex_token_next(&lex)) != NULL) &&
+		    (str = dynar_data(token), strcmp(str, "") != 0)) {
+			if (strcasecmp(str, "verbose") == 0) {
+				verbose = 1;
+			} else if (strcasecmp(str, "cluster") == 0) {
+				token = dynar_simple_lex_token_next(&lex);
+				if (token == NULL) {
+					goto exit_err_low_mem;
+				}
+
+				if ((cluster_name = strdup(dynar_data(token))) == NULL) {
+					goto exit_err_low_mem;
+				}
+			} else {
+				break;
+			}
+		}
+
+		if (qnetd_ipc_cmd_list(instance, &client->send_buffer, verbose, cluster_name) != 0) {
+			if (qnetd_ipc_send_error(instance, client, "Can't get QNetd cluster list") != 0) {
+				client->schedule_disconnect = 1;
+			}
+		} else {
+			if (qnetd_ipc_send_buffer(instance, client) != 0) {
+				client->schedule_disconnect = 1;
+			}
+		}
+		free(cluster_name); cluster_name = NULL;
 	} else {
 		qnetd_log(LOG_DEBUG, "IPC client sent unknown command");
 		if (qnetd_ipc_send_error(instance, client, "Unknown command '%s'", str) != 0) {
@@ -282,6 +311,15 @@ qnetd_ipc_parse_line(struct qnetd_instance *instance, struct unix_socket_client
 	}
 
 	dynar_simple_lex_destroy(&lex);
+
+	return ;
+
+exit_err_low_mem:
+	qnetd_log(LOG_ERR, "Can't alloc memory for simple lex");
+
+	if (qnetd_ipc_send_error(instance, client, "Command too long") != 0) {
+		client->schedule_disconnect = 1;
+	}
 }
 
 void

+ 16 - 1
qdevices/tlv.c

@@ -985,6 +985,7 @@ tlv_vote_to_str(enum tlv_vote vote)
 {
 
 	switch (vote) {
+	case TLV_VOTE_UNDEFINED: break;
 	case TLV_VOTE_ACK: return ("ACK"); break;
 	case TLV_VOTE_NACK: return ("NACK"); break;
 	case TLV_VOTE_ASK_LATER: return ("Ask later"); break;
@@ -1009,7 +1010,7 @@ tlv_node_state_to_str(enum tlv_node_state state)
 	return ("Unhandled node state");
 }
 
-extern const char *
+const char *
 tlv_tls_supported_to_str(enum tlv_tls_supported tls_supported)
 {
 
@@ -1021,3 +1022,17 @@ tlv_tls_supported_to_str(enum tlv_tls_supported tls_supported)
 
 	return ("Unhandled tls supported state");
 }
+
+const char *
+tlv_decision_algorithm_type_to_str(enum tlv_decision_algorithm_type algorithm)
+{
+
+	switch (algorithm) {
+	case TLV_DECISION_ALGORITHM_TYPE_TEST: return ("Test"); break;
+	case TLV_DECISION_ALGORITHM_TYPE_FFSPLIT: return ("Fifty-Fifty split"); break;
+	case TLV_DECISION_ALGORITHM_TYPE_2NODELMS: return ("2 Node LMS"); break;
+	case TLV_DECISION_ALGORITHM_TYPE_LMS: return ("LMS"); break;
+	}
+
+	return ("Unknown algorithm");
+}

+ 4 - 0
qdevices/tlv.h

@@ -123,6 +123,7 @@ enum tlv_node_list_type {
 };
 
 enum tlv_vote {
+	TLV_VOTE_UNDEFINED = 0,
 	TLV_VOTE_ACK = 1,
 	TLV_VOTE_NACK = 2,
 	TLV_VOTE_ASK_LATER = 3,
@@ -327,6 +328,9 @@ extern const char *		 tlv_node_state_to_str(enum tlv_node_state state);
 
 extern const char *		 tlv_tls_supported_to_str(enum tlv_tls_supported tls_supported);
 
+extern const char *		 tlv_decision_algorithm_type_to_str(
+    enum tlv_decision_algorithm_type algorithm);
+
 #ifdef __cplusplus
 }
 #endif