From 005b445d684f30e8611c9b2a374cdc798a6cdcbb Mon Sep 17 00:00:00 2001 From: Raghavendra Bhat Date: Fri, 29 Nov 2013 12:29:38 +0530 Subject: cli/glusterd: implement the snap and cg delete functionalities Change-Id: Icdb66c89acdd043d0d6368c48ce2e01b1a40966f Signed-off-by: Raghavendra Bhat --- xlators/mgmt/glusterd/src/glusterd-snapshot.c | 966 ++++++++++++++++++++++---- xlators/mgmt/glusterd/src/glusterd-utils.c | 186 +++++ xlators/mgmt/glusterd/src/glusterd-utils.h | 9 + xlators/mgmt/glusterd/src/glusterd-volgen.c | 33 + xlators/mgmt/glusterd/src/glusterd-volgen.h | 4 + 5 files changed, 1063 insertions(+), 135 deletions(-) (limited to 'xlators') diff --git a/xlators/mgmt/glusterd/src/glusterd-snapshot.c b/xlators/mgmt/glusterd/src/glusterd-snapshot.c index b5859faaf..3e98e2fa2 100644 --- a/xlators/mgmt/glusterd/src/glusterd-snapshot.c +++ b/xlators/mgmt/glusterd/src/glusterd-snapshot.c @@ -955,65 +955,6 @@ out: return ret; } -int -glusterd_snapshot_prevalidate (dict_t *dict, char **op_errstr, - dict_t *rsp_dict) -{ - int snap_command = 0; - xlator_t *this = NULL; - int ret = -1; - - this = THIS; - - GF_ASSERT (this); - GF_ASSERT (dict); - GF_ASSERT (rsp_dict); //not sure if this is needed, verify. - - ret = dict_get_int32 (dict, "type", &snap_command); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, "unable to get the type of " - "the snapshot command"); - goto out; - } - - switch (snap_command) { - case (GF_SNAP_OPTION_TYPE_CREATE): - ret = glusterd_snapshot_create_prevalidate (dict, op_errstr, - rsp_dict); - if (ret) { - gf_log (this->name, GF_LOG_WARNING, "Snapshot create " - "pre-validation failed"); - goto out; - } - break; - - case (GF_SNAP_OPTION_TYPE_CONFIG): - ret = glusterd_snapshot_config_prevalidate (dict, op_errstr); - if (ret) { - gf_log (this->name, GF_LOG_WARNING, "Snapshot config " - "pre-validation failed"); - goto out; - } - break; - - case GF_SNAP_OPTION_TYPE_RESTORE: - ret = glusterd_snapshot_restore_prevalidate (dict, op_errstr); - if (ret) { - gf_log (this->name, GF_LOG_WARNING, "Snapshot restore " - "validation failed"); - goto out; - } - break; - default: - gf_log (this->name, GF_LOG_WARNING, "invalid snap command"); - goto out; - } - - ret = 0; -out: - return ret; -} - glusterd_snap_t* glusterd_new_snap_object() { @@ -2665,6 +2606,55 @@ out: return ret; } +int32_t +glusterd_snap_delete (glusterd_snap_t *snap) +{ + int32_t ret = -1; + xlator_t *this = NULL; + + this = THIS; + GF_ASSERT (this); + + if (!snap) { + gf_log (this->name, GF_LOG_WARNING, "snap object is NULL"); + goto out; + } + + GF_FREE (snap->description); + ret = glusterd_volinfo_delete (snap->snap_volume); + if (ret) + gf_log (this->name, GF_LOG_WARNING, "deleting the snap volume" + "failed for the snap %s", snap->snap_name); + GF_FREE (snap); + ret = 0; + +out: + return ret; +} + +int32_t +glusterd_cg_delete (glusterd_snap_cg_t *cg) +{ + int32_t ret = -1; + xlator_t *this = NULL; + + this = THIS; + GF_ASSERT (this); + + if (!cg) { + gf_log (this->name, GF_LOG_WARNING, "consistency group is " + "NULL"); + goto out; + } + + GF_FREE (cg->description); + GF_FREE (cg); + ret = 0; + +out: + return ret; +} + /* this should be the last thing to be done. 1. Do op stage related checks such as whether volume is there or not etc 2. Do quorum checks. @@ -3260,113 +3250,733 @@ out: return snapname; } -/* name can be either the snapname if @volnames contains only one volume or - cg name if there are multiple volume names in volnames string -*/ - -int32_t -glusterd_snapshot_create_commit (dict_t *dict, char **op_errstr, - dict_t *rsp_dict) +/* This is a snapshot remove handler function. This function will be + * executed in the originator node. This function is responsible for + * calling mgmt v3 framework to do the actual remove on all the bricks + * + * @param req RPC request object + * @param op gluster operation + * @param dict dictionary containing snapshot remove request + * @param err_str In case of an err this string should be populated + * @param len length of err_str buffer + * + * @return Negative value on Failure and 0 in success + */ +int +glusterd_handle_snapshot_remove (rpcsvc_request_t *req, glusterd_op_t op, + dict_t *dict, char *err_str, size_t len) { - int ret = -1; - int i = 0; - int64_t volume_count = 0; - gf_boolean_t is_cg = _gf_false; - char *name = NULL; - char *volname = NULL; - char *tmp = NULL; - char volname_buf[PATH_MAX] = ""; - char snapvolidname[PATH_MAX] = ""; - xlator_t *this = NULL; - glusterd_volinfo_t *volinfo = NULL; - glusterd_snap_cg_t *cg = NULL; - glusterd_conf_t *priv = NULL; - uuid_t *cg_id = NULL; - uuid_t *snap_volid = NULL; - glusterd_snap_t *snap = NULL; - char err_str[PATH_MAX] = ""; + int ret = -1; + int64_t vol_count = 0; + char *volname = NULL; + char *snapname = NULL; + char *cgname = NULL; + glusterd_conf_t *conf = NULL; + glusterd_snap_cg_t *cg = NULL; + xlator_t *this = NULL; this = THIS; GF_ASSERT (this); - priv = this->private; - GF_ASSERT (priv); + conf = this->private; - ret = dict_get_int64 (dict, "volcount", &volume_count); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, "failed to " - "get the volume count"); - goto out; - } + GF_ASSERT (conf); + GF_ASSERT (req); + GF_ASSERT (dict); + GF_ASSERT (err_str); - if (volume_count == 1) { - ret = dict_get_str (dict, "snap-name", &name); + /* If volume name is provided then volcount will be set */ + ret = dict_get_int64 (dict, "volcount", &vol_count); + if (ret) { + /* If volcount is not provided then cgname must be there */ + ret = dict_get_str (dict, "cgname", &cgname); if (ret) { - gf_log (this->name, GF_LOG_ERROR, "Unable to fetch snap-name"); + gf_log (this->name, GF_LOG_ERROR, "Failed to " + "get neither volcount nor cgname"); goto out; } } else { - ret = dict_get_str (dict, "cg-name", &name); + /* TODO: Change the index to 0 when mgmt v3 code is fixed */ + ret = dict_get_str (dict, "volname1", &volname); if (ret) { - gf_log (this->name, GF_LOG_ERROR, "Unable to fetch cg-name"); + gf_log (this->name, GF_LOG_ERROR, "Failed to " + "get volname"); + goto out; + } + ret = dict_get_str (dict, "snapname", &snapname); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Failed to " + "get snapname"); goto out; } } - ret = dict_get_bin (dict, "cg-id", (void **)&cg_id); - if (ret) - gf_log (this->name, GF_LOG_DEBUG, "Not a cg."); - else { - is_cg = _gf_true; - gf_log (this->name, GF_LOG_DEBUG, "cg-id = %s", uuid_utoa(*cg_id)); - } + if (NULL != cgname) { + cg = glusterd_find_snap_cg_by_name (conf, cgname); - if (volume_count > 1) { - cg = glusterd_new_snap_cg_object (volume_count); - if (!cg) { - gf_log (this->name, GF_LOG_ERROR, "cannot create the " - "consistency group %s", name); + if (NULL == cg) { + snprintf (err_str, len, "CG %s not found", cgname); + gf_log (this->name, GF_LOG_WARNING, "%s", err_str); + ret = -1; goto out; } - } - for (i = 1; i < volume_count + 1; i++) { - snprintf (volname_buf, sizeof (volname_buf), - "volname%d", i); - ret = dict_get_str (dict, volname_buf, - &volname); + LOCK (&cg->lock); + { + /* Get the volumes belong to CG */ + ret = glusterd_get_cg_volume_names_lk (dict, cg); + } + UNLOCK (&cg->lock); + if (ret) { - gf_log (this->name, GF_LOG_ERROR, - "failed to get volume name"); + gf_log (this->name, GF_LOG_ERROR, "Failed to get " + "volume names of %s CG", cgname); goto out; } + } - ret = glusterd_volinfo_find (volname, &volinfo); + ret = glusterd_mgmt_v3_initiate_snap_phases (req, op, dict); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Failed to initiate snap " + "phases"); + goto out; + } + + ret = 0; /* Success */ + +out: + return ret; +} + +int +glusterd_snapshot_remove_prevalidate (dict_t *dict, char **op_errstr, + dict_t *rsp_dict) +{ + int32_t ret = -1; + char *volname = NULL; + char *name = NULL; + xlator_t *this = NULL; + glusterd_conf_t *conf = NULL; + glusterd_snap_t *snap = NULL; + glusterd_snap_cg_t *cg = NULL; + char volname_buf[PATH_MAX] = {0, }; + glusterd_volinfo_t *volinfo = NULL; + char err_str[PATH_MAX] = {0, }; + int64_t volcount = 0; + int64_t i = 0; + int64_t j = 0; + gf_boolean_t volume_found = _gf_false; + + this = THIS; + GF_ASSERT (this); + conf = this->private; + GF_ASSERT (conf); + GF_ASSERT (op_errstr); + + if (!dict) { + gf_log (this->name, GF_LOG_ERROR, "input dict is NULL"); + goto out; + } + + ret = dict_get_int64 (dict, "volcount", &volcount); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "getting volcount failed"); + goto out; + } + + /* TODO: The policy for the snapshot create is not decided on + whether to start the snap volume upon the execution of the + snapshot create command. Once the policy is decided, check + here whether the volume is in use before delete command is + executed. (May be a force option to delete forcefully even + when the snap volume is in use.) + */ + + if (volcount > 1) { + ret = dict_get_str (dict, "cgname", &name); if (ret) { - gf_log (this->name, GF_LOG_ERROR, - "failed to get the volinfo for " - "the volume %s", volname); + gf_log (this->name, GF_LOG_ERROR, "getting the cg name" + " failed"); goto out; } - - tmp = generate_snapname (volname, name, is_cg); - if (!tmp) { - gf_log (this->name, - GF_LOG_ERROR, "strdup " - "failed (%s)", name); + cg = glusterd_find_snap_cg_by_name (conf, name); + if (!cg) { + snprintf (err_str, sizeof (err_str), "consistency group" + "%s is not found", name); + gf_log (this->name, GF_LOG_ERROR, "%s", err_str); + *op_errstr = gf_strdup (err_str); goto out; } + GF_ASSERT (volcount == cg->volume_count); - list_for_each_entry (snap, &volinfo->snaps, snap_list) { - if (!strcmp (snap->snap_name, tmp)) { - snprintf (err_str, sizeof (err_str), "snap " - "with name %s already exists", tmp); - gf_log (this->name, GF_LOG_ERROR, "%s", - err_str); - ret = -1; - *op_errstr = gf_strdup (err_str); + for (i = 0; i < volcount; i++) { + volume_found = _gf_false; + snprintf (volname_buf, sizeof (volname_buf), + "volname%ld", i+1); + ret = dict_get_str (dict, volname_buf, &volname); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "volume name " + "is notgiven"); goto out; } - } + for (j = 0; j < volcount; j++) { + volinfo = cg->volumes[j]; + if (!strcmp (volinfo->volname, volname)) { + volume_found = _gf_true; + break; + } + } + if (!volume_found) { + gf_log (this->name, GF_LOG_ERROR, "volume %s" + " is not found in the consistency " + "group %s", volname, name); + goto out; + } + } + } else { + snprintf (volname_buf, sizeof (volname_buf), "volname1"); + ret = dict_get_str (dict, volname_buf, &volname); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "volume name is not " + "given"); + goto out; + } + ret = glusterd_volinfo_find (volname, &volinfo); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "failed to get the volinfo for " + "the volume %s", volname); + goto out; + } + ret = dict_get_str (dict, "snapname", &name); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "getting snap name " + "failed (volume: %s)", volname); + goto out; + } + snap = glusterd_find_snap_by_name (volinfo, name); + if (!snap) { + ret = -1; + snprintf (err_str, sizeof (err_str), "snap %s is not " + "found", name); + gf_log (this->name, GF_LOG_ERROR, "%s, (volume: %s)", + err_str, volinfo->volname); + *op_errstr = gf_strdup (err_str); + goto out; + } + } + + ret = 0; +out: + return ret; +} + +int +glusterd_remove_snap (glusterd_brickinfo_t *brickinfo, const char *mount_pt, + const char *volname, const char *snapname, + const char *snap_device) +{ + int ret = -1; + xlator_t *this = NULL; + glusterd_conf_t *priv = NULL; + runner_t runner = {0,}; + char msg[1024] = {0, }; + + this = THIS; + GF_ASSERT (this); + priv = this->private; + GF_ASSERT (priv); + + if (!brickinfo) { + gf_log (this->name, GF_LOG_ERROR, "brickinfo NULL"); + goto out; + } + + GF_ASSERT (mount_pt); + GF_ASSERT (volname); + GF_ASSERT (snapname); + GF_ASSERT (snap_device); + + /* sleep for some time so that the glusterfsd process associated + with the snap lvm does not have any reference to the snap and + has been stopped completely + TODO: find the issue because of which umount fails and fix it. + */ + //usleep (24007); + + //ret = umount2 (mount_pt, MNT_FORCE); + runinit (&runner); + snprintf (msg, sizeof (msg), "umount the snapshot mounted path %s", + mount_pt); + runner_add_args (&runner, "umount", mount_pt, NULL); + runner_log (&runner, "", GF_LOG_DEBUG, msg); + + /* We need not do synclock_unlock => runner_run => synclock_lock here. + Because it is needed if we are running a glusterfs process in + runner_run, so that when the glusterfs process started wants to + communicate to glusterd, glusterd wont be able to respond if it + has held the big lock. So we do unlock, run glusterfs process + (thus communicate to glusterd), lock. But since this is not a + glusterfs command that is being run, unlocking and then relocking + is not needed. + */ + ret = runner_run (&runner); + if (ret) { + gf_log (this->name, GF_LOG_WARNING, "unmounting the " + "path %s (brick: %s) failed (%s)", mount_pt, + brickinfo->path, strerror (errno)); + goto out; + } + + runinit (&runner); + snprintf (msg, sizeof(msg), "remove snapshot of the brick %s:%s, " + "device: %s", brickinfo->hostname, brickinfo->path, + snap_device); + runner_add_args (&runner, "/sbin/lvremove", "-f", snap_device, NULL); + runner_log (&runner, "", GF_LOG_DEBUG, msg); + + ret = runner_run (&runner); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "removing snapshot of the " + "brick (%s:%s) of device %s failed", + brickinfo->hostname, brickinfo->path, snap_device); + goto out; + } + +out: + return ret; +} + +int32_t +glusterd_brick_snapshot_remove (glusterd_volinfo_t *snap_volinfo, + glusterd_volinfo_t *actual_volinfo, char *name) +{ + char *mnt_pt = NULL; + struct mntent *entry = NULL; + int32_t ret = -1; + glusterd_brickinfo_t *brickinfo = NULL; + xlator_t *this = NULL; + FILE *mtab = NULL; + + this = THIS; + GF_ASSERT (this); + + if (!snap_volinfo) { + gf_log (this->name, GF_LOG_ERROR, "snap volinfo is NULL"); + goto out; + } + + if (!actual_volinfo) { + gf_log (this->name, GF_LOG_ERROR, "volinfo for the volume " + "is NULL"); + goto out; + } + + if (!name) { + gf_log (this->name, GF_LOG_ERROR, "snapname is NULL " + "(volume: %s)", actual_volinfo->volname); + goto out; + } + + list_for_each_entry (brickinfo, &snap_volinfo->bricks, brick_list) { + if (uuid_compare (brickinfo->uuid, MY_UUID)) + continue; + + ret = glusterd_get_brick_root (brickinfo->path, &mnt_pt); + if (ret) { + gf_log (this->name, GF_LOG_WARNING, "getting the root " + "of the brick for snap volume %s faile", name); + goto out; + } + + entry = glusterd_get_mnt_entry_info (mnt_pt, mtab); + if (!entry) { + gf_log (this->name, GF_LOG_WARNING, "getting the mount" + " entry for the brick %s:%s of the snap %s " + "(volume: %s) failed", brickinfo->hostname, + brickinfo->path, name, actual_volinfo->volname); + ret = -1; + goto out; + } + ret = glusterd_remove_snap (brickinfo, mnt_pt, + actual_volinfo->volname, + name, entry->mnt_fsname); + if (mtab) + endmntent (mtab); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "failed to " + "remove the snapshot %s (%s)", + brickinfo->path, entry->mnt_fsname); + goto out; + } + } + + ret = 0; + +out: + return ret; +} + +int32_t +glusterd_do_snap_remove (glusterd_volinfo_t *volinfo, char *name) +{ + int32_t ret = -1; + xlator_t *this = NULL; + glusterd_conf_t *priv = NULL; + glusterd_snap_t *snap = NULL; + glusterd_volinfo_t *snap_volinfo = NULL; + glusterd_brickinfo_t *brickinfo = NULL; + + this = THIS; + GF_ASSERT (this); + priv = this->private; + GF_ASSERT (priv); + + if (!volinfo) { + gf_log (this->name, GF_LOG_ERROR, "volinfo NULL"); + goto out; + } + + if (!name) { + gf_log (this->name, GF_LOG_ERROR, "name is NULL (volume: %s)", + volinfo->volname); + goto out; + } + + snap = glusterd_find_snap_by_name (volinfo, name); + if (!snap) { + gf_log (this->name, GF_LOG_ERROR, "could not find " + "the snap object by the name %s", + name); + goto out; + } else { + gf_log (this->name, GF_LOG_DEBUG, "found the snap %s " + "(volume: %s)", name, volinfo->volname); + } + + snap_volinfo = snap->snap_volume; + GF_ASSERT (snap_volinfo); + list_for_each_entry (brickinfo, &snap_volinfo->bricks, brick_list) { + if (uuid_compare (brickinfo->uuid, MY_UUID)) + continue; + + /* TODO: The policy for the snapshot create is not + decided on whether to start the snap volume upon + the execution of the snapshot create command. Once + the policy is decided, check here whether the volume + is in use before delete command is executed. + (May be a force option to delete forcefully even + when the snap volume is in use.) + */ + ret = glusterd_snap_brick_stop (volinfo, snap_volinfo, + brickinfo, + _gf_false); + if (ret) { + gf_log (this->name, GF_LOG_WARNING, "stopping " + "the brick %s:%s for the snap %s " + "(volume: %s) failed", + brickinfo->hostname, + brickinfo->path, snap_volinfo->volname, + volinfo->volname); + //goto out; + } + } + ret = glusterd_brick_snapshot_remove (snap_volinfo, volinfo, + name); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "removing the bricks" + " snapshots for the snap %s (volume: %s) " + "failed", name, volinfo->volname); + goto out; + } + + ret = glusterd_store_delete_volume (volinfo, snap->snap_volume); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "removing the snap " + "store for the snap %s (volume %s) failed", + snap->snap_name, volinfo->volname); + goto out; + } + + snap = glusterd_remove_snap_by_name (volinfo, snap->snap_name); + GF_ASSERT (snap); //snap cannot be NULL; + glusterd_snap_delete (snap); //deletes in memory snap object + + ret = glusterd_store_perform_snap_list_store (volinfo); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "doing the snap " + "store for the volume %s failed", + volinfo->volname); + goto out; + } + + ret = 0; +out: + return ret; +} + +char * +glusterd_get_snap_from_cg (glusterd_volinfo_t *volinfo, glusterd_snap_cg_t *cg) +{ + char *snap_name = NULL; + glusterd_snap_t *tmp_snap = NULL; + glusterd_snap_t *snap = NULL; + xlator_t *this = NULL; + + this = THIS; + GF_ASSERT (this); + + if (!volinfo) { + gf_log (this->name, GF_LOG_WARNING, "volinfo NULL"); + goto out; + } + + if (!cg) { + gf_log (this->name, GF_LOG_WARNING, "consistency group NULL"); + goto out; + } + + list_for_each_entry (tmp_snap, &volinfo->snaps, snap_list) { + if ((!uuid_is_null (tmp_snap->cg_id)) && + (uuid_compare (tmp_snap->cg_id, cg->cg_id) == 0)) { + snap = tmp_snap; + break; + } + } + + if (snap) + snap_name = gf_strdup (snap->snap_name); + +out: + return snap_name; +} + +int32_t +glusterd_snapshot_remove_commit (dict_t *dict, char **op_errstr, + dict_t *rsp_dict) +{ + int32_t ret = -1; + char *cg_name = NULL; + char *name = NULL; + glusterd_snap_cg_t *cg = NULL; + xlator_t *this = NULL; + glusterd_conf_t *conf = NULL; + char *volname = NULL; + glusterd_volinfo_t *volinfo = NULL; + int64_t volcount = -1; + char volname_buf[PATH_MAX] = {0, }; + int i = 0; + gf_boolean_t free_name = _gf_false; + + this = THIS; + GF_ASSERT (this); + conf = this->private; + GF_ASSERT (conf); + + if (!dict || !op_errstr) { + gf_log (this->name, GF_LOG_ERROR, "input parameters NULL"); + goto out; + } + + ret = dict_get_int64 (dict, "volcount", &volcount); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "volume count not given"); + goto out; + } + + if (volcount > 1) { + ret = dict_get_str (dict, "cgname", &cg_name); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "getting the cg name" + " failed"); + goto out; + } + cg = glusterd_find_snap_cg_by_name (conf, cg_name); + if (!cg) { + gf_log (this->name, GF_LOG_ERROR, "consistency group " + "%s not found", cg_name); + goto out; + } + GF_ASSERT (volcount == cg->volume_count); + } + + for (i = 0; i < volcount; i++) { + snprintf (volname_buf, sizeof (volname_buf), "volname%d", i+1); + ret = dict_get_str (dict, volname_buf, &volname); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "getting volume name" + "failed"); + goto out; + } + + ret = glusterd_volinfo_find (volname, &volinfo); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "getting the volinfo" + " failed for the volume %s", volname); + goto out; + } + ret = dict_get_str (dict, "snapname", &name); + if (ret && volcount == 1) { + gf_log (this->name, GF_LOG_ERROR, "getting the snap " + "name failed (volume: %s)", volinfo->volname); + goto out; + } + + if (!name) { + name = glusterd_get_snap_from_cg (volinfo, cg); + if (!name) { + gf_log (this->name, GF_LOG_ERROR, "failed to " + "get the snap name " + "(volname: %s, cg name: %s)", + volinfo->volname, cg->cg_name); + goto out; + } + free_name = _gf_true; + } + + ret = glusterd_do_snap_remove (volinfo, name); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "removing the %s %s failed", + (volinfo)?"snap":"cg", name); + goto out; + } + if (free_name) + GF_FREE (name); + name = NULL; + } + + if (volcount > 1) { + ret = glusterd_store_delete_snap_cg (cg); + /* TODO: Handle the errors of deleting store handle of cg. + For now, the error is ignored and we proceed with the + deletion of the in memory cg object. + */ + if (ret) + gf_log (this->name, GF_LOG_WARNING, "removing the " + "store handle for the consistency group %s " + "failed", cg->cg_name); + cg = glusterd_remove_snap_cg_by_name (conf, cg_name); + ret = glusterd_cg_delete (cg); + if (ret) { + gf_log (this->name, GF_LOG_WARNING, "removing the cg " + "object failed"); + goto out; + } + } + + ret = 0; +out: + if (free_name) + GF_FREE (name); + return ret; +} + +/* name can be either the snapname if @volnames contains only one volume or + cg name if there are multiple volume names in volnames string +*/ + +int32_t +glusterd_snapshot_create_commit (dict_t *dict, char **op_errstr, + dict_t *rsp_dict) +{ + int ret = -1; + int i = 0; + int64_t volume_count = 0; + gf_boolean_t is_cg = _gf_false; + char *name = NULL; + char *volname = NULL; + char *tmp = NULL; + char volname_buf[PATH_MAX] = ""; + char snapvolidname[PATH_MAX] = ""; + xlator_t *this = NULL; + glusterd_volinfo_t *volinfo = NULL; + glusterd_snap_cg_t *cg = NULL; + glusterd_conf_t *priv = NULL; + uuid_t *cg_id = NULL; + uuid_t *snap_volid = NULL; + glusterd_snap_t *snap = NULL; + char err_str[PATH_MAX] = ""; + + this = THIS; + GF_ASSERT (this); + priv = this->private; + GF_ASSERT (priv); + + ret = dict_get_int64 (dict, "volcount", &volume_count); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "failed to " + "get the volume count"); + goto out; + } + + if (volume_count == 1) { + ret = dict_get_str (dict, "snap-name", &name); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Unable to fetch snap-name"); + goto out; + } + } else { + ret = dict_get_str (dict, "cg-name", &name); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Unable to fetch cg-name"); + goto out; + } + } + + ret = dict_get_bin (dict, "cg-id", (void **)&cg_id); + if (ret) + gf_log (this->name, GF_LOG_DEBUG, "Not a cg."); + else { + is_cg = _gf_true; + gf_log (this->name, GF_LOG_DEBUG, "cg-id = %s", uuid_utoa(*cg_id)); + } + + if (volume_count > 1) { + cg = glusterd_new_snap_cg_object (volume_count); + if (!cg) { + gf_log (this->name, GF_LOG_ERROR, "cannot create the " + "consistency group %s", name); + goto out; + } + } + + for (i = 1; i < volume_count + 1; i++) { + snprintf (volname_buf, sizeof (volname_buf), + "volname%d", i); + ret = dict_get_str (dict, volname_buf, + &volname); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "failed to get volume name"); + goto out; + } + + ret = glusterd_volinfo_find (volname, &volinfo); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "failed to get the volinfo for " + "the volume %s", volname); + goto out; + } + + tmp = generate_snapname (volname, name, is_cg); + if (!tmp) { + gf_log (this->name, + GF_LOG_ERROR, "strdup " + "failed (%s)", name); + goto out; + } + + list_for_each_entry (snap, &volinfo->snaps, snap_list) { + if (!strcmp (snap->snap_name, tmp)) { + snprintf (err_str, sizeof (err_str), "snap " + "with name %s already exists", tmp); + gf_log (this->name, GF_LOG_ERROR, "%s", + err_str); + ret = -1; + *op_errstr = gf_strdup (err_str); + goto out; + } + } memset (snapvolidname, '\0', sizeof(snapvolidname)); ret = snprintf (snapvolidname, sizeof(snapvolidname) - 1, @@ -3615,6 +4225,16 @@ glusterd_snapshot (dict_t *dict, char **op_errstr, dict_t *rsp_dict) rsp_dict); break; + case GF_SNAP_OPTION_TYPE_DELETE: + ret = glusterd_snapshot_remove_commit (dict, op_errstr, + rsp_dict); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Failed to " + "delete snapshot"); + goto out; + } + break; + case GF_SNAP_OPTION_TYPE_RESTORE: ret = glusterd_snapshot_restore (dict, op_errstr); if (ret) { @@ -3700,6 +4320,74 @@ out: return ret; } +int +glusterd_snapshot_prevalidate (dict_t *dict, char **op_errstr, + dict_t *rsp_dict) +{ + int snap_command = 0; + xlator_t *this = NULL; + int ret = -1; + + this = THIS; + + GF_ASSERT (this); + GF_ASSERT (dict); + GF_ASSERT (rsp_dict); //not sure if this is needed, verify. + + ret = dict_get_int32 (dict, "type", &snap_command); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "unable to get the type of " + "the snapshot command"); + goto out; + } + + switch (snap_command) { + case (GF_SNAP_OPTION_TYPE_CREATE): + ret = glusterd_snapshot_create_prevalidate (dict, op_errstr, + rsp_dict); + if (ret) { + gf_log (this->name, GF_LOG_WARNING, "Snapshot create " + "pre-validation failed"); + goto out; + } + break; + + case (GF_SNAP_OPTION_TYPE_CONFIG): + ret = glusterd_snapshot_config_prevalidate (dict, op_errstr); + if (ret) { + gf_log (this->name, GF_LOG_WARNING, "Snapshot config " + "pre-validation failed"); + goto out; + } + break; + + case GF_SNAP_OPTION_TYPE_RESTORE: + ret = glusterd_snapshot_restore_prevalidate (dict, op_errstr); + if (ret) { + gf_log (this->name, GF_LOG_WARNING, "Snapshot restore " + "validation failed"); + goto out; + } + break; + case GF_SNAP_OPTION_TYPE_DELETE: + ret = glusterd_snapshot_remove_prevalidate (dict, op_errstr, + rsp_dict); + if (ret) { + gf_log (this->name, GF_LOG_WARNING, "Snapshot remove " + "validation failed"); + goto out; + } + break; + default: + gf_log (this->name, GF_LOG_WARNING, "invalid snap command"); + goto out; + } + + ret = 0; +out: + return ret; +} + int glusterd_handle_snapshot_fn (rpcsvc_request_t *req) { @@ -3797,6 +4485,14 @@ glusterd_handle_snapshot_fn (rpcsvc_request_t *req) ret = glusterd_mgmt_v3_initiate_all_phases (req, cli_op, dict); break; case GF_SNAP_OPTION_TYPE_DELETE: + ret = glusterd_handle_snapshot_remove (req, cli_op, dict, + err_str, + sizeof (err_str)); + if (ret) { + gf_log (this->name, GF_LOG_WARNING, "Snapshot delete " + "failed: %s", err_str); + } + break; case GF_SNAP_OPTION_TYPE_START: case GF_SNAP_OPTION_TYPE_STOP: case GF_SNAP_OPTION_TYPE_STATUS: diff --git a/xlators/mgmt/glusterd/src/glusterd-utils.c b/xlators/mgmt/glusterd/src/glusterd-utils.c index 9492baf3a..e9df28b8f 100644 --- a/xlators/mgmt/glusterd/src/glusterd-utils.c +++ b/xlators/mgmt/glusterd/src/glusterd-utils.c @@ -1687,6 +1687,52 @@ glusterd_brick_unlink_socket_file (glusterd_volinfo_t *volinfo, return ret; } +int32_t +glusterd_snap_brick_unlink_socket_file (glusterd_volinfo_t *volinfo, + glusterd_volinfo_t *snap_volinfo, + glusterd_brickinfo_t *brickinfo) +{ + char path[PATH_MAX] = {0,}; + char socketpath[PATH_MAX] = {0}; + xlator_t *this = NULL; + glusterd_conf_t *priv = NULL; + int ret = 0; + char sock_filepath[PATH_MAX] = {0, }; + int expected_file_len = 0; + char export_path[PATH_MAX] = {0,}; + + GF_ASSERT (volinfo); + GF_ASSERT (snap_volinfo); + GF_ASSERT (brickinfo); + + this = THIS; + GF_ASSERT (this); + priv = this->private; + GF_ASSERT (priv); + + GLUSTERD_GET_SNAP_DIR (path, volinfo, snap_volinfo->volname, priv); + + glusterd_set_socket_filepath (sock_filepath, socketpath, sizeof (socketpath)); + + expected_file_len = strlen (GLUSTERD_SOCK_DIR) + strlen ("/") + + MD5_DIGEST_LENGTH*2 + strlen (".socket") + 1; + GF_ASSERT (sizeof (socketpath) >= expected_file_len); + + GLUSTERD_REMOVE_SLASH_FROM_PATH (brickinfo->path, export_path); + snprintf (sock_filepath, PATH_MAX, "%s/run/%s-%s", + path, brickinfo->hostname, export_path); + + ret = unlink (socketpath); + if (ret && (ENOENT == errno)) { + ret = 0; + } else { + gf_log (this->name, GF_LOG_ERROR, "Failed to remove %s" + " error: %s", socketpath, strerror (errno)); + } + + return ret; +} + int32_t glusterd_brick_disconnect (glusterd_brickinfo_t *brickinfo) { @@ -1748,6 +1794,49 @@ glusterd_volume_stop_glusterfs (glusterd_volinfo_t *volinfo, return ret; } +int32_t +glusterd_snap_volume_stop_glusterfs (glusterd_volinfo_t *volinfo, + glusterd_volinfo_t *snap_volinfo, + glusterd_brickinfo_t *brickinfo, + gf_boolean_t del_brick) +{ + xlator_t *this = NULL; + glusterd_conf_t *priv = NULL; + char pidfile[PATH_MAX] = {0,}; + int ret = 0; + + GF_ASSERT (volinfo); + GF_ASSERT (brickinfo); + GF_ASSERT (snap_volinfo); + + this = THIS; + GF_ASSERT (this); + priv = this->private; + GF_ASSERT (priv); + + if (del_brick) + list_del_init (&brickinfo->brick_list); + + if (GLUSTERD_STATUS_STARTED == volinfo->status) { + (void) glusterd_brick_disconnect (brickinfo); + GLUSTERD_GET_SNAP_BRICK_PIDFILE (pidfile, volinfo, + snap_volinfo->volname, + brickinfo, priv); + ret = glusterd_service_stop ("brick", pidfile, SIGTERM, _gf_false); + if (ret == 0) { + glusterd_set_brick_status (brickinfo, GF_BRICK_STOPPED); + (void) glusterd_snap_brick_unlink_socket_file (volinfo, + snap_volinfo, + brickinfo); + } + } + + if (del_brick) + glusterd_delete_snap_brick (volinfo, snap_volinfo, brickinfo); + + return ret; +} + int32_t glusterd_peer_hostname_new (char *hostname, glusterd_peer_hostname_t **name) { @@ -5357,6 +5446,60 @@ out: return ret; } +int +glusterd_snap_brick_stop (glusterd_volinfo_t *volinfo, + glusterd_volinfo_t *snap_volinfo, + glusterd_brickinfo_t *brickinfo, + gf_boolean_t del_brick) +{ + int ret = -1; + xlator_t *this = NULL; + glusterd_conf_t *conf = NULL; + + this = THIS; + GF_ASSERT (this); + conf = this->private; + GF_ASSERT (conf); + + if ((!brickinfo) || (!volinfo) || !snap_volinfo) { + gf_log (this->name, GF_LOG_ERROR, "input parameters NULL"); + goto out; + } + + if (uuid_is_null (brickinfo->uuid)) { + ret = glusterd_resolve_brick (brickinfo); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, FMTSTR_RESOLVE_BRICK, + brickinfo->hostname, brickinfo->path); + goto out; + } + } + + if (uuid_compare (brickinfo->uuid, MY_UUID)) { + ret = 0; + if (del_brick) + glusterd_delete_snap_brick (volinfo, snap_volinfo, + brickinfo); + goto out; + } + + gf_log (this->name, GF_LOG_DEBUG, "About to stop glusterfs" + " for brick %s:%s", brickinfo->hostname, + brickinfo->path); + ret = glusterd_snap_volume_stop_glusterfs (volinfo, snap_volinfo, + brickinfo, del_brick); + if (ret) { + gf_log (this->name, GF_LOG_CRITICAL, "Unable to stop" + " brick: %s:%s", brickinfo->hostname, + brickinfo->path); + goto out; + } + +out: + gf_log (this->name, GF_LOG_TRACE, "returning %d ", ret); + return ret; +} + int glusterd_is_defrag_on (glusterd_volinfo_t *volinfo) { @@ -6005,6 +6148,49 @@ glusterd_delete_brick (glusterd_volinfo_t* volinfo, return ret; } +int32_t +glusterd_delete_snap_brick (glusterd_volinfo_t *volinfo, + glusterd_volinfo_t *snap_volinfo, + glusterd_brickinfo_t *brickinfo) +{ + int ret = 0; + char voldir[PATH_MAX] = {0,}; + xlator_t *this = NULL; + glusterd_conf_t *priv = NULL; + + this = THIS; + GF_ASSERT (this); + priv = this->private; + GF_ASSERT (priv); + + GF_ASSERT (volinfo); + GF_ASSERT (snap_volinfo); + GF_ASSERT (brickinfo); + + GLUSTERD_GET_SNAP_DIR(voldir, volinfo, snap_volinfo->volname, priv); + + ret = glusterd_delete_snap_volfile (volinfo, snap_volinfo, brickinfo); + if (ret) + gf_log (this->name, GF_LOG_WARNING, "failed to delete the " + "volfile for the brick (%s:%s), snap: %s volume: %s", + brickinfo->hostname, brickinfo->path, + snap_volinfo->volname, volinfo->volname); + ret = glusterd_store_delete_brick (brickinfo, voldir); + if (ret) + gf_log (this->name, GF_LOG_WARNING, "failed to delete the " + "store handle of brick (%s:%s), snap: %s volume: %s", + brickinfo->hostname, brickinfo->path, + snap_volinfo->volname, volinfo->volname); + ret = glusterd_brickinfo_delete (brickinfo); + if (ret) + gf_log (this->name, GF_LOG_WARNING, "failed to delete the " + "brickinfo (%s:%s), snap: %s volume: %s", + brickinfo->hostname, brickinfo->path, + snap_volinfo->volname, volinfo->volname); + snap_volinfo->brick_count--; + return ret; +} + int32_t glusterd_delete_all_bricks (glusterd_volinfo_t* volinfo) { diff --git a/xlators/mgmt/glusterd/src/glusterd-utils.h b/xlators/mgmt/glusterd/src/glusterd-utils.h index ca3c620aa..4c98559c9 100644 --- a/xlators/mgmt/glusterd/src/glusterd-utils.h +++ b/xlators/mgmt/glusterd/src/glusterd-utils.h @@ -292,6 +292,11 @@ glusterd_snap_brick_start (glusterd_volinfo_t *volinfo, glusterd_brickinfo_t *brickinfo, gf_boolean_t wait); int +glusterd_snap_brick_stop (glusterd_volinfo_t *volinfo, + glusterd_volinfo_t *snap_volinfo, + glusterd_brickinfo_t *brickinfo, + gf_boolean_t del_brick); +int glusterd_is_defrag_on (glusterd_volinfo_t *volinfo); int32_t @@ -374,6 +379,10 @@ int32_t glusterd_delete_brick (glusterd_volinfo_t* volinfo, glusterd_brickinfo_t *brickinfo); int32_t +glusterd_delete_snap_brick (glusterd_volinfo_t *volinfo, + glusterd_volinfo_t *snap_volinfo, + glusterd_brickinfo_t *brickinfo); +int32_t glusterd_delete_all_bricks (glusterd_volinfo_t* volinfo); int glusterd_spawn_daemons (void *opaque); diff --git a/xlators/mgmt/glusterd/src/glusterd-volgen.c b/xlators/mgmt/glusterd/src/glusterd-volgen.c index 50beb23f7..1bc0db6ce 100644 --- a/xlators/mgmt/glusterd/src/glusterd-volgen.c +++ b/xlators/mgmt/glusterd/src/glusterd-volgen.c @@ -3703,6 +3703,39 @@ glusterd_delete_volfile (glusterd_volinfo_t *volinfo, return ret; } +int +glusterd_delete_snap_volfile (glusterd_volinfo_t *volinfo, + glusterd_volinfo_t *snap_volinfo, + glusterd_brickinfo_t *brickinfo) +{ + int ret = 0; + char filename[PATH_MAX] = {0,}; + char brick[PATH_MAX] = {0, }; + char path[PATH_MAX] = {0, }; + glusterd_conf_t *priv = NULL; + + GF_ASSERT (volinfo); + GF_ASSERT (brickinfo); + GF_ASSERT (snap_volinfo); + + priv = THIS->private; + GF_ASSERT (priv); + + GLUSTERD_REMOVE_SLASH_FROM_PATH (brickinfo->path, brick); + GLUSTERD_GET_SNAP_DIR (path, volinfo, snap_volinfo->volname, priv); + + snprintf (filename, PATH_MAX, "%s/%s.%s.%s.vol", + path, snap_volinfo->volname, + brickinfo->hostname, + brick); + + ret = unlink (filename); + if (ret) + gf_log ("glusterd", GF_LOG_ERROR, "failed to delete file: %s, " + "reason: %s", filename, strerror (errno)); + return ret; +} + int validate_shdopts (glusterd_volinfo_t *volinfo, dict_t *val_dict, diff --git a/xlators/mgmt/glusterd/src/glusterd-volgen.h b/xlators/mgmt/glusterd/src/glusterd-volgen.h index dc334ca8d..2b22f5226 100644 --- a/xlators/mgmt/glusterd/src/glusterd-volgen.h +++ b/xlators/mgmt/glusterd/src/glusterd-volgen.h @@ -124,6 +124,10 @@ int glusterd_create_shd_volfile (); int glusterd_delete_volfile (glusterd_volinfo_t *volinfo, glusterd_brickinfo_t *brickinfo); +int +glusterd_delete_snap_volfile (glusterd_volinfo_t *volinfo, + glusterd_volinfo_t *snap_volinfo, + glusterd_brickinfo_t *brickinfo); int glusterd_volinfo_get (glusterd_volinfo_t *volinfo, char *key, char **value); int glusterd_volinfo_get_boolean (glusterd_volinfo_t *volinfo, char *key); -- cgit