From 540e81676b1011dcf85fbe5cd6739a4f2143b2ab Mon Sep 17 00:00:00 2001 From: Prasanna Kumar Kalever Date: Mon, 5 Feb 2018 15:07:26 +0530 Subject: 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 [] [--json*] commands: [...] replace [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 --- cli/gluster-block.c | 149 +++- rpc/block_svc_routines.c | 1571 ++++++++++++++++++++++++++++++++--------- rpc/glfs-operations.c | 109 +++ rpc/glfs-operations.h | 4 + rpc/rpcl/block.x | 19 + utils/capabilities.h | 4 + utils/common.c | 40 ++ utils/common.h | 11 + utils/gluster-block-caps.info | 12 + utils/utils.h | 36 +- 10 files changed, 1565 insertions(+), 390 deletions(-) diff --git a/cli/gluster-block.c b/cli/gluster-block.c index 53f72bc..98f5bba 100644 --- a/cli/gluster-block.c +++ b/cli/gluster-block.c @@ -14,14 +14,16 @@ # include "config.h" -# define GB_CREATE_HELP_STR "gluster-block create "\ - "[ha ] [auth ] "\ - "[prealloc ] "\ +# define GB_CREATE_HELP_STR "gluster-block create " \ + "[ha ] [auth ] " \ + "[prealloc ] " \ " [--json*]" # define GB_DELETE_HELP_STR "gluster-block delete [force] [--json*]" -# define GB_MODIFY_HELP_STR "gluster-block modify "\ +# define GB_MODIFY_HELP_STR "gluster-block modify " \ " [--json*]" +# define GB_REPLACE_HELP_STR "gluster-block replace " \ + " [force] [--json*]" # define GB_INFO_HELP_STR "gluster-block info [--json*]" # define GB_LIST_HELP_STR "gluster-block list [--json*]" @@ -43,7 +45,8 @@ typedef enum clioperations { LIST_CLI = 2, INFO_CLI = 3, DELETE_CLI = 4, - MODIFY_CLI = 5 + MODIFY_CLI = 5, + REPLACE_CLI = 6 } clioperations; @@ -59,6 +62,7 @@ glusterBlockCliRPC_1(void *cobj, clioperations opt) blockInfoCli *info_obj; blockListCli *list_obj; blockModifyCli *modify_obj; + blockReplaceCli *replace_obj; blockResponse reply = {0,}; char errMsg[2048] = {0}; @@ -145,6 +149,15 @@ glusterBlockCliRPC_1(void *cobj, clioperations opt) goto out; } break; + case REPLACE_CLI: + replace_obj = cobj; + if (block_replace_cli_1(replace_obj, &reply, clnt) != RPC_SUCCESS) { + LOG("cli", GB_LOG_ERROR, "%sblock %s replace on volume %s failed", + clnt_sperror(clnt, "block_replace_cli_1"), replace_obj->block_name, + replace_obj->volume); + goto out; + } + break; } out: @@ -204,6 +217,9 @@ glusterBlockHelp(void) " modify \n" " modify block device.\n" "\n" + " replace [force]\n" + " replace operations.\n" + "\n" " help\n" " show this message and exit.\n" "\n" @@ -216,13 +232,26 @@ glusterBlockHelp(void) } static bool -glusterBlockIsNameAcceptable (char *name) +glusterBlockIsNameAcceptable(char *name) { int i = 0; - if (!name || strlen(name) == 0) + if (!name || strlen(name) == 0 || strlen(name) > 255) return FALSE; for (i = 0; i < strlen(name); i++) { - if (!isalnum (name[i]) && (name[i] != '_') && (name[i] != '-')) + if (!isalnum(name[i]) && (name[i] != '_') && (name[i] != '-')) + return FALSE; + } + return TRUE; +} + +static bool +glusterBlockIsAddrAcceptable(char *addr) +{ + int i = 0; + if (!addr || strlen(addr) == 0 || strlen(addr) > 255) + return FALSE; + for (i = 0; i < strlen(addr); i++) { + if (!isdigit(addr[i]) && (addr[i] != '.')) return FALSE; } return TRUE; @@ -235,9 +264,14 @@ glusterBlockParseVolumeBlock(char *volumeblock, char *volume, char *block, int ret = -1; size_t len = 0; char *sep = NULL; + char *tmp = NULL; + + if (GB_STRDUP(tmp, volumeblock) < 0) { + goto out; + } /* part before '/' is the volume name */ - sep = strchr(volumeblock, '/'); + sep = strchr(tmp, '/'); if (!sep) { MSG("argument ''(%s) is incorrect\n", volumeblock); @@ -245,29 +279,25 @@ glusterBlockParseVolumeBlock(char *volumeblock, char *volume, char *block, LOG("cli", GB_LOG_ERROR, "%s failed while parsing ", op); goto out; } - len = sep - volumeblock; - if (len >= 255 || strlen(sep+1) >= 255) { - MSG("%s\n", "Both volname and blockname should be less than 255 " - "characters long"); - MSG("%s\n", helpstr); - LOG("cli", GB_LOG_ERROR, "%s failed while parsing ", op); + *sep = '\0'; + + if (!glusterBlockIsNameAcceptable(tmp)) { + MSG("volume name(%s) should contain only aplhanumeric,'-', '_' characters " + "and should be less than 255 characters long\n", volume); goto out; } - strncpy(volume, volumeblock, len); /* part after / is blockname */ - strncpy(block, sep+1, strlen(sep+1)); - if (!glusterBlockIsNameAcceptable (volume)) { - MSG("volume name(%s) should contain only aplhanumeric,'-' " - "and '_' characters\n", volume); - goto out; - } - if (!glusterBlockIsNameAcceptable (block)) { - MSG("block name(%s) should contain only aplhanumeric,'-' " - "and '_' characters\n", block); + if (!glusterBlockIsNameAcceptable(sep+1)) { + MSG("block name(%s) should contain only aplhanumeric,'-', '_' characters " + "and should be less than 255 characters long\n", block); goto out; } + strncpy(volume, tmp, strlen(tmp)); + strncpy(block, sep+1, strlen(sep+1)); ret = 0; + out: + GB_FREE(tmp); return ret; } @@ -522,6 +552,68 @@ glusterBlockInfo(int argcount, char **options, int json) } +static int +glusterBlockReplace(int argcount, char **options, int json) +{ + blockReplaceCli robj = {0}; + int ret = -1; + bool singleBlock = false; + char helpMsg[256] = {0, }; + + + if (argcount < 5 || argcount > 6) { + MSG("Inadequate arguments for replace:\n%s\n", GB_REPLACE_HELP_STR); + return -1; + } + + if (glusterBlockParseVolumeBlock(options[2], robj.volume, robj.block_name, + helpMsg, "replace")) { + goto out; + } + + if (!glusterBlockIsAddrAcceptable(options[3])) { + MSG("host addr (%s) should be a valid ip address\n%s\n", + options[3], GB_REPLACE_HELP_STR); + goto out; + } + strcpy(robj.old_node, options[3]); + + if (!glusterBlockIsAddrAcceptable(options[4])) { + MSG("host addr (%s) should be a valid ip address\n%s\n", + options[4], GB_REPLACE_HELP_STR); + goto out; + } + strcpy(robj.new_node, options[4]); + + if (!strncmp(robj.old_node, robj.new_node, 255)) { + MSG(" (%s) and (%s) cannot be same\n%s\n", + robj.old_node, robj.new_node, GB_REPLACE_HELP_STR); + goto out; + } + + robj.json_resp = json; + + if (argcount == 6) { + if (strcmp(options[5], "force")) { + MSG("unknown option '%s' for replace:\n%s\n", options[5], GB_REPLACE_HELP_STR); + return -1; + } else { + robj.force = true; + } + } + + ret = glusterBlockCliRPC_1(&robj, REPLACE_CLI); + if (ret) { + LOG("cli", GB_LOG_ERROR, "failed replace on volume %s", + robj.volume); + } + + out: + + return ret; +} + + static int glusterBlockParseArgs(int count, char **options) { @@ -577,6 +669,13 @@ glusterBlockParseArgs(int count, char **options) } goto out; + case GB_CLI_REPLACE: + ret = glusterBlockReplace(count, options, json); + if (ret) { + LOG("cli", GB_LOG_ERROR, "%s", FAILED_REPLACE); + } + goto out; + case GB_CLI_DELETE: ret = glusterBlockDelete(count, options, json); if (ret) { 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; + } + + 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; - return FALSE; + 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,134 +1395,1007 @@ glusterBlockModifyRemoteAsync(MetaInfo *info, } -static int -glusterBlockCleanUp(struct glfs *glfs, char *blockname, - bool deleteall, bool forcedel, blockRemoteDeleteResp *drobj) +bool * +glusterBlockBuildMinCaps(void *data, operations opt) { - int ret = -1; - size_t i; - static blockDelete dobj; - size_t cleanupsuccess = 0; - size_t count = 0; - MetaInfo *info = NULL; - int asyncret = 0; - char *errMsg = NULL; - + blockCreateCli *cblk = NULL; + blockDeleteCli *dblk = NULL; + blockModifyCli *mblk = NULL; + blockReplaceCli *rblk = NULL; + bool *minCaps = NULL; - if (GB_ALLOC(info) < 0) { - goto out; - } - ret = blockGetMetaInfo(glfs, blockname, info, NULL); - if (ret) { - goto out; + if (GB_ALLOC_N(minCaps, GB_CAP_MAX) < 0) { + return NULL; } - strcpy(dobj.block_name, blockname); - strcpy(dobj.gbid, info->gbid); - - count = glusterBlockDeleteFillArgs(info, deleteall, NULL, NULL, NULL); - asyncret = glusterBlockDeleteRemoteAsync(info, glfs, &dobj, count, - deleteall, &drobj); - if (asyncret) { - LOG("mgmt", GB_LOG_WARNING, - "glusterBlockDeleteRemoteAsync: return %d %s for block %s on volume %s", - asyncret, FAILED_REMOTE_AYNC_DELETE, blockname, info->volume); - } + switch (opt) { + case CREATE_SRV: + cblk = (blockCreateCli *)data; - /* delete metafile and block file */ - if (deleteall) { - blockFreeMetaInfo(info); + 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; - if (GB_ALLOC(info) < 0) { - goto out; + 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; - ret = blockGetMetaInfo(glfs, blockname, info, NULL); - if (ret) { - goto out; + 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; - for (i = 0; i < info->nhosts; i++) { - switch (blockMetaStatusEnumParse(info->list[i]->status)) { - case GB_CONFIG_INPROGRESS: /* un touched */ - case GB_CLEANUP_SUCCESS: - cleanupsuccess++; - break; - } + minCaps[GB_REPLACE_CAP] = true; + if (rblk->json_resp) { + minCaps[GB_JSON_CAP] = true; } + break; + } - if (forcedel || cleanupsuccess == info->nhosts) { - GB_METAUPDATE_OR_GOTO(lock, glfs, blockname, info->volume, - ret, errMsg, out, "ENTRYDELETE: INPROGRESS\n"); - if (glusterBlockDeleteEntry(glfs, info->volume, info->gbid)) { - GB_METAUPDATE_OR_GOTO(lock, glfs, blockname, info->volume, - ret, errMsg, out, "ENTRYDELETE: FAIL\n"); - LOG("mgmt", GB_LOG_ERROR, "%s %s for block %s", FAILED_DELETING_FILE, - info->volume, blockname); - ret = -1; - goto out; + 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; } - GB_METAUPDATE_OR_GOTO(lock, glfs, blockname, info->volume, - ret, errMsg, out, "ENTRYDELETE: SUCCESS\n"); - ret = glusterBlockDeleteMetaFile(glfs, info->volume, blockname); - if (ret) { - LOG("mgmt", GB_LOG_ERROR, "%s %s for block %s", - FAILED_DELETING_META, info->volume, blockname); - goto out; + } else { + if (GB_ASPRINTF(errMsg, "Version check failed between block servers. (%s)", + localErrMsg) == -1) { + errCode = ENOMEM; } } + goto out; } out: - blockFreeMetaInfo(info); - GB_FREE (errMsg); - - /* ignore asyncret if force delete is used */ - if (forcedel) { - asyncret = 0; - } - - return asyncret?asyncret:ret; + GB_FREE(minCaps); + GB_FREE(localErrMsg); + return errCode; } -static int -glusterBlockAuditRequest(struct glfs *glfs, - blockCreateCli *blk, - blockCreate *cobj, - blockServerDefPtr list, - blockRemoteCreateResp **reply) +blockServerDefPtr +glusterBlockGetListFromInfo(MetaInfo *info) { - int ret = -1; size_t i; - size_t successcnt = 0; - size_t failcnt = 0; - size_t spent; - size_t spare; - size_t morereq; - MetaInfo *info; - static bool needcleanup = FALSE; /* partial failure on subset of nodes */ + blockServerDefPtr list = NULL; - if (GB_ALLOC(info) < 0) { - goto out; + if (!info || GB_ALLOC(list) < 0) { + return NULL; } - ret = blockGetMetaInfo(glfs, blk->block_name, info, NULL); - if (ret) { + if (GB_ALLOC_N(list->hosts, info->mpath) < 0) { goto out; } for (i = 0; i < info->nhosts; i++) { - switch (blockMetaStatusEnumParse(info->list[i]->status)) { - case GB_CONFIG_SUCCESS: - case GB_AUTH_ENFORCED: - successcnt++; - break; - case GB_CONFIG_INPROGRESS: - case GB_CONFIG_FAIL: - failcnt++; + 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) +{ + int ret = -1; + size_t i; + static blockDelete dobj; + size_t cleanupsuccess = 0; + size_t count = 0; + MetaInfo *info = NULL; + int asyncret = 0; + char *errMsg = NULL; + + + if (GB_ALLOC(info) < 0) { + goto out; + } + + ret = blockGetMetaInfo(glfs, blockname, info, NULL); + if (ret) { + goto out; + } + + strcpy(dobj.block_name, blockname); + strcpy(dobj.gbid, info->gbid); + + count = glusterBlockDeleteFillArgs(info, deleteall, NULL, NULL, NULL); + asyncret = glusterBlockDeleteRemoteAsync(info, glfs, &dobj, count, + deleteall, &drobj); + if (asyncret) { + LOG("mgmt", GB_LOG_WARNING, + "glusterBlockDeleteRemoteAsync: return %d %s for block %s on volume %s", + asyncret, FAILED_REMOTE_AYNC_DELETE, blockname, info->volume); + } + + /* delete metafile and block file */ + if (deleteall) { + blockFreeMetaInfo(info); + + if (GB_ALLOC(info) < 0) { + goto out; + } + + ret = blockGetMetaInfo(glfs, blockname, info, NULL); + if (ret) { + goto out; + } + + for (i = 0; i < info->nhosts; i++) { + switch (blockMetaStatusEnumParse(info->list[i]->status)) { + case GB_CONFIG_INPROGRESS: /* un touched */ + case GB_CLEANUP_SUCCESS: + cleanupsuccess++; + break; + } + } + + if (forcedel || cleanupsuccess == info->nhosts) { + GB_METAUPDATE_OR_GOTO(lock, glfs, blockname, info->volume, + ret, errMsg, out, "ENTRYDELETE: INPROGRESS\n"); + if (glusterBlockDeleteEntry(glfs, info->volume, info->gbid)) { + GB_METAUPDATE_OR_GOTO(lock, glfs, blockname, info->volume, + ret, errMsg, out, "ENTRYDELETE: FAIL\n"); + LOG("mgmt", GB_LOG_ERROR, "%s %s for block %s", FAILED_DELETING_FILE, + info->volume, blockname); + ret = -1; + goto out; + } + GB_METAUPDATE_OR_GOTO(lock, glfs, blockname, info->volume, + ret, errMsg, out, "ENTRYDELETE: SUCCESS\n"); + ret = glusterBlockDeleteMetaFile(glfs, info->volume, blockname); + if (ret) { + LOG("mgmt", GB_LOG_ERROR, "%s %s for block %s", + FAILED_DELETING_META, info->volume, blockname); + goto out; + } + } + } + + out: + blockFreeMetaInfo(info); + GB_FREE (errMsg); + + /* ignore asyncret if force delete is used */ + if (forcedel) { + asyncret = 0; + } + + return asyncret?asyncret:ret; +} + + +static int +glusterBlockAuditRequest(struct glfs *glfs, + blockCreateCli *blk, + blockCreate *cobj, + blockServerDefPtr list, + blockRemoteCreateResp **reply) +{ + int ret = -1; + size_t i; + size_t successcnt = 0; + size_t failcnt = 0; + size_t spent; + size_t spare; + size_t morereq; + MetaInfo *info; + static bool needcleanup = FALSE; /* partial failure on subset of nodes */ + + + if (GB_ALLOC(info) < 0) { + goto out; + } + + ret = blockGetMetaInfo(glfs, blk->block_name, info, NULL); + if (ret) { + goto out; + } + + for (i = 0; i < info->nhosts; i++) { + switch (blockMetaStatusEnumParse(info->list[i]->status)) { + case GB_CONFIG_SUCCESS: + case GB_AUTH_ENFORCED: + successcnt++; + break; + case GB_CONFIG_INPROGRESS: + case GB_CONFIG_FAIL: + failcnt++; } } @@ -1512,141 +2435,31 @@ glusterBlockAuditRequest(struct glfs *glfs, blk->block_name, blk->volume); ret = glusterBlockCreateRemoteAsync(list, spent, morereq, glfs, cobj, reply); - if (ret) { - LOG("mgmt", GB_LOG_WARNING, "glusterBlockCreateRemoteAsync: return %d" - " %s for block %s on volume %s with hosts %s", ret, - FAILED_REMOTE_AYNC_CREATE, blk->block_name, - blk->volume, blk->block_hosts); - } - /* we could ideally moved this into #CreateRemoteAsync fail {} */ - needcleanup = TRUE; - } - } - - ret = glusterBlockAuditRequest(glfs, blk, cobj, list, reply); - if (ret) { - LOG("mgmt", GB_LOG_ERROR, "glusterBlockAuditRequest: return %d" - "volume: %s hosts: %s blockname %s", ret, - blk->volume, blk->block_hosts, blk->block_name); - } - - out: - if (needcleanup) { - glusterBlockCleanUp(glfs, blk->block_name, FALSE, FALSE, (*reply)->obj); - } - - blockFreeMetaInfo(info); - 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); + if (ret) { + LOG("mgmt", GB_LOG_WARNING, "glusterBlockCreateRemoteAsync: return %d" + " %s for block %s on volume %s with hosts %s", ret, + FAILED_REMOTE_AYNC_CREATE, blk->block_name, + blk->volume, blk->block_hosts); + } + /* we could ideally moved this into #CreateRemoteAsync fail {} */ + needcleanup = TRUE; } } -} - -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; + ret = glusterBlockAuditRequest(glfs, blk, cobj, list, reply); + if (ret) { + LOG("mgmt", GB_LOG_ERROR, "glusterBlockAuditRequest: return %d" + "volume: %s hosts: %s blockname %s", ret, + blk->volume, blk->block_hosts, blk->block_name); } - 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; + out: + if (needcleanup) { + glusterBlockCleanUp(glfs, blk->block_name, FALSE, FALSE, (*reply)->obj); } - return minCaps; + blockFreeMetaInfo(info); + return ret; } @@ -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: @@ -2458,6 +3221,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 <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) { @@ -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; } @@ -3358,6 +4202,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) @@ -3380,6 +4234,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 @@ -358,6 +358,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 */ diff --git a/utils/capabilities.h b/utils/capabilities.h index b157d80..80f03bd 100644 --- a/utils/capabilities.h +++ b/utils/capabilities.h @@ -37,6 +37,8 @@ enum gbCapabilities { GB_MODIFY_CAP, GB_MODIFY_AUTH_CAP, + GB_REPLACE_CAP, + GB_JSON_CAP, GB_CAP_MAX @@ -55,6 +57,8 @@ static const char *const gbCapabilitiesLookup[] = { [GB_MODIFY_CAP] = "modify", [GB_MODIFY_AUTH_CAP] = "modify_auth", + [GB_REPLACE_CAP] = "replace", + [GB_JSON_CAP] = "json", [GB_CAP_MAX] = NULL diff --git a/utils/common.c b/utils/common.c index 98cc0ef..751e2b8 100644 --- a/utils/common.c +++ b/utils/common.c @@ -157,3 +157,43 @@ convertStringToTrillianParse(const char *opt) return -1; } + + +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); +} + + +bool +blockhostIsValid(char *status) +{ + 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: + case GB_RP_SUCCESS: + case GB_RP_FAIL: + case GB_RP_INPROGRESS: + return TRUE; + } + + return FALSE; +} diff --git a/utils/common.h b/utils/common.h index 2d1202a..02940c0 100644 --- a/utils/common.h +++ b/utils/common.h @@ -16,6 +16,13 @@ # include "block.h" +typedef struct blockServerDef { + size_t nhosts; + char **hosts; +} blockServerDef; +typedef blockServerDef *blockServerDefPtr; + + static const char *const JsonResponseFormatLookup[] = { [GB_JSON_NONE] = "", @@ -82,4 +89,8 @@ char* glusterBlockFormatSize(const char *dom, size_t bytes); int convertStringToTrillianParse(const char *opt); +void blockServerDefFree(blockServerDefPtr blkServers); + +bool blockhostIsValid(char *status); + # endif /* _COMMON_H */ diff --git a/utils/gluster-block-caps.info b/utils/gluster-block-caps.info index 2dcdbd4..ffdf679 100644 --- a/utils/gluster-block-caps.info +++ b/utils/gluster-block-caps.info @@ -96,3 +96,15 @@ modify_auth: true # Since: 0.2 ## json: true + + +## +# Nature: cli command +# +# Label: 'replace' +# +# Description: capability to replace node for a given block +# +# Since: 0.4 +## +replace: true diff --git a/utils/utils.h b/utils/utils.h index 7141a3f..7693b5c 100644 --- a/utils/utils.h +++ b/utils/utils.h @@ -85,6 +85,10 @@ # define FAILED_DELETING_FILE "failed while deleting block file from gluster volume" # define FAILED_DELETING_META "failed while deleting block meta file from volume" +/* Target Replace */ +# define FAILED_REPLACE "failed in replace" +# define FAILED_REMOTE_REPLACE "failed in remote replace portal" + # define FAILED_DEPENDENCY "failed dependency, check if you have targetcli and tcmu-runner installed" # define FMT_WARN(fmt...) do { if (0) printf (fmt); } while (0) @@ -328,18 +332,19 @@ extern struct gbConf gbConf; typedef enum gbCliCmdlineOption { - GB_CLI_UNKNOWN = 0, - GB_CLI_CREATE = 1, - GB_CLI_LIST = 2, - GB_CLI_INFO = 3, - GB_CLI_DELETE = 4, - GB_CLI_MODIFY = 5, - GB_CLI_HELP = 6, - GB_CLI_HYPHEN_HELP = 7, - GB_CLI_VERSION = 8, - GB_CLI_HYPHEN_VERSION = 9, - GB_CLI_USAGE = 10, - GB_CLI_HYPHEN_USAGE = 11, + GB_CLI_UNKNOWN = 0, + GB_CLI_CREATE, + GB_CLI_LIST, + GB_CLI_INFO, + GB_CLI_DELETE, + GB_CLI_MODIFY, + GB_CLI_REPLACE, + GB_CLI_HELP, + GB_CLI_HYPHEN_HELP, + GB_CLI_VERSION, + GB_CLI_HYPHEN_VERSION, + GB_CLI_USAGE, + GB_CLI_HYPHEN_USAGE, GB_CLI_OPT_MAX } gbCliCmdlineOption; @@ -351,6 +356,7 @@ static const char *const gbCliCmdlineOptLookup[] = { [GB_CLI_INFO] = "info", [GB_CLI_DELETE] = "delete", [GB_CLI_MODIFY] = "modify", + [GB_CLI_REPLACE] = "replace", [GB_CLI_HELP] = "help", [GB_CLI_HYPHEN_HELP] = "--help", [GB_CLI_VERSION] = "version", @@ -442,6 +448,9 @@ typedef enum MetaStatus { GB_CLEANUP_SUCCESS = 9, GB_CLEANUP_FAIL = 10, GB_CLEANUP_INPROGRESS = 11, + GB_RP_SUCCESS = 12, + GB_RP_INPROGRESS = 13, + GB_RP_FAIL = 14, GB_METASTATUS_MAX } MetaStatus; @@ -459,6 +468,9 @@ static const char *const MetaStatusLookup[] = { [GB_CLEANUP_INPROGRESS] = "CLEANUPINPROGRESS", [GB_CLEANUP_SUCCESS] = "CLEANUPSUCCESS", [GB_CLEANUP_FAIL] = "CLEANUPFAIL", + [GB_RP_SUCCESS] = "RPSUCCESS", + [GB_RP_INPROGRESS] = "RPINPROGRESS", + [GB_RP_FAIL] = "RPFAIL", [GB_METASTATUS_MAX] = NULL, }; -- cgit