From e378778686fca24934e76c41e6496b12162a5420 Mon Sep 17 00:00:00 2001 From: Kaushal M Date: Wed, 3 Aug 2011 18:12:21 +0530 Subject: cli : check for bad brick order while creating replicate volume gluster cli now checks the brick order when creating a replicate or distributed-replicate volume. If a non-optimal order is found the user is given a warning and asked if the volume creation can proceed. Change-Id: I38c4cb65bffb40ccf95319cf3f4f3423a4cdebe9 BUG: 2407 Reviewed-on: http://review.gluster.com/151 Tested-by: Gluster Build System Reviewed-by: Vijay Bellur --- cli/src/cli-cmd-volume.c | 186 ++++++++++++++++++++++++++++++++++++++++++++++- cli/src/cli-cmd.h | 14 ++++ 2 files changed, 199 insertions(+), 1 deletion(-) (limited to 'cli') diff --git a/cli/src/cli-cmd-volume.c b/cli/src/cli-cmd-volume.c index 16dc32328..ec5784176 100644 --- a/cli/src/cli-cmd-volume.c +++ b/cli/src/cli-cmd-volume.c @@ -23,6 +23,11 @@ #include #include +#include +#include +#include +#include + #ifndef _CONFIG_H #define _CONFIG_H #include "config.h" @@ -150,6 +155,156 @@ out: return ret; } +gf_ai_compare_t +cli_cmd_compare_addrinfo (struct addrinfo *first, struct addrinfo *next) +{ + int ret = -1; + struct addrinfo *tmp1 = NULL; + struct addrinfo *tmp2 = NULL; + char firstip[NI_MAXHOST] = {0.}; + char nextip[NI_MAXHOST] = {0,}; + + for (tmp1 = first; tmp1 != NULL; tmp1 = tmp1->ai_next) { + ret = getnameinfo (tmp1->ai_addr, tmp1->ai_addrlen, firstip, + NI_MAXHOST, NULL, 0, NI_NUMERICHOST); + if (ret) + return GF_AI_COMPARE_ERROR; + for (tmp2 = next; tmp2 != NULL; tmp2 = tmp2->ai_next) { + ret = getnameinfo (tmp2->ai_addr, tmp2->ai_addrlen, nextip, + NI_MAXHOST, NULL, 0, NI_NUMERICHOST); + if (ret) + return GF_AI_COMPARE_ERROR; + if (!strcmp (firstip, nextip)) { + return GF_AI_COMPARE_MATCH; + } + } + } + return GF_AI_COMPARE_NO_MATCH; +} + +/* Check for non optimal brick order for replicate : + * Checks if bricks belonging to a replicate volume + * are present on the same server + */ +int32_t +cli_cmd_check_brick_order (struct cli_state *state, const char *bricks, + int brick_count, int sub_count) +{ + int ret = -1; + int i = 0; + int j = 0; + int k = 0; + addrinfo_list_t *ai_list = NULL; + addrinfo_list_t *ai_list_tmp1 = NULL; + addrinfo_list_t *ai_list_tmp2 = NULL; + char *brick = NULL; + char *brick_list = NULL; + char *brick_list_dup = NULL; + char *tmpptr = NULL; + struct addrinfo *ai_info = NULL; + gf_answer_t answer = GF_ANSWER_NO; + const char *failed_question = NULL; + const char *found_question = NULL; + failed_question = "Failed to perform brick order check. " + "Do you want to continue creating the volume? "; + found_question = "Multiple bricks of a replicate volume are present" + " on the same server. This setup is not optimal.\n" + "Do you still want to continue creating the volume? "; + + GF_ASSERT (bricks); + GF_ASSERT (brick_count > 0); + GF_ASSERT (sub_count > 0); + + ai_list = malloc (sizeof (addrinfo_list_t)); + ai_list->info = NULL; + INIT_LIST_HEAD (&ai_list->list); + brick_list = gf_strdup (bricks); + if (brick_list == NULL) { + gf_log ("cli", GF_LOG_DEBUG, "failed to allocate memory"); + goto check_failed; + } + brick_list_dup = brick_list; + /* Resolve hostnames and get addrinfo */ + while (i < brick_count) { + ++i; + brick = strtok_r (brick_list, " \n", &tmpptr); + brick_list = tmpptr; + if (brick == NULL) + goto check_failed; + brick = strtok_r (brick, ":", &tmpptr); + if (brick == NULL) + goto check_failed; + ret = getaddrinfo (brick, NULL, NULL, &ai_info); + if (ret) + goto check_failed; + ai_list_tmp1 = malloc (sizeof (addrinfo_list_t)); + if (ai_list_tmp1 == NULL) + goto check_failed; + ai_list_tmp1->info = ai_info; + list_add_tail (&ai_list_tmp1->list, &ai_list->list); + ai_list_tmp1 = NULL; + } + + i = 0; + ai_list_tmp1 = list_entry (ai_list->list.next, addrinfo_list_t, list); + + /* Check for bad brick order */ + while (i < brick_count) { + ++i; + ai_info = ai_list_tmp1->info; + ai_list_tmp1 = list_entry (ai_list_tmp1->list.next, + addrinfo_list_t, list); + if ( 0 == i % sub_count) { + j = 0; + continue; + } + ai_list_tmp2 = ai_list_tmp1; + k = j; + while (k < sub_count - 1) { + ++k; + ret = cli_cmd_compare_addrinfo (ai_info, + ai_list_tmp2->info); + if (GF_AI_COMPARE_ERROR == ret) + goto check_failed; + if (GF_AI_COMPARE_MATCH == ret) + goto found_bad_brick_order; + ai_list_tmp2 = list_entry (ai_list_tmp2->list.next, + addrinfo_list_t, list); + } + ++j; + } + gf_log ("cli", GF_LOG_INFO, "Brick order okay"); + ret = 0; + goto out; + +check_failed: + gf_log ("cli", GF_LOG_INFO, "Failed bad brick order check"); + answer = cli_cmd_get_confirmation(state, failed_question); + if (GF_ANSWER_YES == answer) + ret = 0; + goto out; + +found_bad_brick_order: + gf_log ("cli", GF_LOG_INFO, "Bad brick order found"); + answer = cli_cmd_get_confirmation (state, found_question); + if (GF_ANSWER_YES == answer) + ret = 0; +out: + ai_list_tmp2 = NULL; + i = 0; + if (brick_list_dup) + GF_FREE (brick_list_dup); + list_for_each_entry (ai_list_tmp1, &ai_list->list, list) { + if (ai_list_tmp1->info) + freeaddrinfo (ai_list_tmp1->info); + if (ai_list_tmp2) + free (ai_list_tmp2); + ai_list_tmp2 = ai_list_tmp1; + } + free (ai_list_tmp2); + return ret; +} + int cli_cmd_volume_create_cbk (struct cli_state *state, struct cli_cmd_word *word, const char **words, int wordcount) @@ -160,6 +315,11 @@ cli_cmd_volume_create_cbk (struct cli_state *state, struct cli_cmd_word *word, dict_t *options = NULL; int sent = 0; int parse_error = 0; + char *brick_list = NULL; + int32_t brick_count = 0; + int32_t sub_count = 0; + int32_t type = GF_CLUSTER_TYPE_NONE; + proc = &cli_rpc_prog->proctable[GLUSTER_CLI_CREATE_VOLUME]; @@ -174,7 +334,31 @@ cli_cmd_volume_create_cbk (struct cli_state *state, struct cli_cmd_word *word, parse_error = 1; goto out; } - + /*Check brick order if type is replicate*/ + if (dict_get_int32 (options, "type", &type) == 0 && type == GF_CLUSTER_TYPE_REPLICATE) { + if ((ret = dict_get_str (options, "bricks", &brick_list)) != 0) { + gf_log ("cli", GF_LOG_ERROR, "Replica bricks check : " + "Could not retrieve bricks list"); + goto out; + } + if ((ret = dict_get_int32 (options, "count", &brick_count)) != 0) { + gf_log ("cli", GF_LOG_ERROR, "Replica bricks check : " + "Could not retrieve brick count"); + goto out; + } + if ((ret = dict_get_int32 (options, "replica-count", &sub_count)) != 0) { + gf_log ("cli", GF_LOG_ERROR, "Replica bricks check : " + "Could not retrieve replica count"); + goto out; + } + gf_log ("cli", GF_LOG_INFO, "Replicate cluster type found." + " Checking brick order."); + ret = cli_cmd_check_brick_order (state, brick_list, brick_count, sub_count); + if (ret) { + gf_log("cli", GF_LOG_INFO, "Not creating volume because of bad brick order"); + goto out; + } + } if (proc->fn) { ret = proc->fn (frame, THIS, options); } diff --git a/cli/src/cli-cmd.h b/cli/src/cli-cmd.h index f6abfa464..1878571fa 100644 --- a/cli/src/cli-cmd.h +++ b/cli/src/cli-cmd.h @@ -25,7 +25,10 @@ #include "config.h" #endif +#include + #include "cli.h" +#include "list.h" typedef enum { GF_ANSWER_YES = 1, @@ -55,6 +58,17 @@ typedef struct cli_profile_info_ { double percentage_avg_latency; } cli_profile_info_t; +typedef struct addrinfo_list { + struct list_head list; + struct addrinfo *info; +} addrinfo_list_t; + +typedef enum { + GF_AI_COMPARE_NO_MATCH = 0, + GF_AI_COMPARE_MATCH = 1, + GF_AI_COMPARE_ERROR = 2 +} gf_ai_compare_t; + typedef struct cli_cmd_volume_get_ctx_ cli_cmd_volume_get_ctx_t; int cli_cmd_volume_register (struct cli_state *state); -- cgit