diff options
author | Krishnan Parthasarathi <kp@gluster.com> | 2012-03-26 16:11:29 +0530 |
---|---|---|
committer | Vijay Bellur <vijay@gluster.com> | 2012-03-31 05:15:08 -0700 |
commit | 66d430da4e3788aeb41eea46455ca25a2d19a626 (patch) | |
tree | b52c1189401cc47c7cfecc7e5225938b926b6a4d | |
parent | 3f81c44a03e9ab78be2b4a69e3e36d41a4de324a (diff) |
glusterd: Added init scripts like interface for gluster commands
Directories to hold the scripts mentioned above would be created for each
gluster command under glusterd's 'working dir' as follows:
(eg.)
<glusterd-working-dir>/hooks/version/create/pre
<glusterd-working-dir>/hooks/version/create/post
where, version corresponds to the version of hook scripts.
The scripts beginning with 'S' under the above directories would be run before
(pre) and after (post) the volume created. The scripts would receive a command
line argument as below:
--volname=<volname>
This can be optionally used by the script.
Change-Id: Ia81b4ff9dd4477d99dd59b39c805aa645521edb0
BUG: 806996
Signed-off-by: Krishnan Parthasarathi <kp@gluster.com>
Reviewed-on: http://review.gluster.com/3010
Tested-by: Gluster Build System <jenkins@build.gluster.com>
Reviewed-by: Csaba Henk <csaba@redhat.com>
Reviewed-by: Vijay Bellur <vijay@gluster.com>
-rw-r--r-- | xlators/mgmt/glusterd/src/glusterd-op-sm.c | 44 | ||||
-rw-r--r-- | xlators/mgmt/glusterd/src/glusterd-store.c | 211 | ||||
-rw-r--r-- | xlators/mgmt/glusterd/src/glusterd-store.h | 23 | ||||
-rw-r--r-- | xlators/mgmt/glusterd/src/glusterd-utils.h | 3 | ||||
-rw-r--r-- | xlators/mgmt/glusterd/src/glusterd.c | 10 |
5 files changed, 287 insertions, 4 deletions
diff --git a/xlators/mgmt/glusterd/src/glusterd-op-sm.c b/xlators/mgmt/glusterd/src/glusterd-op-sm.c index 5788813235b..993ddddb2b4 100644 --- a/xlators/mgmt/glusterd/src/glusterd-op-sm.c +++ b/xlators/mgmt/glusterd/src/glusterd-op-sm.c @@ -2127,6 +2127,32 @@ out: } static int +glusterd_op_commit_hook (glusterd_op_t op, dict_t *op_ctx, glusterd_commit_hook_type_t type) +{ + glusterd_conf_t *priv = NULL; + char hookdir[PATH_MAX] = {0, }; + char scriptdir[PATH_MAX] = {0, }; + char type_subdir[256] = {0, }; + char *cmd_subdir = NULL; + + priv = THIS->private; + if (type == GD_COMMIT_HOOK_PRE) + strcpy (type_subdir, "pre"); + else if (type == GD_COMMIT_HOOK_POST) + strcpy (type_subdir, "post"); + + cmd_subdir = glusterd_store_get_hooks_cmd_subdir (op); + if (strlen (cmd_subdir) == 0) + return -1; + + GLUSTERD_GET_HOOKS_DIR (hookdir, GLUSTERD_HOOK_VER, priv); + snprintf (scriptdir, sizeof (scriptdir), "%s/%s/%s", + hookdir, cmd_subdir, type_subdir); + + return glusterd_store_run_hooks (scriptdir, op_ctx); +} + +static int glusterd_op_ac_send_commit_op (glusterd_op_sm_event_t *event, void *ctx) { int ret = 0; @@ -2145,12 +2171,15 @@ glusterd_op_ac_send_commit_op (glusterd_op_sm_event_t *event, void *ctx) priv = this->private; GF_ASSERT (priv); - op = glusterd_op_get_op (); + op = glusterd_op_get_op (); + op_dict = glusterd_op_get_ctx (); + ret = glusterd_op_build_payload (&dict); if (ret) goto out; + glusterd_op_commit_hook (op, op_dict, GD_COMMIT_HOOK_PRE); ret = glusterd_op_commit_perform (op, dict, &op_errstr, NULL); //rsp_dict invalid for source if (ret) { gf_log (THIS->name, GF_LOG_ERROR, "Commit failed"); @@ -2158,6 +2187,8 @@ glusterd_op_ac_send_commit_op (glusterd_op_sm_event_t *event, void *ctx) goto out; } + glusterd_op_commit_hook (op, op_dict, GD_COMMIT_HOOK_POST); + list_for_each_entry (peerinfo, &priv->peers, uuid_list) { GF_ASSERT (peerinfo); @@ -2196,7 +2227,6 @@ out: if (!opinfo.pending_count) { if (op == GD_OP_REPLACE_BRICK) { - op_dict = glusterd_op_get_ctx (); ret = glusterd_op_start_rb_timer (op_dict); } else { @@ -2579,11 +2609,11 @@ static int glusterd_op_ac_commit_op (glusterd_op_sm_event_t *event, void *ctx) { int ret = 0; - glusterd_req_ctx_t *req_ctx = NULL; + glusterd_req_ctx_t *req_ctx = NULL; int32_t status = 0; char *op_errstr = NULL; dict_t *dict = NULL; - dict_t *rsp_dict = NULL; + dict_t *rsp_dict = NULL; GF_ASSERT (ctx); @@ -2595,6 +2625,8 @@ glusterd_op_ac_commit_op (glusterd_op_sm_event_t *event, void *ctx) if (NULL == rsp_dict) return -1; + glusterd_op_commit_hook (req_ctx->op, dict, GD_COMMIT_HOOK_PRE); + if (GD_OP_CLEARLOCKS_VOLUME == req_ctx->op) { /*clear locks should be run only on * originator glusterd*/ @@ -2607,6 +2639,10 @@ glusterd_op_ac_commit_op (glusterd_op_sm_event_t *event, void *ctx) if (status) { gf_log (THIS->name, GF_LOG_ERROR, "Commit failed: %d", status); + } else { + /* On successful commit */ + glusterd_op_commit_hook (req_ctx->op, dict, + GD_COMMIT_HOOK_POST); } ret = glusterd_op_commit_send_resp (req_ctx->req, req_ctx->op, diff --git a/xlators/mgmt/glusterd/src/glusterd-store.c b/xlators/mgmt/glusterd/src/glusterd-store.c index 56c1d98754a..4cfbf5e4c3d 100644 --- a/xlators/mgmt/glusterd/src/glusterd-store.c +++ b/xlators/mgmt/glusterd/src/glusterd-store.c @@ -51,6 +51,39 @@ #include <inttypes.h> #include <dirent.h> +extern int mkdir_if_missing (char *dir); + +#define EMPTY "" +char glusterd_hook_dirnames[GD_OP_MAX][256] = +{ + [GD_OP_NONE] = EMPTY, + [GD_OP_CREATE_VOLUME] = "create", + [GD_OP_START_BRICK] = EMPTY, + [GD_OP_STOP_BRICK] = EMPTY, + [GD_OP_DELETE_VOLUME] = "delete", + [GD_OP_START_VOLUME] = "start", + [GD_OP_STOP_VOLUME] = "stop", + [GD_OP_DEFRAG_VOLUME] = EMPTY, + [GD_OP_ADD_BRICK] = "add-brick", + [GD_OP_REMOVE_BRICK] = "remove-brick", + [GD_OP_REPLACE_BRICK] = EMPTY, + [GD_OP_SET_VOLUME] = EMPTY, + [GD_OP_RESET_VOLUME] = EMPTY, + [GD_OP_SYNC_VOLUME] = EMPTY, + [GD_OP_LOG_ROTATE] = EMPTY, + [GD_OP_GSYNC_SET] = EMPTY, + [GD_OP_PROFILE_VOLUME] = EMPTY, + [GD_OP_QUOTA] = EMPTY, + [GD_OP_STATUS_VOLUME] = EMPTY, + [GD_OP_REBALANCE] = EMPTY, + [GD_OP_HEAL_VOLUME] = EMPTY, + [GD_OP_STATEDUMP_VOLUME] = EMPTY, + [GD_OP_LIST_VOLUME] = EMPTY, + [GD_OP_CLEARLOCKS_VOLUME] = EMPTY, + [GD_OP_DEFRAG_BRICK_VOLUME] = EMPTY, +}; +#undef EMPTY + static int32_t glusterd_store_mkdir (char *path) { @@ -2464,3 +2497,181 @@ out: gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); return ret; } + +static inline gf_boolean_t +glusterd_is_hook_enabled (char *script) +{ + return (script[0] == 'S'); +} + +int +glusterd_store_create_hooks_directory (char *basedir) +{ + int ret = -1; + int op = GD_OP_NONE; + int type = GD_COMMIT_HOOK_NONE; + char version_dir[PATH_MAX] = {0, }; + char path[PATH_MAX] = {0, }; + char *cmd_subdir = NULL; + char type_subdir[GD_COMMIT_HOOK_MAX][256] = {{0, }, + "pre", + "post"}; + glusterd_conf_t *priv = NULL; + + priv = THIS->private; + + snprintf (path, sizeof (path), "%s/hooks", basedir); + ret = mkdir_if_missing (path); + if (ret) { + gf_log (THIS->name, GF_LOG_CRITICAL, "Unable to create %s due" + "to %s", path, strerror (errno)); + goto out; + } + + GLUSTERD_GET_HOOKS_DIR (version_dir, GLUSTERD_HOOK_VER, priv); + ret = mkdir_if_missing (version_dir); + if (ret) { + gf_log (THIS->name, GF_LOG_CRITICAL, "Unable to create %s due " + "to %s", version_dir, strerror (errno)); + goto out; + } + + for (op = GD_OP_NONE+1; op < GD_OP_MAX; op++) { + cmd_subdir = glusterd_store_get_hooks_cmd_subdir (op); + if (strlen (cmd_subdir) == 0) + continue; + + snprintf (path, sizeof (path), "%s/%s", version_dir, + cmd_subdir); + ret = mkdir_if_missing (path); + if (ret) { + gf_log (THIS->name, GF_LOG_CRITICAL, + "Unable to create %s due to %s", + path, strerror (errno)); + goto out; + } + + for (type = GD_COMMIT_HOOK_PRE; type < GD_COMMIT_HOOK_MAX; + type++) { + snprintf (path, sizeof (path), "%s/%s/%s", + version_dir, cmd_subdir, type_subdir[type]); + ret = mkdir_if_missing (path); + if (ret) { + gf_log (THIS->name, GF_LOG_CRITICAL, + "Unable to create %s due to %s", + path, strerror (errno)); + goto out; + } + } + } + + ret = 0; +out: + return ret; +} + +char* +glusterd_store_get_hooks_cmd_subdir (glusterd_op_t op) +{ + GF_ASSERT ((op > GD_OP_NONE) && (op < GD_OP_MAX)); + + return glusterd_hook_dirnames[op]; +} + +int +glusterd_store_run_hooks (char *hooks_path, dict_t *op_ctx) +{ + xlator_t *this = NULL; + glusterd_conf_t *priv = NULL; + runner_t runner = {0, }; + struct dirent *entry = NULL; + DIR *hookdir = NULL; + char *volname = NULL; + char **lines = NULL; + int N = 8; /*arbitrary*/ + int lineno = 0; + int line_count = 0; + int ret = -1; + + this = THIS; + priv = this->private; + + ret = dict_get_str (op_ctx, "volname", &volname); + if (ret) { + gf_log (this->name, GF_LOG_CRITICAL, "Failed to get volname " + "from operation context"); + goto out; + } + + hookdir = opendir (hooks_path); + if (!hookdir) { + ret = -1; + gf_log (this->name, GF_LOG_ERROR, "Failed to open dir %s, due " + "to %s", hooks_path, strerror (errno)); + goto out; + } + + lines = GF_CALLOC (1, N * sizeof (*lines), gf_gld_mt_charptr); + if (!lines) { + ret = -1; + goto out; + } + + ret = -1; + line_count = 0; + glusterd_for_each_entry (entry, hookdir); + while (entry) { + if (line_count == N-1) { + N *= 2; + lines = GF_REALLOC (lines, N * sizeof (char *)); + if (!lines) + goto out; + } + + if (glusterd_is_hook_enabled (entry->d_name)) { + lines[line_count] = gf_strdup (entry->d_name); + line_count++; + } + + glusterd_for_each_entry (entry, hookdir); + } + + lines[line_count] = NULL; + lines = GF_REALLOC (lines, (line_count + 1) * sizeof (char *)); + if (!lines) + goto out; + + qsort (lines, line_count, sizeof (*lines), glusterd_compare_lines); + + for (lineno = 0; lineno < line_count; lineno++) { + + runinit (&runner); + runner_argprintf (&runner, "%s/%s", hooks_path, lines[lineno]); + /*Add future command line arguments to hook scripts below*/ + runner_argprintf (&runner, "--volname=%s", volname); + ret = runner_run_reuse (&runner); + if (ret) { + runner_log (&runner, this->name, GF_LOG_ERROR, + "Failed to execute script"); + } else { + runner_log (&runner, this->name, GF_LOG_INFO, + "Ran script"); + } + runner_end (&runner); + } + + ret = 0; +out: + if (lines) { + for (lineno = 0; lineno < line_count+1; lineno++) + if (lines[lineno]) + GF_FREE (lines[lineno]); + + GF_FREE (lines); + } + + if (hookdir) + closedir (hookdir); + + return ret; +} diff --git a/xlators/mgmt/glusterd/src/glusterd-store.h b/xlators/mgmt/glusterd/src/glusterd-store.h index b381e5a0cce..788949d55fc 100644 --- a/xlators/mgmt/glusterd/src/glusterd-store.h +++ b/xlators/mgmt/glusterd/src/glusterd-store.h @@ -30,6 +30,7 @@ #include "glusterfs.h" #include "xlator.h" +#include "run.h" #include "logging.h" #include "call-stub.h" #include "fd.h" @@ -73,6 +74,10 @@ typedef enum glusterd_store_ver_ac_{ #define GLUSTERD_STORE_KEY_PEER_HOSTNAME "hostname" #define GLUSTERD_STORE_KEY_PEER_STATE "state" +#define GLUSTERD_GET_HOOKS_DIR(path, version, priv) \ + snprintf (path, PATH_MAX, "%s/hooks/%d", priv->workdir,\ + version); + #define glusterd_for_each_entry(entry, dir) \ do {\ entry = NULL;\ @@ -85,6 +90,7 @@ typedef enum glusterd_store_ver_ac_{ }\ } while (0); \ + typedef enum { GD_STORE_SUCCESS, GD_STORE_KEY_NULL, @@ -95,6 +101,14 @@ typedef enum { GD_STORE_STAT_FAILED } glusterd_store_op_errno_t; +#define GLUSTERD_HOOK_VER 1 +typedef enum glusterd_commit_hook_type { + GD_COMMIT_HOOK_NONE = 0, + GD_COMMIT_HOOK_PRE, + GD_COMMIT_HOOK_POST, + GD_COMMIT_HOOK_MAX +} glusterd_commit_hook_type_t; + int32_t glusterd_store_volinfo (glusterd_volinfo_t *volinfo, glusterd_volinfo_ver_ac_t ac); @@ -138,4 +152,13 @@ glusterd_perform_volinfo_version_action (glusterd_volinfo_t *volinfo, glusterd_volinfo_ver_ac_t ac); gf_boolean_t glusterd_store_is_valid_brickpath (char *volname, char *brick); + +int +glusterd_store_create_hooks_directory (char *basedir); + +char * +glusterd_store_get_hooks_cmd_subdir (glusterd_op_t op); + +int +glusterd_store_run_hooks (char *hooks_path, dict_t *op_ctx); #endif diff --git a/xlators/mgmt/glusterd/src/glusterd-utils.h b/xlators/mgmt/glusterd/src/glusterd-utils.h index 7a784149e0a..6e02929f1ec 100644 --- a/xlators/mgmt/glusterd/src/glusterd-utils.h +++ b/xlators/mgmt/glusterd/src/glusterd-utils.h @@ -57,6 +57,9 @@ typedef struct glusterd_voldict_ctx_ { char *val_name; } glusterd_voldict_ctx_t; +int +glusterd_compare_lines (const void *a, const void *b); + typedef int (*glusterd_condition_func) (glusterd_volinfo_t *volinfo, glusterd_brickinfo_t *brickinfo, void *ctx); diff --git a/xlators/mgmt/glusterd/src/glusterd.c b/xlators/mgmt/glusterd/src/glusterd.c index e4f04002f09..b84c141df9a 100644 --- a/xlators/mgmt/glusterd/src/glusterd.c +++ b/xlators/mgmt/glusterd/src/glusterd.c @@ -795,6 +795,7 @@ init (xlator_t *this) " ,errno = %d", dirname, errno); exit (1); } + first_time = 1; } @@ -977,6 +978,15 @@ init (xlator_t *this) if (ret < 0) goto out; + if (first_time) { + ret = glusterd_store_create_hooks_directory (dirname); + if (-1 == ret) { + gf_log (this->name, GF_LOG_CRITICAL, + "Unable to create hooks directory "); + exit (1); + } + } + INIT_LIST_HEAD (&conf->mount_specs); dict_foreach (this->options, _install_mount_spec, &ret); if (ret) |