Patchwork [BUG:1657] mgmt/glusterd: replace-brick validations

login
register
Submitter Pranith K
Date 2010-09-22 09:51:02
Message ID <20100922095102.GA21057@dev.gluster.com>
Download mbox | patch
Permalink /patch/4923/
State Accepted
Headers show

Comments

Pranith K - 2010-09-22 09:51:02
Signed-off-by: Pranith Kumar K <pranithk@gluster.com>
---
 cli/src/cli-cmd-parser.c                     |   59 +++++++-------
 cli/src/cli-cmd-volume.c                     |    2 +-
 cli/src/cli3_1-cops.c                        |    3 +
 rpc/xdr/src/cli1-xdr.c                       |    4 +-
 rpc/xdr/src/cli1-xdr.h                       |    1 +
 rpc/xdr/src/cli1.x                           |    1 +
 xlators/mgmt/glusterd/src/glusterd-handler.c |   56 ++++---------
 xlators/mgmt/glusterd/src/glusterd-op-sm.c   |  112 +++++++++++++++++++++++---
 xlators/mgmt/glusterd/src/glusterd-utils.c   |   34 ++++++++
 xlators/mgmt/glusterd/src/glusterd-utils.h   |    2 +
 10 files changed, 193 insertions(+), 81 deletions(-)

Patch

diff --git a/cli/src/cli-cmd-parser.c b/cli/src/cli-cmd-parser.c
index 2b7cdd9..9de13e5 100644
--- a/cli/src/cli-cmd-parser.c
+++ b/cli/src/cli-cmd-parser.c
@@ -729,42 +729,45 @@  cli_cmd_volume_replace_brick_parse (const char **words, int wordcount,
         }
 
         delimiter = strchr ((char *)words[3], ':');
-        if (delimiter && delimiter != words[3]
-            && *(delimiter+1) == '/') {
+        if (!delimiter || delimiter == words[3]
+            || *(delimiter+1) != '/') {
+                cli_out ("wrong brick type: %s, use "
+                        "<HOSTNAME>:<export-dir-abs-path>", words[3]);
+                ret = -1;
+                goto out;
+        } else {
                 cli_path_strip_trailing_slashes (delimiter + 1);
-                ret = dict_set_str (dict, "src-brick", (char *)words[3]);
-
-                if (ret)
-                        goto out;
+        }
+        ret = dict_set_str (dict, "src-brick", (char *)words[3]);
 
-                if (wordcount < 5) {
-                        ret = -1;
-                        goto out;
-                }
+        if (ret)
+                goto out;
 
-                delimiter = strchr ((char *)words[4], ':');
-                if (!delimiter || delimiter == words[4]
-                    || *(delimiter+1) != '/') {
-                        cli_out ("wrong brick type: %s, use "
-                                "<HOSTNAME>:<export-dir-abs-path>", words[4]);
-                        ret = -1;
-                        goto out;
-                } else {
-                        cli_path_strip_trailing_slashes (delimiter + 1);
-                }
+        if (wordcount < 5) {
+                ret = -1;
+                goto out;
+        }
 
+        delimiter = strchr ((char *)words[4], ':');
+        if (!delimiter || delimiter == words[4]
+            || *(delimiter+1) != '/') {
+                cli_out ("wrong brick type: %s, use "
+                        "<HOSTNAME>:<export-dir-abs-path>", words[4]);
+                ret = -1;
+                goto out;
+        } else {
+                cli_path_strip_trailing_slashes (delimiter + 1);
+        }
 
-                ret = dict_set_str (dict, "dst-brick", (char *)words[4]);
 
-                if (ret)
-                        goto out;
+        ret = dict_set_str (dict, "dst-brick", (char *)words[4]);
 
-                op_index = 5;
-        } else {
-                op_index = 3;
-        }
+        if (ret)
+                goto out;
 
-        if (wordcount < (op_index + 1)) {
+        op_index = 5;
+        if ((wordcount < (op_index + 1)) ||
+            (wordcount > (op_index + 1))) {
                 ret = -1;
                 goto out;
         }
diff --git a/cli/src/cli-cmd-volume.c b/cli/src/cli-cmd-volume.c
index 28104c1..c834517 100644
--- a/cli/src/cli-cmd-volume.c
+++ b/cli/src/cli-cmd-volume.c
@@ -611,7 +611,7 @@  void
 cli_cmd_volume_replace_brick_usage ()
 {
         cli_out("Usage: volume replace-brick <VOLNAME> "
-                "(<BRICK> <NEW-BRICK>) start|pause|abort|status");
+                "<BRICK> <NEW-BRICK> start|pause|abort|status");
 }
 
 
diff --git a/cli/src/cli3_1-cops.c b/cli/src/cli3_1-cops.c
index 53b80c5..78683cc 100644
--- a/cli/src/cli3_1-cops.c
+++ b/cli/src/cli3_1-cops.c
@@ -937,6 +937,9 @@  gf_cli3_1_replace_brick_cbk (struct rpc_req *req, struct iovec *iov,
                 break;
         }
 
+        if (rsp.op_ret && (strcmp (rsp.op_errstr, ""))) {
+                rb_operation_str = rsp.op_errstr;
+        }
 
         gf_log ("cli", GF_LOG_NORMAL, "Received resp to replace brick");
         cli_out ("%s",
diff --git a/rpc/xdr/src/cli1-xdr.c b/rpc/xdr/src/cli1-xdr.c
index 93f7e76..ca2bc09 100644
--- a/rpc/xdr/src/cli1-xdr.c
+++ b/rpc/xdr/src/cli1-xdr.c
@@ -94,7 +94,7 @@  bool_t
 xdr_gf1_cli_probe_rsp (XDR *xdrs, gf1_cli_probe_rsp *objp)
 {
 
-        register int32_t *buf;
+	register int32_t *buf;
 
 	if (xdrs->x_op == XDR_ENCODE) {
 		buf = XDR_INLINE (xdrs, 3 * BYTES_PER_XDR_UNIT);
@@ -452,6 +452,8 @@  xdr_gf1_cli_replace_brick_rsp (XDR *xdrs, gf1_cli_replace_brick_rsp *objp)
 		 return FALSE;
 	 if (!xdr_int (xdrs, &objp->op_errno))
 		 return FALSE;
+	 if (!xdr_string (xdrs, &objp->op_errstr, ~0))
+		 return FALSE;
 	 if (!xdr_string (xdrs, &objp->volname, ~0))
 		 return FALSE;
 	 if (!xdr_string (xdrs, &objp->status, ~0))
diff --git a/rpc/xdr/src/cli1-xdr.h b/rpc/xdr/src/cli1-xdr.h
index c6d8e8b..0225ace 100644
--- a/rpc/xdr/src/cli1-xdr.h
+++ b/rpc/xdr/src/cli1-xdr.h
@@ -275,6 +275,7 @@  typedef struct gf1_cli_replace_brick_req gf1_cli_replace_brick_req;
 struct gf1_cli_replace_brick_rsp {
 	int op_ret;
 	int op_errno;
+	char *op_errstr;
 	char *volname;
 	char *status;
 };
diff --git a/rpc/xdr/src/cli1.x b/rpc/xdr/src/cli1.x
index 3f37f6d..ba4288b 100644
--- a/rpc/xdr/src/cli1.x
+++ b/rpc/xdr/src/cli1.x
@@ -188,6 +188,7 @@  struct gf1_cli_get_vol_rsp {
  struct gf1_cli_replace_brick_rsp {
         int     op_ret;
         int     op_errno;
+        string  op_errstr<>;
         string  volname<>;
         string  status<>;
 }  ;
diff --git a/xlators/mgmt/glusterd/src/glusterd-handler.c b/xlators/mgmt/glusterd/src/glusterd-handler.c
index 0c33b65..4d9a662 100644
--- a/xlators/mgmt/glusterd/src/glusterd-handler.c
+++ b/xlators/mgmt/glusterd/src/glusterd-handler.c
@@ -1126,8 +1126,6 @@  glusterd_handle_create_volume (rpcsvc_request_t *req)
         gf1_cli_create_vol_rsp  rsp         = {0,};
         glusterd_conf_t        *priv        = NULL;
         int                     err_ret     = 0;
-        glusterd_brickinfo_t   *tmpbrkinfo  = NULL;
-        glusterd_volinfo_t     *volinfo     = NULL;
         xlator_t               *this        = NULL;
         char                   *free_ptr    = NULL;
         char                   *trans_type  = NULL;
@@ -1137,10 +1135,10 @@  glusterd_handle_create_volume (rpcsvc_request_t *req)
         GF_ASSERT (req);
 
         this = THIS;
-        priv = this->private;
-
         GF_ASSERT(this);
 
+        priv = this->private;
+
         if (!gf_xdr_to_cli_create_vol_req (req->msg[0], &cli_req)) {
                 //failed to decode msg;
                 req->rpc_err = GARBAGE_ARGS;
@@ -1250,22 +1248,12 @@  glusterd_handle_create_volume (rpcsvc_request_t *req)
                         goto out;
                 }
 brick_validation:
-                list_for_each_entry (volinfo, &priv->volumes, vol_list) {
-
-                        list_for_each_entry (tmpbrkinfo, &volinfo->bricks,
-                                             brick_list) {
-
-                                if ((!strcmp(brickinfo->hostname, tmpbrkinfo->
-                                    hostname) && !strcmp(brickinfo->path,
-                                    tmpbrkinfo->path))) {
-                                        snprintf(err_str, 1048, "Brick %s already"
-                                                " in use", brick);
-                                        gf_log ("glusterd", GF_LOG_ERROR, "%s",
-                                                err_str);
-                                        err_ret = 1;
-                                        goto out;
-                                }
-                        }
+                err_ret = glusterd_is_exisiting_brick (brickinfo->hostname,
+                                                       brickinfo->path);
+                if (err_ret) {
+                        snprintf(err_str, 1048, "Brick: %s already in use",
+                                 brick);
+                        goto out;
                 }
         }
         ret = glusterd_create_volume (req, dict);
@@ -1406,18 +1394,16 @@  glusterd_handle_add_brick (rpcsvc_request_t *req)
         char                            err_str[1048];
         gf1_cli_add_brick_rsp           rsp = {0,};
         glusterd_volinfo_t              *volinfo = NULL;
-        glusterd_brickinfo_t            *tmpbrkinfo = NULL;
         int32_t                         err_ret = 0;
-        glusterd_volinfo_t              *tmpvolinfo = NULL;
         glusterd_conf_t                 *priv = NULL;
         xlator_t                        *this = NULL;
         char                            *free_ptr = NULL;
 
         this = THIS;
-        priv = this->private;
-
         GF_ASSERT(this);
 
+        priv = this->private;
+
         GF_ASSERT (req);
 
         if (!gf_xdr_to_cli_add_brick_req (req->msg[0], &cli_req)) {
@@ -1544,22 +1530,12 @@  brick_val:
                         goto out;
                 }
 brick_validation:
-                list_for_each_entry (tmpvolinfo, &priv->volumes, vol_list) {
-
-                        list_for_each_entry (tmpbrkinfo, &tmpvolinfo->bricks,
-                                             brick_list) {
-
-                                if ((!strcmp(brickinfo->hostname, tmpbrkinfo->
-                                    hostname) && !strcmp(brickinfo->path,
-                                    tmpbrkinfo->path))) {
-                                        snprintf(err_str, 1048, "Brick %s already"
-                                                "in use", brick);
-                                        gf_log ("glusterd", GF_LOG_ERROR, "%s",
-                                                err_str);
-                                        err_ret = 1;
-                                        goto out;
-                                }
-                        }
+                err_ret = glusterd_is_exisiting_brick (brickinfo->hostname,
+                                                       brickinfo->path);
+                if (err_ret) {
+                        snprintf(err_str, 1048, "Brick: %s already in use",
+                                 brick);
+                        goto out;
                 }
         }
 
diff --git a/xlators/mgmt/glusterd/src/glusterd-op-sm.c b/xlators/mgmt/glusterd/src/glusterd-op-sm.c
index 4506b3a..b8d2778 100644
--- a/xlators/mgmt/glusterd/src/glusterd-op-sm.c
+++ b/xlators/mgmt/glusterd/src/glusterd-op-sm.c
@@ -753,16 +753,22 @@  out:
 }
 
 static int
-glusterd_op_stage_replace_brick (gd1_mgmt_stage_op_req *req)
+glusterd_op_stage_replace_brick (gd1_mgmt_stage_op_req *req, char **op_errstr)
 {
         int                                      ret           = 0;
         dict_t                                  *dict          = NULL;
         char                                    *src_brick     = NULL;
         char                                    *dst_brick     = NULL;
         char                                    *volname       = NULL;
+        gf1_cli_replace_op                       replace_op    = 0;
         glusterd_volinfo_t                      *volinfo       = NULL;
         glusterd_brickinfo_t                    *src_brickinfo = NULL;
-        gf_boolean_t                             exists        = _gf_false;
+        char                                    *host          = NULL;
+        char                                    *path          = NULL;
+        char                                    msg[2048]      = {0};
+        char                                    *dup_dstbrick  = NULL;
+        glusterd_peerinfo_t                     *peerinfo = NULL;
+        struct stat                             st_buf = {0,};
 
         GF_ASSERT (req);
 
@@ -804,36 +810,116 @@  glusterd_op_stage_replace_brick (gd1_mgmt_stage_op_req *req)
                 goto out;
         }
 
+        ret = dict_get_int32 (dict, "operation", (int32_t *)&replace_op);
+        if (ret) {
+                gf_log ("", GF_LOG_DEBUG,
+                        "dict get on replace-brick operation failed");
+                goto out;
+        }
+
         ret = glusterd_volinfo_find (volname, &volinfo);
         if (ret) {
-                gf_log ("", GF_LOG_ERROR, "Unable to allocate memory");
+                snprintf (msg, sizeof (msg), "volume: %s does not exist",
+                          volname);
+                *op_errstr = gf_strdup (msg);
+                goto out;
+        }
+
+        if (GLUSTERD_STATUS_STARTED != volinfo->status) {
+                ret = -1;
+                snprintf (msg, sizeof (msg), "volume: %s is not started",
+                          volname);
+                *op_errstr = gf_strdup (msg);
                 goto out;
         }
 
         ret = glusterd_brickinfo_get (src_brick, volinfo,
                                       &src_brickinfo);
         if (ret) {
-                gf_log ("", GF_LOG_DEBUG, "Unable to get src-brickinfo");
+                snprintf (msg, sizeof (msg), "brick: %s does not exist in "
+                          "volume: %s", src_brick, volname);
+                *op_errstr = gf_strdup (msg);
                 goto out;
         }
 
         if (!glusterd_is_local_addr (src_brickinfo->hostname)) {
                 gf_log ("", GF_LOG_DEBUG,
                         "I AM THE SOURCE HOST");
-                exists = glusterd_check_volume_exists (volname);
+        }
 
-                if (!exists) {
-                        gf_log ("", GF_LOG_ERROR, "Volume with name: %s "
-                                "does not exist",
-                                volname);
+        dup_dstbrick = gf_strdup (dst_brick);
+        if (!dup_dstbrick) {
+                ret = -1;
+                gf_log ("", GF_LOG_ERROR, "Memory allocation failed");
+                goto out;
+        }
+        host = strtok (dup_dstbrick, ":");
+        path = strtok (NULL, ":");
+
+        if (!host || !path) {
+                gf_log ("", GF_LOG_ERROR,
+                        "dst brick %s is not of form <HOSTNAME>:<export-dir>",
+                        dst_brick);
+                ret = -1;
+                goto out;
+        }
+        if (glusterd_is_exisiting_brick (host, path)) {
+                snprintf(msg, sizeof(msg), "Brick: %s:%s already in use",
+                         host, path);
+                *op_errstr = gf_strdup (msg);
+                ret = -1;
+                goto out;
+        }
+
+        if (!glusterd_is_local_addr (host)) {
+                ret = stat (path, &st_buf);
+                if (ret == -1) {
+                        snprintf (msg, sizeof (msg) ,"path: %s for brick: %s"
+                        " does not exist", path, dst_brick);
+                        gf_log ("glusterd", GF_LOG_ERROR, "%s", msg);
+                        *op_errstr = gf_strdup (msg);
+                        goto out;
+                }
+                if (!S_ISDIR (st_buf.st_mode)) {
+                        snprintf (msg, sizeof (msg), "Volume name %s, brick"
+                                  ": %s, path %s is not a directory", volname,
+                                  dst_brick, path);
+                        gf_log ("glusterd", GF_LOG_ERROR,
+                                "%s", msg);
+                        *op_errstr = gf_strdup (msg);
+                        ret = -1;
+                        goto out;
+                }
+        } else {
+                ret = glusterd_friend_find (NULL, host, &peerinfo);
+                if (ret) {
+                        snprintf (msg, sizeof (msg), "%s, is not a friend",
+                                  host);
+                        *op_errstr = gf_strdup (msg);
+                        goto out;
+                }
+
+                if (!peerinfo->connected) {
+                        snprintf (msg, sizeof (msg), "%s, is not connected at "
+                                  "the moment", host);
+                        *op_errstr = gf_strdup (msg);
                         ret = -1;
                         goto out;
                 }
-        }
 
+                if (GD_FRIEND_STATE_BEFRIENDED != peerinfo->state.state) {
+                        snprintf (msg, sizeof (msg), "%s, is not befriended "
+                                  "at the moment", host);
+                        *op_errstr = gf_strdup (msg);
+                        ret = -1;
+                        goto out;
+                }
+        }
         ret = 0;
 
 out:
+        if (dup_dstbrick)
+                GF_FREE (dup_dstbrick);
         if (dict)
                 dict_unref (dict);
         gf_log ("", GF_LOG_DEBUG, "Returning %d", ret);
@@ -3657,6 +3743,10 @@  glusterd_op_send_cli_response (int32_t op, int32_t op_ret,
                                         rsp.status = "";
                                 rsp.op_ret = op_ret;
                                 rsp.op_errno = op_errno;
+                                if (op_errstr)
+                                        rsp.op_errstr = op_errstr;
+                                else
+                                        rsp.op_errstr = "";
                                 rsp.volname = "";
                                 cli_rsp = &rsp;
                                 sfunc = gf_xdr_serialize_cli_replace_brick_rsp;
@@ -3949,7 +4039,7 @@  glusterd_op_stage_validate (gd1_mgmt_stage_op_req *req, char **op_errstr)
                         break;
 
                 case GD_OP_REPLACE_BRICK:
-                        ret = glusterd_op_stage_replace_brick (req);
+                        ret = glusterd_op_stage_replace_brick (req, op_errstr);
                         break;
 
                 case GD_OP_SET_VOLUME:
diff --git a/xlators/mgmt/glusterd/src/glusterd-utils.c b/xlators/mgmt/glusterd/src/glusterd-utils.c
index 358d6ff..e359289 100644
--- a/xlators/mgmt/glusterd/src/glusterd-utils.c
+++ b/xlators/mgmt/glusterd/src/glusterd-utils.c
@@ -1716,3 +1716,37 @@  glusterd_volume_count_get (void)
         return ret;
 
 }
+
+int
+glusterd_is_exisiting_brick (char *hostname, char *path)
+{
+        glusterd_brickinfo_t            *tmpbrkinfo = NULL;
+        glusterd_volinfo_t              *volinfo     = NULL;
+        glusterd_conf_t                 *priv = NULL;
+        xlator_t                        *this = NULL;
+        int                             ret = 0;
+
+        GF_ASSERT (hostname);
+        GF_ASSERT (path);
+
+        this = THIS;
+        GF_ASSERT (this);
+
+        priv = this->private;
+        list_for_each_entry (volinfo, &priv->volumes, vol_list) {
+
+                list_for_each_entry (tmpbrkinfo, &volinfo->bricks,
+                                     brick_list) {
+
+                        if ((!strcmp(hostname, tmpbrkinfo-> hostname)
+                            && !strcmp(path, tmpbrkinfo->path))) {
+                                gf_log ("glusterd", GF_LOG_ERROR, "Brick %s:%s"
+                                        " already in use", hostname, path);
+                                ret = 1;
+                                goto out;
+                        }
+                }
+        }
+out:
+        return ret;
+}
diff --git a/xlators/mgmt/glusterd/src/glusterd-utils.h b/xlators/mgmt/glusterd/src/glusterd-utils.h
index e03968d..72715a0 100644
--- a/xlators/mgmt/glusterd/src/glusterd-utils.h
+++ b/xlators/mgmt/glusterd/src/glusterd-utils.h
@@ -158,4 +158,6 @@  glusterd_volume_count_get (void);
 int32_t
 glusterd_add_volume_to_dict (glusterd_volinfo_t *volinfo,
                              dict_t  *dict, int32_t count);
+int
+glusterd_is_exisiting_brick (char *hostname, char *path);
 #endif