summaryrefslogtreecommitdiffstats
path: root/tools
ModeNameSize
-rw-r--r--test-requires189logstatsplain
alue='9'>9space:mode:
Diffstat (limited to 'cli/src/cli-cmd-volume.c')
-rw-r--r--cli/src/cli-cmd-volume.c1972
1 files changed, 1972 insertions, 0 deletions
diff --git a/cli/src/cli-cmd-volume.c b/cli/src/cli-cmd-volume.c
new file mode 100644
index 000000000..100be0b73
--- /dev/null
+++ b/cli/src/cli-cmd-volume.c
@@ -0,0 +1,1972 @@
+/*
+ Copyright (c) 2010-2012 Red Hat, Inc. <http://www.redhat.com>
+ This file is part of GlusterFS.
+
+ This file is licensed to you under your choice of the GNU Lesser
+ General Public License, version 3 or any later version (LGPLv3 or
+ later), or the GNU General Public License, version 2 (GPLv2), in all
+ cases as published by the Free Software Foundation.
+*/
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <pthread.h>
+
+#include <sys/socket.h>
+#include <netdb.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+
+#ifndef _CONFIG_H
+#define _CONFIG_H
+#include "config.h"
+#endif
+
+#include "cli.h"
+#include "cli-cmd.h"
+#include "cli-mem-types.h"
+#include "cli1-xdr.h"
+#include "run.h"
+
+extern struct rpc_clnt *global_rpc;
+
+extern rpc_clnt_prog_t *cli_rpc_prog;
+
+int
+cli_cmd_volume_help_cbk (struct cli_state *state, struct cli_cmd_word *in_word,
+ const char **words, int wordcount);
+
+int
+cli_cmd_volume_info_cbk (struct cli_state *state, struct cli_cmd_word *word,
+ const char **words, int wordcount)
+{
+ int ret = -1;
+ rpc_clnt_procedure_t *proc = NULL;
+ call_frame_t *frame = NULL;
+ cli_cmd_volume_get_ctx_t ctx = {0,};
+ cli_local_t *local = NULL;
+ int sent = 0;
+ int parse_error = 0;
+
+ proc = &cli_rpc_prog->proctable[GLUSTER_CLI_GET_VOLUME];
+
+ frame = create_frame (THIS, THIS->ctx->pool);
+ if (!frame)
+ goto out;
+
+ if ((wordcount == 2) || (wordcount == 3 &&
+ !strcmp (words[2], "all"))) {
+ ctx.flags = GF_CLI_GET_NEXT_VOLUME;
+ proc = &cli_rpc_prog->proctable[GLUSTER_CLI_GET_NEXT_VOLUME];
+ } else if (wordcount == 3) {
+ ctx.flags = GF_CLI_GET_VOLUME;
+ ctx.volname = (char *)words[2];
+ if (strlen (ctx.volname) > 1024) {
+ cli_out ("Invalid volume name");
+ goto out;
+ }
+ proc = &cli_rpc_prog->proctable[GLUSTER_CLI_GET_VOLUME];
+ } else {
+ cli_usage_out (word->pattern);
+ parse_error = 1;
+ return -1;
+ }
+
+ local = cli_local_get ();
+
+ if (!local)
+ goto out;
+
+ local->get_vol.flags = ctx.flags;
+ if (ctx.volname)
+ local->get_vol.volname = gf_strdup (ctx.volname);
+
+ frame->local = local;
+
+ if (proc->fn) {
+ ret = proc->fn (frame, THIS, &ctx);
+ }
+
+out:
+ if (ret) {
+ cli_cmd_sent_status_get (&sent);
+ if ((sent == 0) && (parse_error == 0))
+ cli_out ("Getting Volume information failed!");
+ }
+
+ CLI_STACK_DESTROY (frame);
+
+ return ret;
+
+}
+
+int
+cli_cmd_sync_volume_cbk (struct cli_state *state, struct cli_cmd_word *word,
+ const char **words, int wordcount)
+{
+ int ret = -1;
+ rpc_clnt_procedure_t *proc = NULL;
+ call_frame_t *frame = NULL;
+ int sent = 0;
+ int parse_error = 0;
+ dict_t *dict = NULL;
+ cli_local_t *local = NULL;
+ gf_answer_t answer = GF_ANSWER_NO;
+ const char *question = "Sync volume may make data "
+ "inaccessible while the sync "
+ "is in progress. Do you want "
+ "to continue?";
+
+ if ((wordcount < 3) || (wordcount > 4)) {
+ cli_usage_out (word->pattern);
+ parse_error = 1;
+ goto out;
+ }
+
+ dict = dict_new ();
+ if (!dict)
+ goto out;
+
+ if ((wordcount == 3) || !strcmp(words[3], "all")) {
+ ret = dict_set_int32 (dict, "flags", (int32_t)
+ GF_CLI_SYNC_ALL);
+ if (ret) {
+ gf_log (THIS->name, GF_LOG_ERROR, "failed to set"
+ "flag");
+ goto out;
+ }
+ } else {
+ ret = dict_set_str (dict, "volname", (char *) words[3]);
+ if (ret) {
+ gf_log (THIS->name, GF_LOG_ERROR, "failed to set "
+ "volume");
+ goto out;
+ }
+ }
+
+ ret = dict_set_str (dict, "hostname", (char *) words[2]);
+ if (ret) {
+ gf_log (THIS->name, GF_LOG_ERROR, "failed to set hostname");
+ goto out;
+ }
+
+ if (!(state->mode & GLUSTER_MODE_SCRIPT)) {
+ answer = cli_cmd_get_confirmation (state, question);
+ if (GF_ANSWER_NO == answer) {
+ ret = 0;
+ goto out;
+ }
+ }
+
+ proc = &cli_rpc_prog->proctable[GLUSTER_CLI_SYNC_VOLUME];
+
+ frame = create_frame (THIS, THIS->ctx->pool);
+ if (!frame)
+ goto out;
+
+ CLI_LOCAL_INIT (local, words, frame, dict);
+
+ if (proc->fn) {
+ ret = proc->fn (frame, THIS, dict);
+ }
+
+out:
+ if (ret) {
+ cli_cmd_sent_status_get (&sent);
+ if ((sent == 0) && (parse_error == 0))
+ cli_out ("Volume sync failed");
+ }
+
+ CLI_STACK_DESTROY (frame);
+
+ 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;
+ 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);
+ 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)
+{
+ int ret = -1;
+ rpc_clnt_procedure_t *proc = NULL;
+ call_frame_t *frame = NULL;
+ 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;
+ cli_local_t *local = NULL;
+
+ proc = &cli_rpc_prog->proctable[GLUSTER_CLI_CREATE_VOLUME];
+
+ frame = create_frame (THIS, THIS->ctx->pool);
+ if (!frame)
+ goto out;
+
+ ret = cli_cmd_volume_create_parse (words, wordcount, &options);
+
+ if (ret) {
+ cli_usage_out (word->pattern);
+ parse_error = 1;
+ goto out;
+ }
+ /*Check brick order if type is replicate*/
+ ret = dict_get_int32 (options, "type", &type);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Could not get brick type");
+ goto out;
+ }
+ if ((type == GF_CLUSTER_TYPE_REPLICATE) ||
+ (type == GF_CLUSTER_TYPE_STRIPE_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 : "
+