[Sheepdog] [PATCH] shepherd: refine command syntax
FUJITA Tomonori
fujita.tomonori at lab.ntt.co.jp
Sat May 8 18:09:43 CEST 2010
As discussed, this makes the command syntax saner.
=
From: FUJITA Tomonori <fujita.tomonori at lab.ntt.co.jp>
Subject: [PATCH] shepherd: refine command syntax
fujita at rose:~/git/sheepdog$ ./shepherd/shepherd --help
Usage: shepherd command subcommand [options]
Sheepdog Administrator Utilty
Command syntax:
cluster (info|format|shutdown)
node (info|list)
vdi (list|delete|object|lock|release)
vm list
Common parameters:
-p, --port specify the daemon port
-h, --help display this help and exit
Signed-off-by: FUJITA Tomonori <fujita.tomonori at lab.ntt.co.jp>
---
shepherd/shepherd.c | 1187 ++++++++++++++++++++++-----------------------------
1 files changed, 518 insertions(+), 669 deletions(-)
diff --git a/shepherd/shepherd.c b/shepherd/shepherd.c
index 85a77a6..a63788e 100644
--- a/shepherd/shepherd.c
+++ b/shepherd/shepherd.c
@@ -34,61 +34,30 @@
static char program_name[] = "shepherd";
static int sdport = SD_LISTEN_PORT;
+static int highlight = 1;
-static struct option const long_options[] =
-{
- {"port", required_argument, NULL, 'p'},
- {"copies", required_argument, NULL, 'c'},
- {"epoch", required_argument, NULL, 'e'},
- {"index", required_argument, NULL, 'i'},
- {"format", required_argument, NULL, 'f'},
- {"type", required_argument, NULL, 't'},
- {"highlight", required_argument, NULL, 'H'},
- {"resident", required_argument, NULL, 'R'},
- {"op", required_argument, NULL, 'o'},
- {"help", no_argument, NULL, 'h'},
- {NULL, 0, NULL, 0},
-};
+#define COMMON_LONG_OPTIONS \
+ {"port", required_argument, NULL, 'p'}, \
+ {"help", no_argument, NULL, 'h'}, \
-static char *short_options = "p:f:rR:t:H:o:i:e:h";
-
-enum info_type {
- INFO_VDI,
- INFO_DOG,
- INFO_SHEEP,
- INFO_OBJ,
- INFO_VM,
- INFO_CLUSTER,
- INFO_NONE,
-};
-
-enum format_type {
- FORMAT_LIST,
- FORMAT_TREE,
- FORMAT_GRAPH,
- FORMAT_NONE,
-};
+#define COMMON_SHORT_OPTIONS "p:h"
static void usage(int status)
{
if (status)
fprintf(stderr, "Try `%s --help' for more information.\n", program_name);
else {
- printf("Usage: %s command [command options]\n", program_name);
+ printf("Usage: %s command subcommand [options]\n", program_name);
printf("Sheepdog Administrator Utilty\n\
\n\
Command syntax:\n\
- mkfs [--copies=N]\n\
- delete [-i snapshot_id] vdiname\n\
- info -t (vdi|dog|sheep|obj|cluster) [-f (list|tree|graph)] [-H (on|off)] [-R (on|off)] [-i N] [-e N] [vdiname]\n\
- debug -o node_version\n\
- shutdown\n\
+ cluster (info|format|shutdown)\n\
+ node (info|list)\n\
+ vdi (list|delete|object|lock|release)\n\
+ vm list\n\
\n\
-Command parameters:\n\
- -f, --format specify the output format\n\
- -R, --resient show in a dynamic real-time view\n\
- -t, --type specify the type of information\n\
- -H, --highlight highlight an important infomation\n\
+Common parameters:\n\
+ -p, --port specify the daemon port\n\
-h, --help display this help and exit\n\
");
}
@@ -97,7 +66,7 @@ Command parameters:\n\
static uint64_t node_list_version;
-static struct sheepdog_node_list_entry *node_list_entries;
+static struct sheepdog_node_list_entry node_list_entries[SD_MAX_NODES];
static int nr_nodes;
static unsigned master_idx;
@@ -214,13 +183,18 @@ out:
return ret;
}
-static int mkfs(int copies)
+struct cluster_cmd_data {
+ int copies;
+} cluster_cmd_data;
+
+static int cluster_format(int argc, char **argv)
{
int fd, ret;
struct sd_so_req hdr;
struct sd_so_rsp *rsp = (struct sd_so_rsp *)&hdr;
unsigned rlen, wlen;
struct timeval tv;
+ int copies = cluster_cmd_data.copies ? cluster_cmd_data.copies : 3;
fd = connect_to("localhost", sdport);
if (fd < 0)
@@ -262,179 +236,6 @@ static int mkfs(int copies)
return 0;
}
-static int delete(char *data, uint32_t id)
-{
- int fd, ret;
- struct sd_vdi_req hdr;
- struct sd_vdi_rsp *rsp = (struct sd_vdi_rsp *)&hdr;
- unsigned rlen, wlen;
- char vdiname[SD_MAX_VDI_LEN];
-
- fd = connect_to("localhost", sdport);
- if (fd < 0)
- return -1;
-
- memset(&hdr, 0, sizeof(hdr));
-
- rlen = 0;
- wlen = sizeof(vdiname);
-
- hdr.opcode = SD_OP_DEL_VDI;
- if (id != ~0)
- hdr.snapid = id;
- hdr.epoch = node_list_version;
- hdr.flags = SD_FLAG_CMD_WRITE;
- hdr.data_length = wlen;
- strncpy(vdiname, data, sizeof(vdiname));
-
- ret = exec_req(fd, (struct sd_req *)&hdr, vdiname, &wlen, &rlen);
- close(fd);
-
- if (ret != SD_RES_SUCCESS) {
- fprintf(stderr, "failed to connect the dog\n");
- return ret;
- }
-
- if (rsp->result != SD_RES_SUCCESS) {
- switch (rsp->result) {
- case SD_RES_VDI_LOCKED:
- fprintf(stderr, "the vdi is locked\n");
- break;
- case SD_RES_NO_VDI:
- fprintf(stderr, "no such vdi\n");
- break;
- default:
- fprintf(stderr, "error, %d\n", rsp->result);
- break;
- }
- }
-
- return 0;
-}
-
-static int debug(char *op, char *arg)
-{
- struct sd_req hdr;
- struct sd_rsp *rsp = (struct sd_rsp *)&hdr;
- int fd, ret;
- char name[128];
- unsigned rlen, wlen;
- unsigned opcode, flags;
- uint32_t vid = 0;
- char vdiname[SD_MAX_VDI_LEN];
-
- if (!op)
- return 1;
-
- memset(vdiname, 0, sizeof(vdiname));
-
- strcpy(name, "localhost");
-
- if (!strcasecmp(op, "node_version")) {
- rlen = 0;
- wlen = 0;
- opcode = SD_OP_DEBUG_INC_NVER;
- flags = 0;
- } else if (!strcasecmp(op, "node")) {
- if (!arg)
- return 1;
- rlen = 0;
- wlen = strlen(arg);
- opcode = SD_OP_DEBUG_SET_NODE;
- flags = SD_FLAG_CMD_WRITE;
- } else if (!strcasecmp(op, "lock_vdi")) {
- if (!arg)
- return 1;
- rlen = 0;
- strncpy(vdiname, arg, sizeof(vdiname));
- wlen = sizeof(vdiname);
- opcode = SD_OP_LOCK_VDI;
- flags = SD_FLAG_CMD_WRITE;
- arg = vdiname;
- } else if (!strcasecmp(op, "release_vdi")) {
- if (!arg)
- return 1;
- rlen = 0;
- strncpy(vdiname, arg, sizeof(vdiname));
- wlen = sizeof(vdiname);
- opcode = SD_OP_RELEASE_VDI;
- flags = SD_FLAG_CMD_WRITE;
- arg = vdiname;
- } else if (!strcasecmp(op, "vdi_info")) {
- if (!arg)
- return 1;
- rlen = 0;
- vid = strtoul(arg, NULL, 10);
- if (vid == 0) {
- wlen = strlen(arg) + 1;
- opcode = SD_OP_GET_VDI_INFO;
- flags = SD_FLAG_CMD_WRITE;
- } else {
- wlen = 0;
- opcode = SD_OP_GET_EPOCH;
- flags = 0;
- }
- } else if (!strcasecmp(op, "kill")) {
- if (!arg) {
- fprintf(stderr, "specify hostname\n");
- return 1;
- }
- strcpy(name, arg);
- rlen = 0;
- wlen = 0;
- opcode = SD_OP_DEBUG_KILL;
- flags = 0;
- } else
- return 1;
-
- fd = connect_to(name, sdport);
- if (fd < 0)
- return -1;
-
- memset(&hdr, 0, sizeof(hdr));
-
- hdr.opcode = opcode;
- hdr.data_length = wlen;
- hdr.flags = flags;
- hdr.epoch = node_list_version;
- if (vid > 0) {
- ((struct sd_vdi_req *)&hdr)->base_vdi_id = vid;
- }
-
- ret = exec_req(fd, &hdr, arg, &wlen, &rlen);
- close(fd);
-
- if (ret) {
- fprintf(stderr, "communication error\n");
- return ret;
- }
-
- if (rsp->result != SD_RES_SUCCESS) {
- switch(rsp->result) {
- case SD_RES_VDI_LOCKED:
- fprintf(stderr, "%s is already locked\n", arg);
- break;
- case SD_RES_VDI_NOT_LOCKED:
- fprintf(stderr, "%s is not locked\n", arg);
- break;
- case SD_RES_NO_VDI:
- fprintf(stderr, "%s: no such vdi\n", arg);
- break;
- default:
- fprintf(stderr, "error %d\n", rsp->result);
- break;
- }
- return -1;
- }
-
- if (!strcasecmp(op, "vdi_info")) {
- struct sd_vdi_rsp *vdi_rsp = (struct sd_vdi_rsp *)rsp;
- printf("name = %s, vid = %"PRIu32", epoch = %d\n",
- arg, vdi_rsp->vdi_id, vdi_rsp->vdi_epoch);
- }
- return ret;
-}
-
static int shutdown_sheepdog(void)
{
int fd, ret;
@@ -475,13 +276,9 @@ static int shutdown_sheepdog(void)
return 0;
}
-#define DIR_BUF_LEN (UINT64_C(1) << 20)
-
typedef void (*vdi_parser_func_t)(uint32_t vid, char *name, uint32_t tag, uint32_t flags,
struct sheepdog_inode *i, void *data);
-
-
static int parse_vdi(vdi_parser_func_t func, void *data)
{
int ret, fd;
@@ -528,127 +325,6 @@ static int parse_vdi(vdi_parser_func_t func, void *data)
return 0;
}
-struct graph_info {
- int64_t root;
- char *name;
- int highlight;
-};
-
-static void print_graph_tree(uint32_t vid, char *name, uint32_t tag,
- uint32_t flags, struct sheepdog_inode *i, void *data)
-{
- struct graph_info *info = (struct graph_info *)data;
- time_t ti;
- struct tm tm;
- char date[128];
- char time[128];
- char size_str[8];
-
- if (info->name && strcmp(info->name, name) != 0)
- return;
-
- if (info->root < 0)
- info->root = vid_to_vdi_oid(i->parent_vdi_id);
-
- ti = i->ctime >> 32;
- localtime_r(&ti, &tm);
-
- strftime(date, sizeof(date), "%y-%m-%d", &tm);
- strftime(time, sizeof(time), "%H:%M:%S", &tm);
- size_to_str(i->vdi_size, size_str, sizeof(size_str));
-
- printf(" \"%" PRIu32 "\" [shape = \"box\","
- "fontname = \"Courier\","
- "fontsize = \"12\","
- "group = \"%s\","
- "label = \"",
- vid, name);
- printf("name: %8s\\n"
- "tag : %8x\\n"
- "size: %8s\\n"
- "date: %8s\\n"
- "time: %8s",
- name, tag, size_str, date, time);
-
- if (info->highlight && is_current(i))
- printf("\", color=\"red\"];\n");
- else
- printf("\"];\n");
-
- printf(" \"%" PRIu32 "\" -> \"%" PRIu32 "\";\n", i->parent_vdi_id, vid);
-}
-
-static int graphview_vdi(char *vdiname, int highlight)
-{
- struct graph_info i;
-
- i.name = vdiname;
- i.highlight = highlight;
- i.root = -1;
-
- /* print a header */
- printf("digraph G {\n");
-
- parse_vdi(print_graph_tree, &i);
-
- if (i.root == 0)
- printf(" \"0\" [shape = \"ellipse\", label = \"root\"];\n");
- else if (i.root > 0)
- printf(" \"%" PRIu64 "\" [shape = \"ellipse\", label = \"%s\"];\n",
- i.root, vdiname);
-
- /* print a footer */
- printf("}\n");
-
- return 0;
-}
-
-struct tree_info {
- int highlight;
- char *name;
-};
-
-static void print_vdi_tree(uint32_t vid, char *name, uint32_t tag,
- uint32_t flags, struct sheepdog_inode *i, void *data)
-{
- struct tree_info *info = (struct tree_info *)data;
- time_t ti;
- struct tm tm;
- char buf[128];
-
- if (info->name && strcmp(name, info->name))
- return;
-
- if (is_current(i))
- strcpy(buf, "(You Are Here)");
- else {
- ti = i->ctime >> 32;
- localtime_r(&ti, &tm);
-
- strftime(buf, sizeof(buf),
- "[%y-%m-%d %H:%M]", &tm);
- }
-
- add_vdi_tree(name, buf, vid, i->parent_vdi_id,
- info->highlight && is_current(i));
-}
-
-static int treeview_vdi(char *vdiname, int highlight)
-{
- struct tree_info i;
-
- i.name = vdiname;
- i.highlight = highlight;
-
- init_tree();
-
- parse_vdi(print_vdi_tree, &i);
-
- dump_tree();
-
- return 0;
-}
-
static void print_vdi_list(uint32_t vid, char *name, uint32_t tag,
uint32_t flags, struct sheepdog_inode *i, void *data)
{
@@ -878,8 +554,216 @@ static void parse_objs(uint64_t oid, obj_parser_func_t func, void *data)
free(buf);
}
-static void print_obj(char *vdiname, unsigned index)
+#define SUBCMD_FLAG_NEED_NOEDLIST (1 << 0)
+#define SUBCMD_FLAG_NEED_THIRD_ARG (1 << 1)
+
+struct subcommand {
+ char *name;
+ unsigned long flags;
+ int (*fn)(int, char **);
+};
+
+static int node_list(int argc, char **argv)
+{
+ int i;
+
+ printf(" Idx\tNode id (FNV-1a) - Host:Port\n");
+ printf("------------------------------------------------\n");
+ for (i = 0; i < nr_nodes; i++) {
+ char data[128];
+
+ print_node_list_entry(&node_list_entries[i], data, sizeof(data));
+
+ if (i == master_idx) {
+ const char *tmp;
+
+ if (highlight && (tmp = tgetstr("md", NULL)))
+ tputs(tmp, 1, putchar);
+ printf("* %d\t%s\n", i, data);
+ if (highlight && (tmp = tgetstr("me", NULL)))
+ tputs(tmp, 1, putchar);
+ } else
+ printf(" %d\t%s\n", i, data);
+ }
+
+ return 0;
+}
+
+static int node_info(int argc, char **argv)
{
+ int i, ret, success = 0;
+ uint64_t total_size = 0, total_avail = 0, total_vdi_size = 0;
+ char total_str[8], avail_str[8], vdi_size_str[8];
+
+ printf("Id\tSize\tUsed\tUse%%\n");
+
+ for (i = 0; i < nr_nodes; i++) {
+ char name[128];
+ int fd;
+ unsigned wlen, rlen;
+ struct sd_node_req req;
+ struct sd_node_rsp *rsp = (struct sd_node_rsp *)&req;
+ char store_str[8], free_str[8];
+
+ addr_to_str(name, sizeof(name), node_list_entries[i].addr, 0);
+
+ fd = connect_to(name, node_list_entries[i].port);
+ if (fd < 0)
+ return 1;
+
+ memset(&req, 0, sizeof(req));
+
+ req.opcode = SD_OP_STAT_SHEEP;
+ req.epoch = node_list_version;
+
+ wlen = 0;
+ rlen = 0;
+ ret = exec_req(fd, (struct sd_req *)&req, NULL, &wlen, &rlen);
+ close(fd);
+
+ size_to_str(rsp->store_size, store_str, sizeof(store_str));
+ size_to_str(rsp->store_size - rsp->store_free, free_str,
+ sizeof(free_str));
+ if (!ret && rsp->result == SD_RES_SUCCESS) {
+ printf("%2d\t%s\t%s\t%3d%%\n", i, store_str, free_str,
+ (int)(((double)(rsp->store_size - rsp->store_free) / rsp->store_size) * 100));
+ success++;
+ }
+
+ total_size += rsp->store_size;
+ total_avail += rsp->store_free;
+ }
+
+ printf("\n");
+
+ if (success == 0) {
+ fprintf(stderr, "cannot get information from any nodes\n");
+ return 1;
+ }
+
+ parse_vdi(cal_total_vdi_size, &total_vdi_size);
+
+ size_to_str(total_size, total_str, sizeof(total_str));
+ size_to_str(total_size - total_avail, avail_str, sizeof(avail_str));
+ size_to_str(total_vdi_size, vdi_size_str, sizeof(vdi_size_str));
+ printf("Total\t%s\t%s\t%3d%%, total virtual VDI Size\t%s\n",
+ total_str, avail_str,
+ (int)(((double)(total_size - total_avail) / total_size) * 100),
+ vdi_size_str);
+
+ return 0;
+}
+
+static struct subcommand node_cmd[] = {
+ {"list", SUBCMD_FLAG_NEED_NOEDLIST, node_list},
+ {"info", SUBCMD_FLAG_NEED_NOEDLIST, node_info},
+ {NULL,},
+};
+
+static int vm_list(int argc, char **argv)
+{
+ int fd, ret;
+ struct sd_req hdr;
+ unsigned rlen, wlen;
+ char *data;
+ struct vm_list_info vli;
+
+ fd = connect_to("localhost", sdport);
+ if (fd < 0)
+ return 1;
+
+ memset(&hdr, 0, sizeof(hdr));
+
+ hdr.opcode = SD_OP_GET_VM_LIST;
+ hdr.data_length = sizeof(struct sheepdog_vm_list_entry) * SD_MAX_VMS;
+ hdr.epoch = node_list_version;
+ data = zalloc(hdr.data_length);
+
+ rlen = hdr.data_length;
+ wlen = 0;
+ ret = exec_req(fd, &hdr, data, &wlen, &rlen);
+ close(fd);
+
+ if (ret != SD_RES_SUCCESS)
+ return 1;
+ vli.vm_list_entries = (struct sheepdog_vm_list_entry *)data;
+ vli.nr_vms = rlen / sizeof(struct sheepdog_vm_list_entry);
+ vli.highlight = highlight;
+
+ printf("Name |Vdi size |Allocated| Shared | Status\n");
+ printf("----------------+---------+---------+---------+------------\n");
+ ret = parse_vdi(print_vm_list, &vli);
+
+ return 0;
+}
+
+static struct subcommand vm_cmd[] = {
+ {"list", SUBCMD_FLAG_NEED_NOEDLIST, vm_list},
+ {NULL,},
+};
+
+static int vdi_list(int argc, char **argv)
+{
+ parse_vdi(print_vdi_list, NULL);
+ return 0;
+}
+
+static int vdi_delete(int argc, char **argv)
+{
+ char *data = argv[optind];
+ int fd, ret;
+ struct sd_vdi_req hdr;
+ struct sd_vdi_rsp *rsp = (struct sd_vdi_rsp *)&hdr;
+ unsigned rlen, wlen;
+ char vdiname[SD_MAX_VDI_LEN];
+ uint32_t id = ~0;
+
+ fd = connect_to("localhost", sdport);
+ if (fd < 0)
+ return -1;
+
+ memset(&hdr, 0, sizeof(hdr));
+
+ rlen = 0;
+ wlen = sizeof(vdiname);
+
+ hdr.opcode = SD_OP_DEL_VDI;
+ if (id != ~0)
+ hdr.snapid = id;
+ hdr.epoch = node_list_version;
+ hdr.flags = SD_FLAG_CMD_WRITE;
+ hdr.data_length = wlen;
+ strncpy(vdiname, data, sizeof(vdiname));
+
+ ret = exec_req(fd, (struct sd_req *)&hdr, vdiname, &wlen, &rlen);
+ close(fd);
+
+ if (ret != SD_RES_SUCCESS) {
+ fprintf(stderr, "failed to connect the dog\n");
+ return ret;
+ }
+
+ if (rsp->result != SD_RES_SUCCESS) {
+ switch (rsp->result) {
+ case SD_RES_VDI_LOCKED:
+ fprintf(stderr, "the vdi is locked\n");
+ break;
+ case SD_RES_NO_VDI:
+ fprintf(stderr, "no such vdi\n");
+ break;
+ default:
+ fprintf(stderr, "error, %d\n", rsp->result);
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static int vdi_object(int argc, char **argv)
+{
+ char *vdiname = argv[optind];
+ unsigned index = ~0;
int ret;
struct get_vid_info info;
uint32_t vid;
@@ -892,7 +776,7 @@ static void print_obj(char *vdiname, unsigned index)
vid = info.vid;
if (vid == 0) {
printf("No such vdi\n");
- return;
+ return 1;
}
if (index == ~0) {
@@ -925,396 +809,361 @@ static void print_obj(char *vdiname, unsigned index)
} else
printf("failed to read the inode object 0x%" PRIx32 "\n", vid);
}
+
+ return 0;
}
-static int info(enum info_type type, enum format_type format, char *name,
- int highlight, int real_time, unsigned index)
+static int vdi_lock(int argc, char **argv)
{
- int i, ret = -1;
- uint64_t total_size = 0, total_avail = 0, total_vdi_size = 0;
- char total_str[8], avail_str[8], vdi_size_str[8];
- int success;
+ struct sd_req hdr;
+ struct sd_rsp *rsp = (struct sd_rsp *)&hdr;
+ int ret;
+ char vdiname[SD_MAX_VDI_LEN];
+ unsigned rlen = 0, wlen = 0;
+ unsigned opcode, flags;
+ int fd;
- if (real_time) {
- setupterm(NULL, 1, (int *)0);
- fflush(stderr);
- fflush(stdout);
- clear();
- }
-rerun:
- if (real_time) {
- if (clear_screen == NULL)
- return -2;
- putp(clear_screen);
+ memset(vdiname, 0, sizeof(vdiname));
+
+ strncpy(vdiname, argv[optind], sizeof(vdiname));
+ wlen = sizeof(vdiname);
+ opcode = SD_OP_LOCK_VDI;
+ flags = SD_FLAG_CMD_WRITE;
+
+ fd = connect_to("localhost", sdport);
+ if (fd < 0)
+ return 1;
+
+ memset(&hdr, 0, sizeof(hdr));
+
+ hdr.opcode = opcode;
+ hdr.data_length = wlen;
+ hdr.flags = flags;
+ hdr.epoch = node_list_version;
+
+ ret = exec_req(fd, &hdr, vdiname, &wlen, &rlen);
+ close(fd);
+
+ if (ret) {
+ fprintf(stderr, "communication error\n");
+ return 1;
}
- switch (type) {
- case INFO_VDI:
- switch (format) {
- case FORMAT_LIST:
- printf(" name id size used shared creation time vdi id\n");
- printf("------------------------------------------------------------------\n");
- ret = parse_vdi(print_vdi_list, name);
+ if (rsp->result != SD_RES_SUCCESS) {
+ switch(rsp->result) {
+ case SD_RES_VDI_LOCKED:
+ fprintf(stderr, "%s is already locked\n", vdiname);
break;
- case FORMAT_TREE:
- ret = treeview_vdi(name, highlight);
+ case SD_RES_VDI_NOT_LOCKED:
+ fprintf(stderr, "%s is not locked\n", vdiname);
break;
- case FORMAT_GRAPH:
- ret = graphview_vdi(name, highlight);
+ case SD_RES_NO_VDI:
+ fprintf(stderr, "%s: no such vdi\n", vdiname);
break;
default:
- ret = -1;
+ fprintf(stderr, "error %d\n", rsp->result);
break;
}
- break;
- case INFO_DOG:
- printf(" Idx\tNode id (FNV-1a) - Host:Port\n");
- printf("------------------------------------------------\n");
- for (i = 0; i < nr_nodes; i++) {
- char data[128];
-
- print_node_list_entry(&node_list_entries[i], data, sizeof(data));
-
- if (i == master_idx) {
- const char *tmp;
-
- if (highlight && (tmp = tgetstr("md", NULL)))
- tputs(tmp, 1, putchar);
- printf("* %d\t%s\n", i, data);
- if (highlight && (tmp = tgetstr("me", NULL)))
- tputs(tmp, 1, putchar);
- } else
- printf(" %d\t%s\n", i, data);
- }
- ret = 0;
- break;
- case INFO_SHEEP:
- printf("Id\tSize\tUsed\tUse%%\n");
-
- success = 0;
- for (i = 0; i < nr_nodes; i++) {
- char name[128];
- int fd;
- unsigned wlen, rlen;
- struct sd_node_req req;
- struct sd_node_rsp *rsp = (struct sd_node_rsp *)&req;
- char store_str[8], free_str[8];
-
- addr_to_str(name, sizeof(name), node_list_entries[i].addr, 0);
-
- fd = connect_to(name, node_list_entries[i].port);
- if (fd < 0)
- continue;
+ return 1;
+ }
- memset(&req, 0, sizeof(req));
+ return 0;
+}
- req.opcode = SD_OP_STAT_SHEEP;
- req.epoch = node_list_version;
+static int vdi_release(int argc, char **argv)
+{
+ struct sd_req hdr;
+ struct sd_rsp *rsp = (struct sd_rsp *)&hdr;
+ int ret;
+ char vdiname[SD_MAX_VDI_LEN];
+ unsigned rlen = 0, wlen = 0;
+ unsigned opcode, flags;
+ int fd;
+ char *data = NULL;
- wlen = 0;
- rlen = 0;
- ret = exec_req(fd, (struct sd_req *)&req, NULL, &wlen, &rlen);
- close(fd);
+ memset(vdiname, 0, sizeof(vdiname));
- size_to_str(rsp->store_size, store_str, sizeof(store_str));
- size_to_str(rsp->store_size - rsp->store_free, free_str,
- sizeof(free_str));
- if (!ret && rsp->result == SD_RES_SUCCESS) {
- printf("%2d\t%s\t%s\t%3d%%\n", i, store_str, free_str,
- (int)(((double)(rsp->store_size - rsp->store_free) / rsp->store_size) * 100));
- success++;
- }
+ strncpy(vdiname, argv[optind], sizeof(vdiname));
+ wlen = sizeof(vdiname);
+ data = vdiname;
+ opcode = SD_OP_RELEASE_VDI;
+ flags = SD_FLAG_CMD_WRITE;
- total_size += rsp->store_size;
- total_avail += rsp->store_free;
- }
+ fd = connect_to("localhost", sdport);
+ if (fd < 0)
+ return 1;
- printf("\n");
+ memset(&hdr, 0, sizeof(hdr));
- if (success == 0) {
- fprintf(stderr, "cannot get information from any nodes\n");
- ret = -1;
- break;
- }
+ hdr.opcode = opcode;
+ hdr.data_length = wlen;
+ hdr.flags = flags;
+ hdr.epoch = node_list_version;
- parse_vdi(cal_total_vdi_size, &total_vdi_size);
+ ret = exec_req(fd, &hdr, data, &wlen, &rlen);
+ close(fd);
- size_to_str(total_size, total_str, sizeof(total_str));
- size_to_str(total_size - total_avail, avail_str, sizeof(avail_str));
- size_to_str(total_vdi_size, vdi_size_str, sizeof(vdi_size_str));
- printf("Total\t%s\t%s\t%3d%%, total virtual VDI Size\t%s\n",
- total_str, avail_str,
- (int)(((double)(total_size - total_avail) / total_size) * 100),
- vdi_size_str);
+ if (ret) {
+ fprintf(stderr, "communication error\n");
+ return 1;
+ }
- ret = 0;
- break;
- case INFO_OBJ:
- if (!name) {
- printf("Please specify the vdiname\n");
+ if (rsp->result != SD_RES_SUCCESS) {
+ switch(rsp->result) {
+ case SD_RES_VDI_LOCKED:
+ fprintf(stderr, "%s is already locked\n", vdiname);
+ break;
+ case SD_RES_VDI_NOT_LOCKED:
+ fprintf(stderr, "%s is not locked\n", vdiname);
+ break;
+ case SD_RES_NO_VDI:
+ fprintf(stderr, "%s: no such vdi\n", vdiname);
+ break;
+ default:
+ fprintf(stderr, "error %d\n", rsp->result);
break;
}
- print_obj(name, index);
- ret = 0;
- break;
- case INFO_VM:
- {
- int fd;
- struct sd_req hdr;
- unsigned rlen, wlen;
- char *data;
- struct vm_list_info vli;
+ return 1;
+ }
- fd = connect_to("localhost", sdport);
- if (fd < 0)
- break;
+ return 0;
+}
- memset(&hdr, 0, sizeof(hdr));
+static struct subcommand vdi_cmd[] = {
+ {"delete", SUBCMD_FLAG_NEED_NOEDLIST|SUBCMD_FLAG_NEED_THIRD_ARG, vdi_delete},
+ {"list", SUBCMD_FLAG_NEED_NOEDLIST, vdi_list},
+ {"object", SUBCMD_FLAG_NEED_NOEDLIST|SUBCMD_FLAG_NEED_THIRD_ARG, vdi_object},
+ {"lock", SUBCMD_FLAG_NEED_THIRD_ARG, vdi_lock},
+ {"release", SUBCMD_FLAG_NEED_THIRD_ARG, vdi_release},
+ {NULL,},
+};
- hdr.opcode = SD_OP_GET_VM_LIST;
- hdr.data_length = sizeof(struct sheepdog_vm_list_entry) * SD_MAX_VMS;
- hdr.epoch = node_list_version;
- data = zalloc(hdr.data_length);
+static int cluster_info(int argc, char **argv)
+{
+ int i, fd, ret;
+ struct sd_vdi_req hdr;
+ struct sd_vdi_rsp *rsp = (struct sd_vdi_rsp *)&hdr;
+ unsigned rlen, wlen;
+ struct epoch_log logs[8];
+ int nr_logs;
+ time_t ti;
+ struct tm tm;
+ char time[128];
- rlen = hdr.data_length;
- wlen = 0;
- ret = exec_req(fd, &hdr, data, &wlen, &rlen);
- close(fd);
+ fd = connect_to("localhost", sdport);
+ if (fd < 0)
+ return 1;
- if (ret != SD_RES_SUCCESS)
- break;
- vli.vm_list_entries = (struct sheepdog_vm_list_entry *)data;
- vli.nr_vms = rlen / sizeof(struct sheepdog_vm_list_entry);
- vli.highlight = highlight;
+ memset(&hdr, 0, sizeof(hdr));
+
+ hdr.opcode = SD_OP_STAT_CLUSTER;
+ hdr.epoch = node_list_version;
+ hdr.data_length = sizeof(logs);
+
+ rlen = hdr.data_length;
+ wlen = 0;
+ ret = exec_req(fd, (struct sd_req *)&hdr, logs, &wlen, &rlen);
+ close(fd);
+
+ if (ret != 0)
+ return 1;
+
+ if (rsp->result != SD_RES_SUCCESS) {
+ fprintf(stderr, "failed to get cluster status, %x\n", rsp->result);
+ return 1;
+ }
+ switch (rsp->rsvd) {
+ case SD_STATUS_OK:
+ printf("running\n");
+ break;
+ case SD_STATUS_WAIT_FOR_FORMAT:
+ printf("sheepdog is not formatted yet\n");
+ break;
+ case SD_STATUS_WAIT_FOR_JOIN:
+ printf("sheepdog is waiting for other nodes joining\n");
+ break;
+ case SD_STATUS_INCONSISTENT_EPOCHS:
+ printf("there is inconsistency between epochs\n");
+ break;
+ case SD_STATUS_SHUTDOWN:
+ printf("shutdown\n");
+ break;
+ default:
+ printf("%d\n", rsp->rsvd);
+ break;
+ }
+ printf("\n");
+ printf("Ctime Epoch Nodes\n");
+ nr_logs = rsp->data_length / sizeof(struct epoch_log);
+ for (i = 0; i < nr_logs; i++) {
+ int j;
+ char name[128];
+ struct sheepdog_node_list_entry *entry;
+
+ ti = logs[i].ctime >> 32;
+ localtime_r(&ti, &tm);
+ strftime(time, sizeof(time), "%y-%m-%d %H:%M:%S", &tm);
+
+ printf("%s %6d", time, logs[i].epoch);
+ printf(" [");
+ for (j = 0; j < logs[i].nr_nodes; j++) {
+ entry = logs[i].nodes + j;
+ printf("%s%s",
+ (j == 0) ? "" : ", ",
+ addr_to_str(name, sizeof(name),
+ entry->addr, entry->port));
+ }
+ printf("]\n");
+ }
+
+ return 0;
+}
- printf("Name |Vdi size |Allocated| Shared | Status\n");
- printf("----------------+---------+---------+---------+------------\n");
- ret = parse_vdi(print_vm_list, &vli);
+static int cluster_parser(int ch, char *opt)
+{
+ switch (ch) {
+ case 'c':
+ cluster_cmd_data.copies = atoi(opt);
break;
}
- case INFO_CLUSTER:
- {
- int fd;
- struct sd_vdi_req hdr;
- struct sd_vdi_rsp *rsp = (struct sd_vdi_rsp *)&hdr;
- unsigned rlen, wlen;
- struct epoch_log logs[8];
- int nr_logs;
- time_t ti;
- struct tm tm;
- char time[128];
-
- fd = connect_to("localhost", sdport);
- if (fd < 0)
- break;
- memset(&hdr, 0, sizeof(hdr));
+ return 0;
+}
- hdr.opcode = SD_OP_STAT_CLUSTER;
- hdr.epoch = node_list_version;
- hdr.data_length = sizeof(logs);
+static int cluster_shoutdown(int argc, char **argv)
+{
+ shutdown_sheepdog();
+ return 0;
+}
- rlen = hdr.data_length;
- wlen = 0;
- ret = exec_req(fd, (struct sd_req *)&hdr, logs, &wlen, &rlen);
- close(fd);
+static struct subcommand cluster_cmd[] = {
+ {"info", 0, cluster_info},
+ {"format", 0, cluster_format},
+ {"shutdown", SUBCMD_FLAG_NEED_NOEDLIST, cluster_shoutdown},
+ {NULL,},
+};
- if (ret != 0)
- break;
+static struct option cluster_long_options[] =
+{
+ COMMON_LONG_OPTIONS
+ {"copies", required_argument, NULL, 'c'},
+ {NULL, 0, NULL, 0},
+};
- if (rsp->result != SD_RES_SUCCESS) {
- fprintf(stderr, "failed to get cluster status, %x\n", rsp->result);
+static struct {
+ char *name;
+ struct subcommand *sub;
+ struct option *lopts;
+ char *sopts;
+ int (*parser)(int, char *);
+ void (*help)(void);
+} commands[] = {
+ {"vdi", vdi_cmd,},
+ {"node", node_cmd,},
+ {"vm", vm_cmd,},
+ {"cluster", cluster_cmd,
+ cluster_long_options,
+ COMMON_SHORT_OPTIONS "c:",
+ cluster_parser,},
+};
+
+static struct option common_long_options[] =
+{
+ COMMON_LONG_OPTIONS
+ {NULL, 0, NULL, 0},
+};
+
+static struct option *long_options = common_long_options;
+static char *short_options = COMMON_SHORT_OPTIONS;
+static int (*command_parser)(int, char *);
+static int (*command_fn)(int, char **);
+static void (*command_help)(void);
+
+static void setup_command(char *cmd, char *subcmd)
+{
+ int i, found = 0;
+ struct subcommand *s;
+ unsigned long flags;
+
+ for (i = 0; i < ARRAY_SIZE(commands); i++) {
+ if (!strncmp(commands[i].name, cmd, strlen(commands[i].name))) {
+ found = 1;
+ if (commands[i].parser) {
+ command_parser = commands[i].parser;
+ long_options = commands[i].lopts;
+ short_options = commands[i].sopts;
+ }
break;
}
- switch (rsp->rsvd) {
- case SD_STATUS_OK:
- printf("running\n");
- break;
- case SD_STATUS_WAIT_FOR_FORMAT:
- printf("sheepdog is not formatted yet\n");
- break;
- case SD_STATUS_WAIT_FOR_JOIN:
- printf("sheepdog is waiting for other nodes joining\n");
- break;
- case SD_STATUS_INCONSISTENT_EPOCHS:
- printf("there is inconsistency between epochs\n");
- break;
- case SD_STATUS_SHUTDOWN:
- printf("shutdown\n");
- break;
- default:
- printf("%d\n", rsp->rsvd);
+ }
+
+ if (!found) {
+ fprintf(stderr, "'%s' is not a valid command\n", cmd);
+ usage(1);
+ }
+
+ for (s = commands[i].sub; s->name; s++) {
+ if (!strncmp(s->name, subcmd, strlen(s->name))) {
+ command_fn = s->fn;
+ flags = s->flags;
break;
}
- printf("\n");
- printf("Ctime Epoch Nodes\n");
- nr_logs = rsp->data_length / sizeof(struct epoch_log);
- for (i = 0; i < nr_logs; i++) {
- int j;
- char name[128];
- struct sheepdog_node_list_entry *entry;
-
- ti = logs[i].ctime >> 32;
- localtime_r(&ti, &tm);
- strftime(time, sizeof(time), "%y-%m-%d %H:%M:%S", &tm);
-
- printf("%s %6d", time, logs[i].epoch);
- printf(" [");
- for (j = 0; j < logs[i].nr_nodes; j++) {
- entry = logs[i].nodes + j;
- printf("%s%s",
- (j == 0) ? "" : ", ",
- addr_to_str(name, sizeof(name),
- entry->addr, entry->port));
- }
- printf("]\n");
- }
- break;
}
- default:
- ret = -1;
- break;
+
+ if (!command_fn) {
+ fprintf(stderr, "'%s' is not a valid subcommand\n", subcmd);
+ fprintf(stderr, "'%s' supports the following subcommand:\n", cmd);
+ for (s = commands[i].sub; s->name; s++)
+ fprintf(stderr, "%s\n", s->name);
+ exit(1);
}
- if (real_time && ret == 0) {
- fflush(stdout);
- sleep(1);
- goto rerun;
+ if (flags & SUBCMD_FLAG_NEED_THIRD_ARG) {
+ fprintf(stderr, "'%s %s' needs the third argument\n", cmd, subcmd);
+ exit(1);
}
- return ret;
+
+ if (flags & SUBCMD_FLAG_NEED_NOEDLIST)
+ update_node_list(SD_MAX_NODES, 0);
}
int main(int argc, char **argv)
{
int ch, longindex;
- int ret = 0;
- char *command;
- enum info_type type = INFO_NONE;
- enum format_type format = FORMAT_LIST;
- int reboot = 0;
- int highlight = 1;
char termcap_area[1024];
- int copies = DEAFAULT_NR_COPIES;
- char *op = NULL;
- unsigned index = ~0;
- int real_time = 0;
- int epoch = 0;
if (getenv("TERM"))
tgetent(termcap_area, getenv("TERM"));
+ if (argc < 3)
+ usage(0);
+
+ setup_command(argv[1], argv[2]);
+
+ optind = 3;
+
while ((ch = getopt_long(argc, argv, short_options, long_options,
- &longindex)) >= 0) {
+ &longindex)) >= 0) {
+
switch (ch) {
case 'p':
sdport = atoi(optarg);
break;
- case 'c':
- copies = atoi(optarg);
- break;
- case 'f':
- if (strcasecmp(optarg, "list") == 0)
- format = FORMAT_LIST;
- else if (strcasecmp(optarg, "tree") == 0)
- format = FORMAT_TREE;
- else if (strcasecmp(optarg, "graph") == 0)
- format = FORMAT_GRAPH;
- else
- usage(1);
- break;
- case 'H':
- if (strcasecmp(optarg, "on") == 0)
- highlight = 1;
- else if (strcasecmp(optarg, "off") == 0)
- highlight = 0;
- else
- usage(1);
- break;
- case 'R':
- if (strcasecmp(optarg, "on") == 0)
- real_time = 1;
- else if (strcasecmp(optarg, "off") == 0)
- real_time = 0;
- else
- usage(1);
- break;
case 'h':
- usage(0);
- case 'r':
- reboot = 1;
- break;
- case 't':
- if (!strcasecmp(optarg, "vdi"))
- type = INFO_VDI;
- else if (!strcasecmp(optarg, "dog"))
- type = INFO_DOG;
- else if (!strcasecmp(optarg, "sheep"))
- type = INFO_SHEEP;
- else if (!strcasecmp(optarg, "obj"))
- type = INFO_OBJ;
- else if (!strcasecmp(optarg, "vm"))
- type = INFO_VM;
- else if (!strcasecmp(optarg, "cluster"))
- type = INFO_CLUSTER;
- else
- usage(1);
- break;
- case 'o':
- op = optarg;
+ if (command_help)
+ command_help();
break;
- case 'i':
- index = strtoul(optarg, NULL, 10);
- break;
- case 'e':
- epoch = strtoul(optarg, NULL, 10);
- if (epoch <= 0) {
- fprintf(stderr, "epoch must be larger than 0\n");
- usage(1);
- }
+ case '?':
+ usage(1);
break;
default:
- usage(1);
+ if (command_parser)
+ command_parser(ch, optarg);
+ else
+ usage(1);
break;
}
}
- if (optind >= argc)
- usage(0);
-
- node_list_entries = zalloc(SD_MAX_NODES * sizeof(struct sheepdog_node_list_entry));
- command = argv[optind++];
-
- /* TODO: cleanup */
- if (strcasecmp(command, "mkfs") == 0)
- ;
- else if (strcasecmp(command, "info") == 0 && type == INFO_CLUSTER)
- ;
- else {
- ret = update_node_list(SD_MAX_NODES, epoch);
- if (ret < 0)
- return 1;
- }
-
- if (!strcasecmp(command, "info")) {
- char *name = NULL;
-
- if (type == INFO_NONE)
- usage(0);
- if (optind != argc)
- name = argv[optind];
-
- info(type, format, name, highlight, real_time, index);
- } else if (!strcasecmp(command, "mkfs"))
- ret = mkfs(copies);
- else if (!strcasecmp(command, "delete"))
- ret = delete(argv[optind], index);
- else if (!strcasecmp(command, "debug"))
- ret = debug(op, argv[optind]);
- else if (!strcasecmp(command, "shutdown"))
- ret = shutdown_sheepdog();
- else {
- fprintf(stderr, "'%s' is not a valid command\n", command);
- usage(1);
- }
- return ret;
+ return command_fn(argc, argv);
}
--
1.6.5
More information about the sheepdog
mailing list