summaryrefslogtreecommitdiffstats
path: root/rpc
diff options
context:
space:
mode:
authorPrasanna Kumar Kalever <prasanna.kalever@redhat.com>2018-02-05 15:07:26 +0530
committerPrasanna Kumar Kalever <prasanna.kalever@redhat.com>2018-02-07 16:49:21 +0530
commit540e81676b1011dcf85fbe5cd6739a4f2143b2ab (patch)
tree7eed76faf5483e03bbbe59bb23ede3675ae6ad97 /rpc
parentf217c0bf9cf464e21c01fa50643b778f236acedb (diff)
replace: add replace feature
1. create conf in new node 2. delete conf from old node 3. replace portals from nodes hosting other paths (HA) $ gluster-block create sample/block ha 3 192.168.124.57,192.168.124.26,192.168.124.30 1GiB --json-pretty { "IQN":"iqn.2016-12.org.gluster-block:d516bb5c-5f56-4d9c-96a7-385df19c2e2c", "PORTAL(S)":[ "192.168.124.57:3260", "192.168.124.26:3260", "192.168.124.30:3260" ], "RESULT":"SUCCESS" } $ gluster-block help gluster-block (0.3) usage: gluster-block <command> <volname[/blockname]> [<args>] [--json*] commands: [...] replace <volname/blockname> <old-node> <new-node> [force] replace operations. [...] supported JSON formats: --json|--json-plain|--json-spaced|--json-pretty $ gluster-block replace sample/block 192.168.124.26 192.168.124.56 --json-pretty { "NAME":"block", "CREATE SUCCESS":"192.168.124.56", "DELETE SUCCESS":"192.168.124.26", "REPLACE PORTAL SUCCESS ON":[ "192.168.124.57", "192.168.124.30" ], "RESULT":"SUCCESS" } Fixes: #4 Change-Id: I0411d15c407111db0d423052d9a6bc075174bf90 Signed-off-by: Prasanna Kumar Kalever <prasanna.kalever@redhat.com>
Diffstat (limited to 'rpc')
-rw-r--r--rpc/block_svc_routines.c1343
-rw-r--r--rpc/glfs-operations.c109
-rw-r--r--rpc/glfs-operations.h4
-rw-r--r--rpc/rpcl/block.x19
4 files changed, 1236 insertions, 239 deletions
diff --git a/rpc/block_svc_routines.c b/rpc/block_svc_routines.c
index 433b185..4230964 100644
--- a/rpc/block_svc_routines.c
+++ b/rpc/block_svc_routines.c
@@ -37,9 +37,17 @@
# define GB_JSON_OBJ_TO_STR(x) json_object_new_string(x?x:"")
# define GB_DEFAULT_ERRMSG "Operation failed, please check the log "\
"file to find the reason."
+# define GB_GET_PORTAL_TPG "targetcli /iscsi/" GB_TGCLI_IQN_PREFIX \
+ "'%s' ls | grep -e tpg -e '%s' | grep -B1 '%s' | grep -o 'tpg\\w'"
+# define GB_CHECK_PORTAL "targetcli /iscsi/" GB_TGCLI_IQN_PREFIX \
+ "'%s' ls | grep '%s' > " DEVNULLPATH
# define GB_OLD_CAP_MAX 9
+# define GB_OP_SKIPPED 222
+# define GB_NODE_NOT_EXIST 223
+# define GB_NODE_IN_USE 224
+
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
typedef enum operations {
@@ -47,6 +55,8 @@ typedef enum operations {
DELETE_SRV,
MODIFY_SRV,
MODIFY_TPGC_SRV,
+ REPLACE_SRV,
+ REPLACE_GET_PORTAL_TPG_SRV,
LIST_SRV,
INFO_SRV,
VERSION_SRV
@@ -63,6 +73,23 @@ typedef struct blockRemoteObj {
} blockRemoteObj;
+typedef struct blockRemoteResp {
+ char *attempt;
+ char *success;
+ char *skipped;
+ int status;
+} blockRemoteResp;
+
+
+typedef struct blockRemoteReplaceResp {
+ blockRemoteResp *cop;
+ blockRemoteResp *dop;
+ blockRemoteResp *rop;
+ bool force;
+ int status;
+} blockRemoteReplaceResp;
+
+
typedef struct blockRemoteModifyResp {
char *attempt;
char *success;
@@ -87,13 +114,6 @@ typedef struct blockRemoteCreateResp {
} blockRemoteCreateResp;
-typedef struct blockServerDef {
- size_t nhosts;
- char **hosts;
-} blockServerDef;
-typedef blockServerDef *blockServerDefPtr;
-
-
static char *
getLastWordNoDot(char *line)
{
@@ -174,22 +194,56 @@ mapJsonFlagToJsonCstring(int jsonflag)
}
-static bool
-blockhostIsValid(char *status)
+void
+blockFormatErrorResponse(operations op, int json_resp, int errCode,
+ char *errMsg, struct blockResponse *reply)
{
- switch (blockMetaStatusEnumParse(status)) {
- case GB_CONFIG_SUCCESS:
- case GB_CLEANUP_INPROGRESS:
- case GB_AUTH_ENFORCEING:
- case GB_AUTH_ENFORCED:
- case GB_AUTH_ENFORCE_FAIL:
- case GB_AUTH_CLEAR_ENFORCED:
- case GB_AUTH_CLEAR_ENFORCEING:
- case GB_AUTH_CLEAR_ENFORCE_FAIL:
- return TRUE;
+ json_object *json_obj = NULL;
+
+
+ if (!reply) {
+ return;
}
- return FALSE;
+ reply->exit = errCode;
+ if (json_resp) {
+ json_obj = json_object_new_object();
+ json_object_object_add(json_obj, "RESULT", GB_JSON_OBJ_TO_STR("FAIL"));
+ json_object_object_add(json_obj, "errCode", json_object_new_int(errCode));
+ json_object_object_add(json_obj, "errMsg", GB_JSON_OBJ_TO_STR(errMsg));
+ GB_ASPRINTF(&reply->out, "%s\n",
+ json_object_to_json_string_ext(json_obj,
+ mapJsonFlagToJsonCstring(json_resp)));
+ json_object_put(json_obj);
+ } else {
+ if (op != INFO_SRV) {
+ GB_ASPRINTF (&reply->out, "%s\nRESULT:FAIL\n", errMsg);
+ } else {
+ GB_ASPRINTF (&reply->out, "%s\n", errMsg);
+ }
+ }
+}
+
+
+static void
+blockStr2arrayAddToJsonObj(json_object *json_obj, char *string, char *label,
+ json_object **json_array)
+{
+ char *tmp = NULL;
+ json_object *json_array1 = NULL;
+
+ if (!string)
+ return;
+
+ json_array1 = json_object_new_array();
+ tmp = strtok (string, " ");
+ while (tmp != NULL)
+ {
+ json_object_array_add(json_array1, GB_JSON_OBJ_TO_STR(tmp));
+ tmp = strtok (NULL, " ");
+ }
+ json_object_object_add(json_obj, label, json_array1);
+ *json_array = json_array1;
}
@@ -464,6 +518,14 @@ glusterBlockCallRPC_1(char *host, void *cobj,
case LIST_SRV:
case INFO_SRV:
goto out;
+ case REPLACE_SRV:
+ *rpc_sent = TRUE;
+ if (block_replace_1((blockReplace *)cobj, &reply, clnt) != RPC_SUCCESS) {
+ LOG("mgmt", GB_LOG_ERROR, "%son host %s",
+ clnt_sperror(clnt, "block remote replace failed"), host);
+ goto out;
+ }
+ break;
}
ret = reply.exit;
@@ -514,24 +576,6 @@ glusterBlockCallRPC_1(char *host, void *cobj,
}
-static void
-blockServerDefFree(blockServerDefPtr blkServers)
-{
- size_t i;
-
-
- if (!blkServers) {
- return;
- }
-
- for (i = 0; i < blkServers->nhosts; i++) {
- GB_FREE(blkServers->hosts[i]);
- }
- GB_FREE(blkServers->hosts);
- GB_FREE(blkServers);
-}
-
-
static blockServerDefPtr
blockServerParse(char *blkServers)
{
@@ -955,6 +999,9 @@ glusterBlockDeleteFillArgs(MetaInfo *info, bool deleteall, blockRemoteObj *args,
case GB_AUTH_CLEAR_ENFORCED:
case GB_AUTH_CLEAR_ENFORCEING:
case GB_AUTH_CLEAR_ENFORCE_FAIL:
+ case GB_RP_SUCCESS:
+ case GB_RP_FAIL:
+ case GB_RP_INPROGRESS:
if (!deleteall)
break;
/* case GB_CONFIG_INPROGRESS: untouched may be due to connect failed */
@@ -1246,13 +1293,16 @@ glusterBlockModifyArgsFill(blockModify *mobj, MetaInfo *info,
for (i = 0, count = 0; i < info->nhosts; i++) {
switch (blockMetaStatusEnumParse(info->list[i]->status)) {
case GB_CONFIG_SUCCESS:
- /* case GB_AUTH_ENFORCED: this is not required to be configured */
case GB_AUTH_ENFORCE_FAIL:
case GB_AUTH_CLEAR_ENFORCED:
+ case GB_RP_SUCCESS:
+ case GB_RP_FAIL:
+ case GB_RP_INPROGRESS:
if (mobj->auth_mode) {
fill = TRUE;
}
break;
+ /* case GB_AUTH_ENFORCED: this is not required to be configured */
case GB_AUTH_ENFORCED:
if (!mobj->auth_mode) {
fill = TRUE;
@@ -1345,6 +1395,879 @@ glusterBlockModifyRemoteAsync(MetaInfo *info,
}
+bool *
+glusterBlockBuildMinCaps(void *data, operations opt)
+{
+ blockCreateCli *cblk = NULL;
+ blockDeleteCli *dblk = NULL;
+ blockModifyCli *mblk = NULL;
+ blockReplaceCli *rblk = NULL;
+ bool *minCaps = NULL;
+
+
+ if (GB_ALLOC_N(minCaps, GB_CAP_MAX) < 0) {
+ return NULL;
+ }
+
+ switch (opt) {
+ case CREATE_SRV:
+ cblk = (blockCreateCli *)data;
+
+ minCaps[GB_CREATE_CAP] = true;
+ if (cblk->mpath > 1) {
+ minCaps[GB_CREATE_HA_CAP] = true;
+ }
+ if (cblk->prealloc) {
+ minCaps[GB_CREATE_PREALLOC_CAP] = true;
+ }
+ if (cblk->auth_mode) {
+ minCaps[GB_CREATE_AUTH_CAP] = true;
+ }
+ if (cblk->json_resp) {
+ minCaps[GB_JSON_CAP] = true;
+ }
+ break;
+ case DELETE_SRV:
+ dblk = (blockDeleteCli *)data;
+
+ minCaps[GB_DELETE_CAP] = true;
+ if (dblk->force) {
+ minCaps[GB_DELETE_FORCE_CAP] = true;
+ }
+ if (dblk->json_resp) {
+ minCaps[GB_JSON_CAP] = true;
+ }
+ break;
+ case MODIFY_SRV:
+ mblk = (blockModifyCli *)data;
+
+ minCaps[GB_MODIFY_CAP] = true;
+ if (mblk->auth_mode) {
+ minCaps[GB_MODIFY_AUTH_CAP] = true;
+ }
+ if (mblk->json_resp) {
+ minCaps[GB_JSON_CAP] = true;
+ }
+ break;
+ case REPLACE_SRV:
+ rblk = (blockReplaceCli *)data;
+
+ minCaps[GB_REPLACE_CAP] = true;
+ if (rblk->json_resp) {
+ minCaps[GB_JSON_CAP] = true;
+ }
+ break;
+ }
+
+ return minCaps;
+}
+
+
+static int
+glusterBlockCheckCapabilities(void* blk, operations opt, blockServerDefPtr list,
+ char **errMsg)
+{
+ int errCode = 0;
+ bool *minCaps = NULL;
+ char *localErrMsg = NULL;
+
+
+ /* skip if nhosts = 1 */
+ if (!list || (list->nhosts <= 1)) {
+ return 0;
+ }
+
+ minCaps = glusterBlockBuildMinCaps(blk, opt);
+ if (!minCaps) {
+ errCode = ENOMEM;
+ goto out;
+ }
+
+ errCode = glusterBlockCapabilityRemoteAsync(list, minCaps, &localErrMsg);
+ if (errCode) {
+ LOG("mgmt", GB_LOG_ERROR, "glusterBlockCapabilityRemoteAsync() failed (%s)",
+ localErrMsg);
+ if (errCode == -ENOTCONN) {
+ if (GB_ASPRINTF(errMsg, "Version check failed [%s] (Hint: See if all "
+ "servers are up and running gluster-blockd daemon)",
+ localErrMsg) == -1) {
+ errCode = ENOMEM;
+ }
+ } else {
+ if (GB_ASPRINTF(errMsg, "Version check failed between block servers. (%s)",
+ localErrMsg) == -1) {
+ errCode = ENOMEM;
+ }
+ }
+ goto out;
+ }
+
+ out:
+ GB_FREE(minCaps);
+ GB_FREE(localErrMsg);
+ return errCode;
+}
+
+
+blockServerDefPtr
+glusterBlockGetListFromInfo(MetaInfo *info)
+{
+ size_t i;
+ blockServerDefPtr list = NULL;
+
+
+ if (!info || GB_ALLOC(list) < 0) {
+ return NULL;
+ }
+
+ if (GB_ALLOC_N(list->hosts, info->mpath) < 0) {
+ goto out;
+ }
+
+ for (i = 0; i < info->nhosts; i++) {
+ if (blockhostIsValid (info->list[i]->status)) {
+ if (GB_STRDUP(list->hosts[list->nhosts++], info->list[i]->addr) < 0) {
+ goto out;
+ }
+ }
+ }
+
+ return list;
+
+ out:
+ blockServerDefFree(list);
+ return NULL;
+}
+
+
+void *
+glusterBlockReplacePortalRemote(void *data)
+{
+ int ret;
+ int saveret;
+ blockRemoteObj *args = (blockRemoteObj *)data;
+ blockReplace robj = *(blockReplace *)args->obj;
+ char *errMsg = NULL;
+ bool rpc_sent = FALSE;
+
+
+ GB_METAUPDATE_OR_GOTO(lock, args->glfs, robj.block_name, robj.volume,
+ ret, errMsg, out, "%s: RPINPROGRESS\n", args->addr);
+
+ ret = glusterBlockCallRPC_1(args->addr, &robj, REPLACE_SRV, &rpc_sent,
+ &args->reply);
+ if (ret && ret != GB_OP_SKIPPED) {
+ saveret = ret;
+ if (!rpc_sent) {
+ GB_ASPRINTF(&errMsg, ": %s", strerror(errno));
+ LOG("mgmt", GB_LOG_ERROR, "%s hence %s for block %s on "
+ "host %s volume %s", strerror(errno), FAILED_REMOTE_REPLACE,
+ robj.block_name, args->addr, args->volume);
+ goto out;
+ } else if (args->reply) {
+ errMsg = args->reply;
+ args->reply = NULL;
+ }
+
+ GB_METAUPDATE_OR_GOTO(lock, args->glfs, robj.block_name, robj.volume,
+ ret, errMsg, out, "%s: RPFAIL\n", args->addr);
+ LOG("mgmt", GB_LOG_ERROR, "%s for block %s on host %s volume %s",
+ FAILED_REMOTE_CREATE, robj.block_name, args->addr, args->volume);
+
+ ret = saveret;
+ goto out;
+ }
+
+ GB_METAUPDATE_OR_GOTO(lock, args->glfs, robj.block_name, robj.volume,
+ ret, errMsg, out, "%s: RPSUCCESS\n", args->addr);
+
+out:
+ if (!args->reply) {
+ if (GB_ASPRINTF(&args->reply, "failed to replace remote portal on %s %s\n", args->addr,
+ errMsg?errMsg:"") == -1) {
+ ret = ret?ret:-1;
+ }
+ }
+ args->exit = ret;
+
+ GB_FREE (errMsg);
+ return NULL;
+}
+
+
+int
+blockGetHostStatus(MetaInfo *info, char *host)
+{
+ size_t i;
+
+
+ if (!info || !host)
+ return GB_METASTATUS_MAX;
+
+ for (i = 0; i < info->nhosts; i++) {
+ if (!strcmp(info->list[i]->addr, host)) {
+ return blockMetaStatusEnumParse(info->list[i]->status);
+ }
+ }
+
+ return GB_METASTATUS_MAX;
+}
+
+
+void
+blockRemoteRespFree(blockRemoteResp *resp)
+{
+
+ if (!resp)
+ return;
+
+ GB_FREE(resp->attempt);
+ GB_FREE(resp->success);
+ GB_FREE(resp->skipped);
+ GB_FREE(resp);
+}
+
+
+void
+blockRemoteReplaceRespFree(blockRemoteReplaceResp *resp)
+{
+
+ if (!resp)
+ return;
+
+ blockRemoteRespFree(resp->cop);
+ blockRemoteRespFree(resp->dop);
+ blockRemoteRespFree(resp->rop);
+ GB_FREE(resp);
+}
+
+
+int
+glusterBlockReplaceNodeRemoteAsync(struct glfs *glfs, blockReplaceCli *blk,
+ char *block, blockRemoteReplaceResp **savereply)
+{
+ blockRemoteReplaceResp *reply = NULL;
+ pthread_t *tid = NULL;
+ blockRemoteObj *args = NULL;
+ MetaInfo *info = NULL;
+ blockCreate *cobj = NULL;
+ blockDelete *dobj = NULL;
+ blockReplace *robj = NULL;
+ bool Flag = false;
+ bool cCheck = false;
+ bool dCheck = false;
+ bool rCheck = false;
+ bool newNodeInUse = false;
+ char *tmp = NULL;
+ size_t i = 0, j = 1;
+ int ret = -1;
+ int status = 0;
+
+
+ if ((GB_ALLOC(reply) < 0) || (GB_ALLOC(reply->cop) < 0) ||
+ (GB_ALLOC(reply->dop) < 0) || (GB_ALLOC(reply->rop) < 0)) {
+ goto out;
+ }
+ reply->cop->status = -1;
+ reply->dop->status = -1;
+ reply->rop->status = -1;
+ reply->force = blk->force;
+
+ if (GB_ALLOC(info) < 0) {
+ goto out;
+ }
+ if (blockGetMetaInfo(glfs, block, info, NULL)) {
+ goto out;
+ }
+
+ if ((GB_ALLOC(cobj) < 0) || (GB_ALLOC(robj) < 0) || (GB_ALLOC(dobj) < 0)){
+ goto out;
+ }
+
+ strcpy(cobj->ipaddr, blk->new_node);
+ strcpy(cobj->volume, info->volume);
+ strcpy(cobj->gbid, info->gbid);
+ cobj->size = info->size;
+ strcpy(cobj->passwd, info->passwd);
+ strcpy(cobj->block_name, block);
+
+ strcpy(robj->volume, info->volume);
+ strcpy(robj->gbid, info->gbid);
+ strcpy(robj->block_name, block);
+ strcpy(robj->ipaddr, blk->new_node);
+ strcpy(robj->ripaddr, blk->old_node);
+
+ strcpy(dobj->block_name, block);
+ strcpy(dobj->gbid, info->gbid);
+
+ /* Fill args[] */
+ if (GB_ALLOC_N(args, info->mpath + 1) < 0) {
+ goto out;
+ }
+ args[0].glfs = glfs;
+ args[0].obj = (void *)cobj;
+ args[0].addr = blk->new_node;
+ args[0].volume = blk->volume;
+ if (GB_STRDUP(cobj->block_hosts, blk->new_node) < 0) {
+ goto out;
+ }
+ for (i = 0; i < info->nhosts; i++) {
+ if (strcmp(info->list[i]->addr, blk->old_node)) {
+ if (blockhostIsValid(info->list[i]->status)) {
+ tmp = cobj->block_hosts;
+ if (GB_ASPRINTF(&cobj->block_hosts, "%s,%s", tmp, info->list[i]->addr) == -1) {
+ GB_FREE (tmp);
+ goto out;
+ }
+ GB_FREE(tmp);
+ args[j].glfs = glfs;
+ args[j].obj = (void *)robj;
+ args[j].addr = info->list[i]->addr;
+ args[j].volume = blk->volume;
+ j++;
+ }
+ }
+ }
+ args[info->mpath].glfs = glfs;
+ args[info->mpath].obj = (void *)dobj;
+ args[info->mpath].addr = blk->old_node;
+ args[info->mpath].volume = blk->volume;
+
+ /* -> Make Sure Old Node is currenly in use */
+ if (blockGetHostStatus(info, blk->old_node) == GB_METASTATUS_MAX) {
+ ret = GB_NODE_NOT_EXIST;
+ LOG("mgmt", GB_LOG_WARNING, "block %s is not configured on node %s for volume %s",
+ blk->block_name, blk->old_node, blk->volume);
+ goto out;
+ } else if (blockGetHostStatus(info, blk->old_node) == GB_CLEANUP_SUCCESS) {
+ dCheck = true; /* Old node deleted, but we are not sure when though */
+ }
+
+ /* -> Make Sure New Node is not already consumed by this block */
+ for (i = 0; i < info->nhosts; i++) {
+ if (!strcmp(info->list[i]->addr, blk->new_node) && blockhostIsValid(info->list[i]->status)) {
+ newNodeInUse = true; /* New node in use */
+ status = blockMetaStatusEnumParse(info->list[i]->status);
+ if (status == GB_AUTH_ENFORCED || status == GB_CONFIG_SUCCESS) {
+ cCheck = true; /* New node is freshly configured */
+ }
+ break;
+ }
+ }
+
+ /* -> New node used && not triggered by previouly issued replace node */
+ if (newNodeInUse && !cCheck) {
+ ret = GB_NODE_IN_USE;
+ LOG("mgmt", GB_LOG_ERROR, "block %s was already configured on node %s for volume %s",
+ blk->block_name, blk->old_node, blk->volume);
+ goto out;
+ }
+
+ /* -> Was Replace Node already run on this block ? (might not be for same portals) */
+ for (i = 1; i < info->mpath; i++) {
+ switch(blockGetHostStatus(info, args[i].addr)) {
+ case GB_RP_SUCCESS:
+ case GB_RP_INPROGRESS:
+ case GB_RP_FAIL:
+ break;
+ default:
+ Flag = true; /* doesn't look like RP run on same portals as now */
+ break;
+ }
+ if (Flag)
+ break;
+ }
+
+ /* -> If new node got already configured but not as part of previous RP req */
+ if (cCheck && Flag) {
+ ret = GB_NODE_IN_USE;
+ LOG("mgmt", GB_LOG_ERROR, "block %s was already configured on node %s for volume %s",
+ blk->block_name, blk->old_node, blk->volume);
+ goto out;
+ }
+
+ for (i = 1; i < info->mpath; i++) {
+ if (blockGetHostStatus(info, args[i].addr) != GB_RP_SUCCESS) {
+ rCheck = true; /* not all RP req are success */
+ break;
+ }
+ }
+
+ /* All nodes are already replaced ? */
+ if (!rCheck) {
+ /* Then check for delete of old node and create on new node, to confirm last op was same as this */
+ if (dCheck && cCheck) {
+ reply->status = GB_OP_SKIPPED; /* replace was already successful in previous RP req */
+ ret = 0;
+ goto out; /* We can skip this op */
+ }
+ }
+
+ if (GB_ALLOC_N(tid, info->mpath + 1) < 0) {
+ goto out;
+ }
+
+ /* Create */
+ if (!cCheck) {
+ pthread_create(&tid[0], NULL, glusterBlockCreateRemote, &args[0]);
+ } else {
+ reply->cop->status = GB_OP_SKIPPED; /* skip */
+ if (GB_STRDUP(reply->cop->skipped, args[0].addr) < 0) {
+ goto out;
+ }
+ }
+
+ /* Replace Portal */
+ if (rCheck) {
+ for (i = 1; i < info->mpath; i++) {
+ pthread_create(&tid[i], NULL, glusterBlockReplacePortalRemote, &args[i]);
+ }
+ } else {
+ reply->rop->status = GB_OP_SKIPPED; /* skip */
+ for (i = 1; i < info->mpath; i++) {
+ tmp = reply->rop->skipped;
+ if (GB_ASPRINTF(&reply->rop->skipped, "%s %s",
+ (tmp==NULL?"":tmp), args[i].addr) == -1) {
+ GB_FREE (tmp);
+ goto out;
+ }
+ GB_FREE (tmp);
+ }
+ }
+
+ /* Delete */
+ if (!dCheck) {
+ pthread_create(&tid[info->mpath], NULL, glusterBlockDeleteRemote, &args[info->mpath]);
+ } else {
+ reply->dop->status = GB_OP_SKIPPED; /* skip */
+ if (GB_STRDUP(reply->dop->skipped, args[info->mpath].addr) < 0) {
+ goto out;
+ }
+ }
+
+ if (!cCheck) {
+ pthread_join(tid[0], NULL);
+ }
+ if (rCheck) {
+ for (i = 1; i < info->mpath; i++) {
+ pthread_join(tid[i], NULL);
+ }
+ }
+ if (!dCheck) {
+ pthread_join(tid[info->mpath], NULL);
+ }
+
+ /* Collect results */
+ if (!cCheck) {
+ reply->cop->status = args[0].exit;
+ if (args[0].exit) {
+ if (GB_STRDUP(reply->cop->attempt, args[0].addr) < 0) {
+ goto out;
+ }
+ } else {
+ if (GB_STRDUP(reply->cop->success, args[0].addr) < 0) {
+ goto out;
+ }
+ }
+ }
+
+ if (!dCheck) {
+ reply->dop->status = args[info->mpath].exit;
+ if (args[info->mpath].exit) {
+ if (GB_STRDUP(reply->dop->attempt, args[info->mpath].addr) < 0) {
+ goto out;
+ }
+ } else {
+ if (GB_STRDUP(reply->dop->success, args[info->mpath].addr) < 0) {
+ goto out;
+ }
+ }
+ }
+
+ if (rCheck) {
+ for (i = 1; i < info->mpath; i++) {
+ if (args[i].exit) {
+ tmp = reply->rop->attempt;
+ if (GB_ASPRINTF(&reply->rop->attempt, "%s %s", tmp?tmp:"", args[i].addr) == -1) {
+ goto out;
+ }
+ GB_FREE(tmp);
+ } else {
+ tmp = reply->rop->success;
+ if (GB_ASPRINTF(&reply->rop->success, "%s %s", tmp?tmp:"", args[i].addr) == -1) {
+ goto out;
+ }
+ GB_FREE(tmp);
+ }
+ reply->rop->status = args[i].exit;
+ }
+ } else {
+ if (info->mpath == 1) {
+ if (GB_ASPRINTF(&reply->rop->success, "N/A") == -1) {
+ goto out;
+ }
+ reply->rop->status = 0; /* mimic success */
+ }
+ }
+
+ ret = 0;
+
+ out:
+ if (!ret) {
+ *savereply = reply;
+ reply = NULL;
+ }
+ GB_FREE(tid);
+ GB_FREE(cobj);
+ GB_FREE(dobj);
+ GB_FREE(robj);
+ GB_FREE(args);
+ blockFreeMetaInfo(info);
+ blockRemoteReplaceRespFree(reply);
+
+ return ret;
+}
+
+
+void
+blockReplaceNodeCliFormatResponse(blockReplaceCli *blk, int errCode, char *errMsg,
+ blockRemoteReplaceResp *savereply,
+ struct blockResponse *reply)
+{
+ json_object *json_obj = NULL;
+ json_object *json_array[2] = {NULL, };
+ char *tmp = NULL;
+ char *entry = NULL;
+ int i;
+
+ if (!reply) {
+ return;
+ }
+
+ if (errCode < 0) {
+ errCode = GB_DEFAULT_ERRCODE;
+ }
+
+ reply->exit = errCode;
+
+ if (errMsg) {
+ blockFormatErrorResponse(REPLACE_SRV, blk->json_resp, errCode,
+ errMsg, reply);
+ return;
+ }
+
+ if (!savereply || !savereply->cop || !savereply->dop || !savereply->rop) {
+ goto out;
+ }
+
+ if (blk->json_resp) {
+ json_obj = json_object_new_object();
+ json_object_object_add(json_obj, "NAME", GB_JSON_OBJ_TO_STR(blk->block_name));
+
+ if (savereply->status == GB_OP_SKIPPED || savereply->status == -1) {
+ if (savereply->status == GB_OP_SKIPPED) {
+ json_object_object_add(json_obj, "RESULT", GB_JSON_OBJ_TO_STR("SKIPPED"));
+ } else {
+ /* see if node in use by this block */
+ json_object_object_add(json_obj, "RESULT", GB_JSON_OBJ_TO_STR("FAIL"));
+ json_object_object_add(json_obj, "errCode", json_object_new_int(-1));
+ json_object_object_add(json_obj, "errMsg",
+ GB_JSON_OBJ_TO_STR("Given new-node is already in-use with this block, use other node"));
+ }
+ } else {
+ if (savereply->cop->status == GB_OP_SKIPPED) {
+ json_object_object_add(json_obj, "CREATE SKIPPED",
+ GB_JSON_OBJ_TO_STR(savereply->cop->skipped));
+ } else if (savereply->cop->status) {
+ json_object_object_add(json_obj, "CREATE FAILED",
+ GB_JSON_OBJ_TO_STR(savereply->cop->attempt));
+ } else {
+ json_object_object_add(json_obj, "CREATE SUCCESS",
+ GB_JSON_OBJ_TO_STR(savereply->cop->success));
+ }
+
+ if (savereply->dop->status == GB_OP_SKIPPED) {
+ json_object_object_add(json_obj, "DELETE SKIPPED",
+ GB_JSON_OBJ_TO_STR(savereply->dop->skipped));
+ } else if (savereply->dop->status) {
+ if (savereply->force) {
+ json_object_object_add(json_obj, "DELETE FAILED (ignored)",
+ GB_JSON_OBJ_TO_STR(savereply->dop->attempt));
+ } else {
+ json_object_object_add(json_obj, "DELETE FAILED",
+ GB_JSON_OBJ_TO_STR(savereply->dop->attempt));
+ }
+ /* mimic success */
+ savereply->dop->status = 0;
+ } else {
+ json_object_object_add(json_obj, "DELETE SUCCESS",
+ GB_JSON_OBJ_TO_STR(savereply->dop->success));
+ }
+
+ if (savereply->rop->status == GB_OP_SKIPPED) {
+ blockStr2arrayAddToJsonObj(json_obj, savereply->rop->skipped,
+ "REPLACE PORTAL SKIPPED ON", &json_array[0]);
+ } else {
+ if (savereply->rop->attempt) {
+ blockStr2arrayAddToJsonObj(json_obj, savereply->rop->attempt,
+ "REPLACE PORTAL FAILED ON", &json_array[0]);
+ }
+ if (savereply->rop->success) {
+ blockStr2arrayAddToJsonObj(json_obj,
+ savereply->rop->success?savereply->rop->success:"N/A",
+ "REPLACE PORTAL SUCCESS ON", &json_array[1]);
+ }
+ }
+
+ if ((savereply->cop->status == GB_OP_SKIPPED || !savereply->cop->status) &&
+ (savereply->dop->status == GB_OP_SKIPPED || !savereply->dop->status) &&
+ (savereply->rop->status == GB_OP_SKIPPED || !savereply->rop->status)) {
+ json_object_object_add(json_obj, "RESULT", GB_JSON_OBJ_TO_STR("SUCCESS"));
+ } else {
+ json_object_object_add(json_obj, "RESULT", GB_JSON_OBJ_TO_STR("FAIL"));
+ }
+ }
+ GB_ASPRINTF(&reply->out, "%s\n", json_object_to_json_string_ext(json_obj,
+ mapJsonFlagToJsonCstring(blk->json_resp)));
+ for (i = 0; i < 2; i++) {
+ if (json_array[i]) {
+ json_object_put(json_array[i]);
+ }
+ }
+ json_object_put(json_obj);
+ } else {
+ if (GB_ASPRINTF(&entry, "NAME: %s\n", blk->block_name) == -1) {
+ goto out;
+ }
+
+ if (savereply->status == GB_OP_SKIPPED || savereply->status == -1) {
+ tmp = entry;
+ if (savereply->status == GB_OP_SKIPPED) {
+ if (GB_ASPRINTF(&entry, "%sRESULT: SKIPPED\n", tmp?tmp:"") == -1) {
+ goto out;
+ }
+ } else {
+ /* see if node in use by this block */
+ if (GB_ASPRINTF(&entry, "%serrMsg:%s\nRESULT: FAIL\n", tmp?tmp:"",
+ "Given new-node is already in-use with this block, use other node") == -1) {
+ goto out;
+ }
+ }
+ GB_FREE(tmp);
+ } else {
+ tmp = entry;
+ if (savereply->cop->status == GB_OP_SKIPPED) {
+ if (GB_ASPRINTF(&entry, "%sCREATE SKIPPED: %s\n", tmp?tmp:"",
+ savereply->cop->skipped) == -1) {
+ goto out;
+ }
+ } else if (savereply->cop->status) {
+ if (GB_ASPRINTF(&entry, "%sCREATE FAILED: %s\n", tmp?tmp:"",
+ savereply->cop->attempt) == -1) {
+ goto out;
+ }
+ } else {
+ if (GB_ASPRINTF(&entry, "%sCREATE SUCCESS: %s\n", tmp?tmp:"",
+ savereply->cop->success) == -1) {
+ goto out;
+ }
+ }
+ GB_FREE(tmp);
+
+ tmp = entry;
+ if (savereply->dop->status == GB_OP_SKIPPED) {
+ if (GB_ASPRINTF(&entry, "%sDELETE SKIPPED: %s\n", tmp?tmp:"",
+ savereply->dop->skipped) == -1) {
+ goto out;
+ }
+ } else if (savereply->dop->status) {
+ if (savereply->force) {
+ if (GB_ASPRINTF(&entry, "%sDELETE FAILED (ignored): %s\n", tmp?tmp:"",
+ savereply->dop->attempt) == -1) {
+ goto out;
+ }
+ /* mimic success */
+ savereply->dop->status = 0;
+ } else {
+ if (GB_ASPRINTF(&entry, "%sDELETE FAILED: %s\n", tmp?tmp:"",
+ savereply->dop->attempt) == -1) {
+ goto out;
+ }
+ }
+ } else {
+ if (GB_ASPRINTF(&entry, "%sDELETE SUCCESS: %s\n", tmp?tmp:"",
+ savereply->dop->success) == -1) {
+ goto out;
+ }
+ }
+ GB_FREE(tmp);
+
+ if (savereply->rop->status == GB_OP_SKIPPED) {
+ tmp = entry;
+ if (GB_ASPRINTF(&entry, "%sREPLACE PORTAL SKIPPED ON: %s\n", tmp?tmp:"",
+ savereply->rop->skipped) == -1) {
+ goto out;
+ }
+ GB_FREE(tmp);
+ } else {
+ if (savereply->rop->attempt) {
+ tmp = entry;
+ if (GB_ASPRINTF(&entry, "%sREPLACE PORTAL FAILED ON: %s\n", tmp?tmp:"",
+ savereply->rop->attempt) == -1) {
+ goto out;
+ }
+ GB_FREE(tmp);
+ }
+ if (savereply->rop->success) {
+ tmp = entry;
+ if (GB_ASPRINTF(&entry, "%sREPLACE PORTAL SUCCESS ON: %s\n", tmp?tmp:"",
+ savereply->rop->success?savereply->rop->success:"N/A") == -1) {
+ goto out;
+ }
+ GB_FREE(tmp);
+ }
+ }
+
+ tmp = entry;
+ if ((savereply->cop->status == GB_OP_SKIPPED || !savereply->cop->status) &&
+ (savereply->dop->status == GB_OP_SKIPPED || !savereply->dop->status) &&
+ (savereply->rop->status == GB_OP_SKIPPED || !savereply->rop->status)) {
+ if (GB_ASPRINTF(&entry, "%sRESULT: SUCCESS\n", tmp?tmp:"") == -1) {
+ goto out;
+ }
+ } else {
+ if (GB_ASPRINTF(&entry, "%sRESULT: FAIL\n", tmp?tmp:"") == -1) {
+ goto out;
+ }
+ }
+ GB_FREE(tmp);
+ }
+
+ if (GB_ASPRINTF(&reply->out, "%s\n", entry) == -1) {
+ goto out;
+ }
+ GB_FREE(entry);
+ }
+
+out:
+ /*catch all*/
+ if (!reply->out) {
+ blockFormatErrorResponse(REPLACE_SRV, blk->json_resp, errCode,
+ GB_DEFAULT_ERRMSG, reply);
+ }
+
+ GB_FREE (tmp);
+ return;
+}
+
+
+blockResponse *
+block_replace_cli_1_svc_st(blockReplaceCli *blk, struct svc_req *rqstp)
+{
+ blockRemoteReplaceResp *savereply = NULL;
+ blockResponse *reply = NULL;
+ struct glfs *glfs;
+ struct glfs_fd *lkfd = NULL;
+ int errCode = 0;
+ char *errMsg = NULL;
+ int ret;
+ blockServerDefPtr list = NULL;
+
+
+ LOG("mgmt", GB_LOG_DEBUG,
+ "replace request, volume=%s, blockname=%s oldnode=%s newnode=%s force=%d",
+ blk->volume, blk->block_name, blk->old_node, blk->new_node, blk->force);
+
+ if (GB_ALLOC(reply) < 0) {
+ return NULL;
+ }
+ reply->exit = -1;
+
+ glfs = glusterBlockVolumeInit(blk->volume, &errCode, &errMsg);
+ if (!glfs) {
+ LOG("mgmt", GB_LOG_ERROR,
+ "glusterBlockVolumeInit(%s) failed", blk->volume);
+ goto optfail;
+ }
+
+ lkfd = glusterBlockCreateMetaLockFile(glfs, blk->volume, &errCode, &errMsg);
+ if (!lkfd) {
+ LOG("mgmt", GB_LOG_ERROR, "%s %s", FAILED_CREATING_META, blk->volume);
+ goto optfail;
+ }
+
+ GB_METALOCK_OR_GOTO(lkfd, blk->volume, errCode, errMsg, optfail);
+
+ if (glfs_access(glfs, blk->block_name, F_OK)) {
+ errCode = errno;
+ if (errCode == ENOENT) {
+ GB_ASPRINTF(&errMsg, "block %s/%s doesn't exist",
+ blk->volume, blk->block_name);
+ LOG("mgmt", GB_LOG_ERROR,
+ "block with name %s doesn't exist in the volume %s",
+ blk->block_name, blk->volume);
+ } else {
+ GB_ASPRINTF(&errMsg, "block %s/%s is not accessible (%s)",
+ blk->volume, blk->block_name, strerror(errCode));
+ LOG("mgmt", GB_LOG_ERROR, "block %s/%s is not accessible (%s)",
+ blk->volume, blk->block_name, strerror(errCode));
+ }
+ goto out;
+ }
+
+ ret = blockParseValidServers(glfs, blk->block_name, &errCode, &list,
+ blk->force?blk->old_node:NULL);
+ if (ret) {
+ LOG("mgmt", GB_LOG_ERROR, "blockParseValidServers(%s): on volume %s failed[%s]",
+ blk->block_name, blk->volume, strerror(errno));
+ goto out;
+ }
+
+ errCode = glusterBlockCheckCapabilities((void *)blk, REPLACE_SRV, list, &errMsg);
+ if (errCode) {
+ LOG("mgmt", GB_LOG_ERROR,
+ "glusterBlockCheckCapabilities() for block %s on volume %s failed",
+ blk->block_name, blk->volume);
+ goto out;
+ }
+
+ ret = glusterBlockReplaceNodeRemoteAsync(glfs, blk, blk->block_name, &savereply);
+ if (ret) {
+ LOG("mgmt", GB_LOG_WARNING, "glusterBlockReplaceNodeRemoteAsync: return"
+ " %d %s for single block %s on volume %s", ret, FAILED_REMOTE_REPLACE,
+ blk->block_name, blk->volume);
+ if (ret == GB_NODE_NOT_EXIST) {
+ GB_ASPRINTF(&errMsg, "block '%s' is not configured on node '%s' for volume '%s'",
+ blk->block_name, blk->old_node, blk->volume);
+ errCode = ret;
+ goto out;
+ } else if (ret == GB_NODE_IN_USE) {
+ GB_ASPRINTF(&errMsg, "block '%s' was already configured on node '%s' for volume '%s'",
+ blk->block_name, blk->new_node, blk->volume);
+ errCode = ret;
+ goto out;
+ }
+ }
+ if (savereply && savereply->force && savereply->dop->status) {
+ GB_METAUPDATE_OR_GOTO(lock, glfs, blk->block_name, blk->volume,
+ errCode, errMsg, out, "%s: CLEANUPSUCCESS\n", blk->old_node);
+ }
+
+ errCode = 0;
+
+ LOG("mgmt", GB_LOG_DEBUG, "replace cli success, volume=%s", blk->volume);
+
+ out:
+ GB_METAUNLOCK(lkfd, blk->volume, errCode, errMsg);
+ blockReplaceNodeCliFormatResponse(blk, errCode, errMsg, savereply, reply);
+ blockServerDefFree(list);
+ blockRemoteReplaceRespFree(savereply);
+
+optfail:
+ return reply;
+}
+
+
static int
glusterBlockCleanUp(struct glfs *glfs, char *blockname,
bool deleteall, bool forcedel, blockRemoteDeleteResp *drobj)
@@ -1539,116 +2462,6 @@ glusterBlockAuditRequest(struct glfs *glfs,
return ret;
}
-void
-blockFormatErrorResponse (operations op, int json_resp, int errCode,
- char *errMsg, struct blockResponse *reply)
-{
- json_object *json_obj = NULL;
-
-
- if (!reply) {
- return;
- }
-
- reply->exit = errCode;
- if (json_resp) {
- json_obj = json_object_new_object();
- json_object_object_add(json_obj, "RESULT", GB_JSON_OBJ_TO_STR("FAIL"));
- json_object_object_add(json_obj, "errCode", json_object_new_int(errCode));
- json_object_object_add(json_obj, "errMsg", GB_JSON_OBJ_TO_STR(errMsg));
- GB_ASPRINTF(&reply->out, "%s\n",
- json_object_to_json_string_ext(json_obj,
- mapJsonFlagToJsonCstring(json_resp)));
- json_object_put(json_obj);
- } else {
- if (op != INFO_SRV) {
- GB_ASPRINTF (&reply->out, "%s\nRESULT:FAIL\n", errMsg);
- } else {
- GB_ASPRINTF (&reply->out, "%s\n", errMsg);
- }
- }
-}
-
-static void
-blockStr2arrayAddToJsonObj (json_object *json_obj, char *string, char *label,
- json_object **json_array)
-{
- char *tmp = NULL;
- json_object *json_array1 = NULL;
-
- if (!string)
- return;
-
- json_array1 = json_object_new_array();
- tmp = strtok (string, " ");
- while (tmp != NULL)
- {
- json_object_array_add(json_array1, GB_JSON_OBJ_TO_STR(tmp));
- tmp = strtok (NULL, " ");
- }
- json_object_object_add(json_obj, label, json_array1);
- *json_array = json_array1;
-}
-
-
-bool *
-glusterBlockBuildMinCaps(void *data, operations opt)
-{
- blockCreateCli *cblk = NULL;
- blockDeleteCli *dblk = NULL;
- blockModifyCli *mblk = NULL;
- bool *minCaps = NULL;
-
-
- if (GB_ALLOC_N(minCaps, GB_CAP_MAX) < 0) {
- return NULL;
- }
-
- switch (opt) {
- case CREATE_SRV:
- cblk = (blockCreateCli *)data;
-
- minCaps[GB_CREATE_CAP] = true;
- if (cblk->mpath > 1) {
- minCaps[GB_CREATE_HA_CAP] = true;
- }
- if (cblk->prealloc) {
- minCaps[GB_CREATE_PREALLOC_CAP] = true;
- }
- if (cblk->auth_mode) {
- minCaps[GB_CREATE_AUTH_CAP] = true;
- }
- if (cblk->json_resp) {
- minCaps[GB_JSON_CAP] = true;
- }
- break;
- case DELETE_SRV:
- dblk = (blockDeleteCli *)data;
-
- minCaps[GB_DELETE_CAP] = true;
- if (dblk->force) {
- minCaps[GB_DELETE_FORCE_CAP] = true;
- }
- if (dblk->json_resp) {
- minCaps[GB_JSON_CAP] = true;
- }
- break;
- case MODIFY_SRV:
- mblk = (blockModifyCli *)data;
-
- minCaps[GB_MODIFY_CAP] = true;
- if (mblk->auth_mode) {
- minCaps[GB_MODIFY_AUTH_CAP] = true;
- }
- if (mblk->json_resp) {
- minCaps[GB_JSON_CAP] = true;
- }
- break;
- }
-
- return minCaps;
-}
-
static void
blockModifyCliFormatResponse (blockModifyCli *blk, struct blockModify *mobj,
@@ -1773,84 +2586,6 @@ blockModifyCliFormatResponse (blockModifyCli *blk, struct blockModify *mobj,
}
-static int
-glusterBlockCheckCapabilities(void* blk, operations opt, blockServerDefPtr list,
- char **errMsg)
-{
- int errCode = 0;
- bool *minCaps = NULL;
- char *localErrMsg = NULL;
-
-
- /* skip if nhosts = 1 */
- if (!list || (list->nhosts <= 1)) {
- return 0;
- }
-
- minCaps = glusterBlockBuildMinCaps(blk, opt);
- if (!minCaps) {
- errCode = ENOMEM;
- goto out;
- }
-
- errCode = glusterBlockCapabilityRemoteAsync(list, minCaps, &localErrMsg);
- if (errCode) {
- LOG("mgmt", GB_LOG_ERROR, "glusterBlockCapabilityRemoteAsync() failed (%s)",
- localErrMsg);
- if (errCode == -ENOTCONN) {
- if (GB_ASPRINTF(errMsg, "Version check failed [%s] (Hint: See if all "
- "servers are up and running gluster-blockd daemon)",
- localErrMsg) == -1) {
- errCode = ENOMEM;
- }
- } else {
- if (GB_ASPRINTF(errMsg, "Version check failed between block servers. (%s)",
- localErrMsg) == -1) {
- errCode = ENOMEM;
- }
- }
- goto out;
- }
-
- out:
- GB_FREE(minCaps);
- GB_FREE(localErrMsg);
- return errCode;
-}
-
-
-blockServerDefPtr
-glusterBlockGetListFromInfo(MetaInfo *info)
-{
- size_t i;
- blockServerDefPtr list = NULL;
-
-
- if (!info || GB_ALLOC(list) < 0) {
- return NULL;
- }
-
- if (GB_ALLOC_N(list->hosts, info->mpath) < 0) {
- goto out;
- }
-
- for (i = 0; i < info->nhosts; i++) {
- if (blockhostIsValid (info->list[i]->status)) {
- if (GB_STRDUP(list->hosts[i], info->list[i]->addr) < 0) {
- goto out;
- }
- list->nhosts++;
- }
- }
-
- return list;
-
- out:
- blockServerDefFree(list);
- return NULL;
-}
-
-
blockResponse *
block_modify_cli_1_svc_st(blockModifyCli *blk, struct svc_req *rqstp)
{
@@ -1901,12 +2636,19 @@ block_modify_cli_1_svc_st(blockModifyCli *blk, struct svc_req *rqstp)
GB_METALOCK_OR_GOTO(lkfd, blk->volume, ret, errMsg, nolock);
if (glfs_access(glfs, blk->block_name, F_OK)) {
- LOG("mgmt", GB_LOG_ERROR,
- "block with name %s doesn't exist in the volume %s",
- blk->block_name, blk->volume);
- GB_ASPRINTF(&errMsg, "block %s/%s doesn't exist", blk->volume,
- blk->block_name);
- errCode = ENOENT;
+ errCode = errno;
+ if (errCode == ENOENT) {
+ GB_ASPRINTF(&errMsg, "block %s/%s doesn't exist",
+ blk->volume, blk->block_name);
+ LOG("mgmt", GB_LOG_ERROR,
+ "block with name %s doesn't exist in the volume %s",
+ blk->block_name, blk->volume);
+ } else {
+ GB_ASPRINTF(&errMsg, "block %s/%s is not accessible (%s)",
+ blk->volume, blk->block_name, strerror(errCode));
+ LOG("mgmt", GB_LOG_ERROR, "block %s/%s is not accessible (%s)",
+ blk->volume, blk->block_name, strerror(errCode));
+ }
goto out;
}
@@ -2346,6 +3088,7 @@ blockValidateCommandOutput(const char *out, int opt, void *data)
blockCreate *cblk = data;
blockDelete *dblk = data;
blockModify *mblk = data;
+ blockReplace *rblk = data;
int ret = -1;
@@ -2451,6 +3194,26 @@ blockValidateCommandOutput(const char *out, int opt, void *data)
mblk->gbid);
ret = 0;
break;
+
+ case REPLACE_SRV:
+ /* old portal deletion validation */
+ GB_OUT_VALIDATE_OR_GOTO(out, out, "portal delete failed: %s:3260",
+ rblk, rblk->ripaddr, "Deleted network portal %s:3260",
+ rblk->ripaddr);
+
+ /* re-create portal validation */
+ GB_OUT_VALIDATE_OR_GOTO(out, out, "portal (re)create failed: %s:3260",
+ rblk, rblk->ipaddr, "Created network portal %s:3260.",
+ rblk->ipaddr);
+ ret = 0;
+ break;
+
+ case REPLACE_GET_PORTAL_TPG_SRV:
+ /* get tpg of the portal */
+ GB_OUT_VALIDATE_OR_GOTO(out, out, "failed to get tpg number for portal : %s",
+ rblk, rblk->ripaddr, "tpg");
+ ret = 0;
+ break;
}
out:
@@ -2459,6 +3222,80 @@ out:
blockResponse *
+block_replace_1_svc_st(blockReplace *blk, struct svc_req *rqstp)
+{
+ blockResponse *reply = NULL;
+ char *path = NULL;
+ char *exec = NULL;
+ char *tpg;
+
+
+ LOG("mgmt", GB_LOG_INFO,
+ "replace portal request, volume=%s blockname=%s iqn=%s old_portal=%s "
+ "new_portal=%s", blk->volume, blk->block_name, blk->gbid, blk->ripaddr, blk->ipaddr);
+
+ if (GB_ALLOC(reply) < 0) {
+ goto out;
+ }
+ reply->exit = -1;
+
+ if (GB_ALLOC_N(reply->out, 8192) < 0) {
+ GB_FREE(reply);
+ goto out;
+ }
+
+ if (GB_ASPRINTF(&exec, GB_CHECK_PORTAL, blk->gbid, blk->ipaddr) == -1) {
+ goto out;
+ }
+
+ if (!gbRunner(exec)) {
+ reply->exit = GB_OP_SKIPPED;
+ snprintf(reply->out, 8192, "remote portal %s already exist", blk->ipaddr);
+ goto out;
+ }
+ GB_FREE(exec);
+
+ if (GB_ASPRINTF(&exec, GB_GET_PORTAL_TPG, blk->gbid,
+ blk->ripaddr, blk->ripaddr) == -1) {
+ goto out;
+ }
+
+ /* get number of tpg's for this target */
+ GB_CMD_EXEC_AND_VALIDATE(exec, reply, blk, blk->volume, REPLACE_GET_PORTAL_TPG_SRV);
+ if (reply->exit) {
+ snprintf(reply->out, 8192, "failed to get portal tpg");
+ goto out;
+ }
+ GB_FREE(exec);
+ tpg = strtok(reply->out, "\n");
+
+ if (GB_ASPRINTF(&path, "%s/%s%s/%s/portals", GB_TGCLI_ISCSI_PATH,
+ GB_TGCLI_IQN_PREFIX, blk->gbid, tpg) == -1) {
+ goto out;
+ }
+
+ if (GB_ASPRINTF(&exec,
+ "targetcli <<EOF\n%s delete %s ip_port=3260\n%s create %s\n%s\nEOF",
+ path, blk->ripaddr, path, blk->ipaddr, GB_TGCLI_SAVE) == -1) {
+ goto out;
+ }
+ GB_FREE(path);
+
+ GB_CMD_EXEC_AND_VALIDATE(exec, reply, blk, blk->volume, REPLACE_SRV);
+ if (reply->exit) {
+ snprintf(reply->out, 8192, "replace portal failed");
+ goto out;
+ }
+ GB_FREE(exec);
+
+out:
+ GB_FREE(path);
+ GB_FREE(exec);
+ return reply;
+}
+
+
+blockResponse *
block_create_1_svc_st(blockCreate *blk, struct svc_req *rqstp)
{
char *tmp = NULL;
@@ -2731,12 +3568,19 @@ block_delete_cli_1_svc_st(blockDeleteCli *blk, struct svc_req *rqstp)
GB_METALOCK_OR_GOTO(lkfd, blk->volume, errCode, errMsg, optfail);
if (glfs_access(glfs, blk->block_name, F_OK)) {
- LOG("mgmt", GB_LOG_ERROR,
- "block with name %s doesn't exist in the volume %s",
- blk->block_name, blk->volume);
- GB_ASPRINTF(&errMsg, "block %s/%s doesn't exist", blk->volume,
- blk->block_name);
- errCode = ENOENT;
+ errCode = errno;
+ if (errCode == ENOENT) {
+ GB_ASPRINTF(&errMsg, "block %s/%s doesn't exist",
+ blk->volume, blk->block_name);
+ LOG("mgmt", GB_LOG_ERROR,
+ "block with name %s doesn't exist in the volume %s",
+ blk->block_name, blk->volume);
+ } else {
+ GB_ASPRINTF(&errMsg, "block %s/%s is not accessible (%s)",
+ blk->volume, blk->block_name, strerror(errCode));
+ LOG("mgmt", GB_LOG_ERROR, "block %s/%s is not accessible (%s)",
+ blk->volume, blk->block_name, strerror(errCode));
+ }
goto out;
}
@@ -3359,6 +4203,16 @@ block_version_1_svc(void *data, blockResponse *reply, struct svc_req *rqstp)
bool_t
+block_replace_1_svc(blockReplace *blk, blockResponse *reply, struct svc_req *rqstp)
+{
+ int ret;
+
+ GB_RPC_CALL(replace, blk, reply, rqstp, ret);
+ return ret;
+}
+
+
+bool_t
block_create_cli_1_svc(blockCreateCli *blk, blockResponse *reply,
struct svc_req *rqstp)
{
@@ -3381,6 +4235,17 @@ block_modify_cli_1_svc(blockModifyCli *blk, blockResponse *reply,
bool_t
+block_replace_cli_1_svc(blockReplaceCli *blk, blockResponse *reply,
+ struct svc_req *rqstp)
+{
+ int ret;
+
+ GB_RPC_CALL(replace_cli, blk, reply, rqstp, ret);
+ return ret;
+}
+
+
+bool_t
block_list_cli_1_svc(blockListCli *blk, blockResponse *reply,
struct svc_req *rqstp)
{
diff --git a/rpc/glfs-operations.c b/rpc/glfs-operations.c
index d5d3aba..b1f68ac 100644
--- a/rpc/glfs-operations.c
+++ b/rpc/glfs-operations.c
@@ -359,6 +359,115 @@ blockStuffMetaInfo(MetaInfo *info, char *line)
int
+blockParseValidServers(struct glfs* glfs, char *metafile,
+ int *errCode, blockServerDefPtr *savelist, char *skiphost)
+{
+ blockServerDefPtr list = *savelist;
+ char fpath[PATH_MAX] = {0};
+ struct glfs_fd *tgmfd = NULL;
+ char line[1024];
+ int ret = -1;
+ char *h, *s, *sep;
+ size_t i, count = 0;
+ bool match;
+
+
+ snprintf(fpath, sizeof fpath, "%s/%s", GB_METADIR, metafile);
+ tgmfd = glfs_open(glfs, fpath, O_RDONLY);
+ if (!tgmfd) {
+ if (errCode) {
+ *errCode = errno;
+ }
+ LOG("gfapi", GB_LOG_ERROR, "glfs_open(%s) failed[%s]", metafile,
+ strerror(errno));
+ goto out;
+ }
+
+ while ((ret = glfs_read (tgmfd, line, sizeof(line), 0)) > 0) {
+ /* clip till current line */
+ h = line;
+ sep = strchr(h, '\n');
+ *sep = '\0';
+
+ count += strlen(h) + 1;
+
+ /* Part before ':' */
+ sep = strchr(h, ':');
+ *sep = '\0';
+
+ switch (blockMetaKeyEnumParse(h)) {
+ case GB_META_VOLUME:
+ case GB_META_GBID:
+ case GB_META_SIZE:
+ case GB_META_HA:
+ case GB_META_ENTRYCREATE:
+ case GB_META_PASSWD:
+ break;
+ default:
+ if (skiphost && !strcmp(h, skiphost)) {
+ break; /* switch case */
+ }
+ /* Part after ':' and before '\n' */
+ s = sep + 1;
+ while(*s == ' ') {
+ s++;
+ }
+
+ if (!list) {
+ if (blockhostIsValid(s)) {
+ if (GB_ALLOC(list) < 0)
+ goto out;
+ if (GB_ALLOC(list->hosts) < 0)
+ goto out;
+ if (GB_STRDUP(list->hosts[0], h) < 0)
+ goto out;
+
+ list->nhosts = 1;
+ }
+ } else {
+ match = false;
+ for (i = 0; i < list->nhosts; i++) {
+ if (!strcmp(list->hosts[i], h)) {
+ match = true;
+ break; /* for loop */
+ }
+ }
+ if (!match && blockhostIsValid(s)){
+ if(GB_REALLOC_N(list->hosts, list->nhosts+1) < 0)
+ goto out;
+ if (GB_STRDUP(list->hosts[list->nhosts], h) < 0)
+ goto out;
+
+ list->nhosts++;
+ }
+ }
+ break; /* switch case */
+ }
+
+ glfs_lseek(tgmfd, count, SEEK_SET);
+ }
+
+ if (ret < 0 && errCode) { /*Failure from glfs_read*/
+ *errCode = errno;
+ goto out;
+ }
+
+ *savelist = list;
+ list = NULL;
+ ret = 0;
+
+ out:
+ if (tgmfd && glfs_close(tgmfd) != 0) {
+ LOG("gfapi", GB_LOG_ERROR, "glfs_close(%s): failed[%s]",
+ metafile, strerror(errno));
+ }
+ blockServerDefFree(list);
+
+ return ret;
+}
+
+
+int
blockGetMetaInfo(struct glfs* glfs, char* metafile, MetaInfo *info,
int *errCode)
{
diff --git a/rpc/glfs-operations.h b/rpc/glfs-operations.h
index bd6b497..b458e4b 100644
--- a/rpc/glfs-operations.h
+++ b/rpc/glfs-operations.h
@@ -64,4 +64,8 @@ blockGetMetaInfo(struct glfs* glfs, char* metafile, MetaInfo *info,
void
blockFreeMetaInfo(MetaInfo *info);
+int
+blockParseValidServers(struct glfs* glfs, char *metafile, int *errCode,
+ blockServerDefPtr *savelist, char *skiphost);
+
#endif /* _GLFS_OPERATIONS_H */
diff --git a/rpc/rpcl/block.x b/rpc/rpcl/block.x
index 6eeb321..4ad0549 100644
--- a/rpc/rpcl/block.x
+++ b/rpc/rpcl/block.x
@@ -33,6 +33,14 @@ struct blockModify {
bool auth_mode;
};
+struct blockReplace {
+ char volume[255];
+ char block_name[255];
+ char gbid[127];
+ char ipaddr[255];
+ char ripaddr[255];
+};
+
struct blockCreateCli {
char volume[255];
u_quad_t size;
@@ -75,6 +83,15 @@ struct blockModifyCli {
enum JsonResponseFormat json_resp;
};
+struct blockReplaceCli {
+ char volume[255];
+ char block_name[255];
+ char old_node[255];
+ char new_node[255];
+ bool force;
+ enum JsonResponseFormat json_resp;
+};
+
struct blockResponse {
int exit; /* exit code of the command */
string out<>; /* output; TODO: return respective objects */
@@ -88,6 +105,7 @@ program GLUSTER_BLOCK {
blockResponse BLOCK_DELETE(blockDelete) = 2;
blockResponse BLOCK_MODIFY(blockModify) = 3;
blockResponse BLOCK_VERSION() = 4;
+ blockResponse BLOCK_REPLACE(blockReplace) = 5;
} = 1;
} = 21215311; /* B2 L12 O15 C3 K11 */
@@ -98,5 +116,6 @@ program GLUSTER_BLOCK_CLI {
blockResponse BLOCK_INFO_CLI(blockInfoCli) = 3;
blockResponse BLOCK_DELETE_CLI(blockDeleteCli) = 4;
blockResponse BLOCK_MODIFY_CLI(blockModifyCli) = 5;
+ blockResponse BLOCK_REPLACE_CLI(blockReplaceCli) = 6;
} = 1;
} = 212153113; /* B2 L12 O15 C3 K11 C3 */