diff options
author | Prasanna Kumar Kalever <prasanna.kalever@redhat.com> | 2018-02-05 15:07:26 +0530 |
---|---|---|
committer | Prasanna Kumar Kalever <prasanna.kalever@redhat.com> | 2018-02-07 16:49:21 +0530 |
commit | 540e81676b1011dcf85fbe5cd6739a4f2143b2ab (patch) | |
tree | 7eed76faf5483e03bbbe59bb23ede3675ae6ad97 /rpc | |
parent | f217c0bf9cf464e21c01fa50643b778f236acedb (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.c | 1343 | ||||
-rw-r--r-- | rpc/glfs-operations.c | 109 | ||||
-rw-r--r-- | rpc/glfs-operations.h | 4 | ||||
-rw-r--r-- | rpc/rpcl/block.x | 19 |
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 */ |