/*
Copyright (c) 2006-2009 Gluster, Inc. <http://www.gluster.com>
This file is part of GlusterFS.
GlusterFS is GF_FREE software; you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
GlusterFS is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see
<http://www.gnu.org/licenses/>.
*/
#ifndef _CONFIG_H
#define _CONFIG_H
#include "config.h"
#endif
#include <time.h>
#include <sys/uio.h>
#include <sys/resource.h>
#include <libgen.h>
#include "uuid.h"
#include "fnmatch.h"
#include "xlator.h"
#include "protocol-common.h"
#include "glusterd.h"
#include "call-stub.h"
#include "defaults.h"
#include "list.h"
#include "dict.h"
#include "compat.h"
#include "compat-errno.h"
#include "statedump.h"
#include "glusterd-sm.h"
#include "glusterd-op-sm.h"
#include "glusterd-utils.h"
#include "glusterd-store.h"
#include "cli1.h"
#include "glusterd-volgen.h"
#include <sys/types.h>
#include <signal.h>
static struct list_head gd_op_sm_queue;
glusterd_op_info_t opinfo = {{0},};
static int glusterfs_port = GLUSTERD_DEFAULT_PORT;
static void
glusterd_set_volume_status (glusterd_volinfo_t *volinfo,
glusterd_volume_status status)
{
GF_ASSERT (volinfo);
volinfo->status = status;
}
static int
glusterd_is_volume_started (glusterd_volinfo_t *volinfo)
{
GF_ASSERT (volinfo);
return (!(volinfo->status == GLUSTERD_STATUS_STARTED));
}
static int
glusterd_op_get_len (glusterd_op_t op)
{
GF_ASSERT (op < GD_OP_MAX);
GF_ASSERT (op > GD_OP_NONE);
int ret = -1;
switch (op) {
case GD_OP_CREATE_VOLUME:
{
dict_t *dict = glusterd_op_get_ctx (op);
ret = dict_serialized_length (dict);
return ret;
}
break;
case GD_OP_START_BRICK:
break;
case GD_OP_REPLACE_BRICK:
case GD_OP_ADD_BRICK:
{
dict_t *dict = glusterd_op_get_ctx (op);
ret = dict_serialized_length (dict);
return ret;
}
case GD_OP_REMOVE_BRICK:
{
dict_t *dict = glusterd_op_get_ctx (op);
ret = dict_serialized_length (dict);
return ret;
}
break;
break;
default:
GF_ASSERT (op);
}
return 0;
}
static int
glusterd_op_sm_inject_all_acc ()
{
int32_t ret = -1;
ret = glusterd_op_sm_inject_event (GD_OP_EVENT_ALL_ACC, NULL);
gf_log ("", GF_LOG_DEBUG, "Returning %d", ret);
return ret;
}
int
glusterd_op_build_payload (glusterd_op_t op, gd1_mgmt_stage_op_req **req)
{
int len = 0;
int ret = -1;
gd1_mgmt_stage_op_req *stage_req = NULL;
GF_ASSERT (op < GD_OP_MAX);
GF_ASSERT (op > GD_OP_NONE);
GF_ASSERT (req);
len = glusterd_op_get_len (op);
stage_req = GF_CALLOC (1, sizeof (*stage_req),
gf_gld_mt_mop_stage_req_t);
if (!stage_req) {
gf_log ("", GF_LOG_ERROR, "Out of Memory");
goto out;
}
glusterd_get_uuid (&stage_req->uuid);
stage_req->op = op;
//stage_req->buf.buf_len = len;
switch (op) {
case GD_OP_CREATE_VOLUME:
{
dict_t *dict = NULL;
dict = glusterd_op_get_ctx (op);
GF_ASSERT (dict);
++glusterfs_port;
ret = dict_set_int32 (dict, "port", glusterfs_port);
ret = dict_allocate_and_serialize (dict,
&stage_req->buf.buf_val,
(size_t *)&stage_req->buf.buf_len);
if (ret) {
goto out;
}
}
break;
case GD_OP_START_VOLUME:
{
glusterd_op_start_volume_ctx_t *ctx = NULL;
ctx = glusterd_op_get_ctx (op);
GF_ASSERT (ctx);
stage_req->buf.buf_len =
strlen (ctx->volume_name);
stage_req->buf.buf_val =
gf_strdup (ctx->volume_name);
}
break;
case GD_OP_STOP_VOLUME:
{
dict_t *dict = NULL;
dict = glusterd_op_get_ctx (op);
if (!dict) {
gf_log ("", GF_LOG_ERROR, "Null Context for "
"stop volume");
ret = -1;
goto out;
}
ret = dict_allocate_and_serialize (dict,
&stage_req->buf.buf_val,
(size_t *)&stage_req->buf.buf_len);
if (ret) {
goto out;
}
}
break;
case GD_OP_DELETE_VOLUME:
{
glusterd_op_delete_volume_ctx_t *ctx = NULL;
ctx = glusterd_op_get_ctx (op);
GF_ASSERT (ctx);
stage_req->buf.buf_len =
strlen (ctx->volume_name);
stage_req->buf.buf_val =
gf_strdup (ctx->volume_name);
}
break;
case GD_OP_ADD_BRICK:
{
dict_t *dict = NULL;
dict = glusterd_op_get_ctx (op);
GF_ASSERT (dict);
ret = dict_allocate_and_serialize (dict,
&stage_req->buf.buf_val,
(size_t *)&stage_req->buf.buf_len);
if (ret) {
goto out;
}
}
break;
case GD_OP_REPLACE_BRICK:
{
dict_t *dict = NULL;
dict = glusterd_op_get_ctx (op);
GF_ASSERT (dict);
ret = dict_allocate_and_serialize (dict,
&stage_req->buf.buf_val,
(size_t *)&stage_req->buf.buf_len);
if (ret) {
goto out;
}
}
break;
case GD_OP_REMOVE_BRICK:
{
dict_t *dict = NULL;
dict = glusterd_op_get_ctx (op);
GF_ASSERT (dict);
ret = dict_allocate_and_serialize (dict,
&stage_req->buf.buf_val,
(size_t *)&stage_req->buf.buf_len);
if (ret) {
goto out;
}
}
break;
default:
break;
}
*req = stage_req;
ret = 0;
out:
return ret;
}
static int
glusterd_op_stage_create_volume (gd1_mgmt_stage_op_req *req)
{
int ret = 0;
dict_t *dict = NULL;
char *volname = NULL;
gf_boolean_t exists = _gf_false;
char *bricks = NULL;
char *brick_list = NULL;
glusterd_brickinfo_t *brick_info = NULL;
int32_t brick_count = 0;
int32_t i = 0;
struct stat st_buf = {0,};
char *brick = NULL;
char *tmpptr = NULL;
char cmd_str[1024];
GF_ASSERT (req);
dict = dict_new ();
if (!dict)
goto out;
ret = dict_unserialize (req->buf.buf_val, req->buf.buf_len, &dict);
if (ret) {
gf_log ("", GF_LOG_ERROR, "Unable to unserialize dict");
goto out;
}
ret = dict_get_str (dict, "volname", &volname);
if (ret) {
gf_log ("", GF_LOG_ERROR, "Unable to get volume name");
goto out;
}
exists = glusterd_check_volume_exists (volname);
if (exists) {
gf_log ("", GF_LOG_ERROR, "Volume with name: %s exists",
volname);
ret = -1;
} else {
ret = 0;
}
ret = dict_get_int32 (dict, "count", &brick_count);
if (ret) {
gf_log ("", GF_LOG_ERROR, "Unable to get count");
goto out;
}
ret = dict_get_str (dict, "bricks", &bricks);
if (ret) {
gf_log ("", GF_LOG_ERROR, "Unable to get bricks");
goto out;
}
if (bricks)
brick_list = gf_strdup (bricks);
while ( i < brick_count) {
i++;
brick= strtok_r (brick_list, " \n", &tmpptr);
brick_list = tmpptr;
ret = glusterd_brickinfo_from_brick (brick, &brick_info);
if (ret)
goto out;
snprintf (cmd_str, 1024, "%s", brick_info->path);
ret = stat (cmd_str, &st_buf);
if (ret == -1) {
gf_log ("glusterd", GF_LOG_ERROR, "Volname %s, brick"
":%s path %s not present", volname,
brick, brick_info->path);
goto out;
}
brick_list = tmpptr;
}
out:
gf_log ("", GF_LOG_DEBUG, "Returning %d", ret);
return ret;
}
static int
glusterd_op_stage_start_volume (gd1_mgmt_stage_op_req *req)
{
int ret = 0;
char volname [1024] = {0,};
gf_boolean_t exists = _gf_false;
glusterd_volinfo_t *volinfo = NULL;
glusterd_brickinfo_t *brickinfo = NULL;
GF_ASSERT (req);
strncpy (volname, req->buf.buf_val, req->buf.buf_len);
//volname = req->buf.buf_val;
exists = glusterd_check_volume_exists (volname);
if (!exists) {
gf_log ("", GF_LOG_ERROR, "Volume with name %s does not exist",
volname);
ret = -1;
} else {
ret = 0;
}
ret = glusterd_volinfo_find (volname, &volinfo);
if (ret)
goto out;
list_for_each_entry (brickinfo, &volinfo->bricks, brick_list) {
ret = glusterd_resolve_brick (brickinfo);
if (ret) {
gf_log ("", GF_LOG_ERROR, "Unable to resolve brick"
" with hostname: %s, export: %s",
brickinfo->hostname,brickinfo->path);
goto out;
}
}
out:
gf_log ("", GF_LOG_DEBUG, "Returning %d", ret);
return ret;
}
static int
glusterd_op_stop_volume_args_get (gd1_mgmt_stage_op_req *req,
dict_t *dict, char** volname,
int *flags)
{
int ret = -1;
if (!req || !dict || !volname || !flags)
goto out;
ret = dict_unserialize (req->buf.buf_val, req->buf.buf_len, &dict);
if (ret) {
gf_log ("", GF_LOG_ERROR, "Unable to unserialize dict");
goto out;
}
ret = dict_get_str (dict, "volname", volname);
if (ret) {
gf_log ("", GF_LOG_ERROR, "Unable to get volume name");
goto out;
}
ret = dict_get_int32 (dict, "flags", flags);
if (ret) {
gf_log ("", GF_LOG_ERROR, "Unable to get flags");
goto out;
}
out:
return ret;
}
static int
glusterd_op_stage_stop_volume (gd1_mgmt_stage_op_req *req)
{
int ret = -1;
dict_t *dict = NULL;
char *volname = NULL;
int flags = 0;
gf_boolean_t exists = _gf_false;
glusterd_volinfo_t *volinfo = NULL;
dict = dict_new ();
if (!dict)
goto out;
ret = glusterd_op_stop_volume_args_get (req, dict, &volname, &flags);
if (ret)
goto out;
exists = glusterd_check_volume_exists (volname);
if (!exists) {
gf_log ("", GF_LOG_ERROR, "Volume with name %s does not exist",
volname);
ret = -1;
} else {
ret = 0;
}
ret = glusterd_volinfo_find (volname, &volinfo);
if (ret)
goto out;
if (!(flags & GF_CLI_FLAG_OP_FORCE)) {
ret = glusterd_is_volume_started (volinfo);
if (ret) {
gf_log ("", GF_LOG_ERROR, "Volume %s "
"has not been started", volname);
goto out;
}
}
out:
if (dict)
dict_unref (dict);
gf_log ("", GF_LOG_DEBUG, "Returning %d", ret);
return ret;
}
static int
glusterd_op_stage_delete_volume (gd1_mgmt_stage_op_req *req)
{
int ret = 0;
char volname [1024] = {0,};
gf_boolean_t exists = _gf_false;
glusterd_volinfo_t *volinfo = NULL;
GF_ASSERT (req);
strncpy (volname, req->buf.buf_val, req->buf.buf_len);
exists = glusterd_check_volume_exists (volname);
if (!exists) {
gf_log ("", GF_LOG_ERROR, "Volume with name %s does not exist",
volname);
ret = -1;
goto out;
} else {
ret = 0;
}
ret = glusterd_volinfo_find (volname, &volinfo);
if (ret)
goto out;
ret = glusterd_is_volume_started (volinfo);
if (!ret) {
gf_log ("", GF_LOG_ERROR, "Volume %s has been started."
"Volume needs to be stopped before deletion.",
volname);
ret = -1;
goto out;
}
ret = 0;
out:
gf_log ("", GF_LOG_DEBUG, "Returning %d", ret);
return ret;
}
static int
glusterd_op_stage_add_brick (gd1_mgmt_stage_op_req *req)
{
int ret = 0;
dict_t *dict = NULL;
char *volname = NULL;
int count = 0;
int i = 0;
char *bricks = NULL;
|