All of lore.kernel.org
 help / color / mirror / Atom feed
From: Dmitry Mishin <dim@parallels.com>
To: cluster-devel.redhat.com
Subject: [Cluster-devel] [PATCH 1/8] Add "service" object manipulations
Date: Fri, 10 Dec 2010 16:42:30 +0300	[thread overview]
Message-ID: <1291988557-22348-2-git-send-email-dim@parallels.com> (raw)
In-Reply-To: <1291988557-22348-1-git-send-email-dim@parallels.com>

In order to be useful, cluster needs service defined, which it will take care
of. Patch adds ability to define service using already defined resources (like
fs, script, ip, etc.)

Signed-off-by: Dmitry Mishin <dim@parallels.com>
---
 config/tools/ccs_tool/ccs_tool.c |   15 ++
 config/tools/ccs_tool/editconf.c |  364 +++++++++++++++++++++++++++++++++++++-
 config/tools/ccs_tool/editconf.h |    3 +
 3 files changed, 378 insertions(+), 4 deletions(-)

diff --git a/config/tools/ccs_tool/ccs_tool.c b/config/tools/ccs_tool/ccs_tool.c
index 34805be..2fe6f78 100644
--- a/config/tools/ccs_tool/ccs_tool.c
+++ b/config/tools/ccs_tool/ccs_tool.c
@@ -225,6 +225,14 @@ static int tool_main(int argc, char *argv[])
 	    del_node(argc-1, argv+1);
 	    exit(EXIT_SUCCESS);
     }
+    else if(!strcmp(argv[optind], "addservice")){
+	    add_service(argc-1, argv+1);
+	    exit(EXIT_SUCCESS);
+    }
+    else if(!strcmp(argv[optind], "delservice")){
+	    del_service(argc-1, argv+1);
+	    exit(EXIT_SUCCESS);
+    }
     else if(!strcmp(argv[optind], "addfence")){
 	    add_fence(argc-1, argv+1);
 	    exit(EXIT_SUCCESS);
@@ -237,6 +245,10 @@ static int tool_main(int argc, char *argv[])
 	    list_nodes(argc-1, argv+1);
 	    exit(EXIT_SUCCESS);
     }
+    else if(!strcmp(argv[optind], "lsservice")){
+	    list_services(argc-1, argv+1);
+	    exit(EXIT_SUCCESS);
+    }
     else if(!strcmp(argv[optind], "lsfence")){
 	    list_fences(argc-1, argv+1);
 	    exit(EXIT_SUCCESS);
@@ -279,6 +291,9 @@ static void tool_print_usage(FILE *stream){
 	  "  addnode <node>      Add a node\n"
           "  delnode <node>      Delete a node\n"
           "  lsnode              List nodes\n"
+	  "  addservice <name>   Add a service\n"
+          "  delservice <name>   Delete a service\n"
+          "  lsservice           List services\n"
           "  lsfence             List fence devices\n"
 	  "  addfence <fencedev> Add a new fence device\n"
 	  "  delfence <fencedev> Delete a fence device\n"
diff --git a/config/tools/ccs_tool/editconf.c b/config/tools/ccs_tool/editconf.c
index a0371b4..d63dc37 100644
--- a/config/tools/ccs_tool/editconf.c
+++ b/config/tools/ccs_tool/editconf.c
@@ -32,7 +32,14 @@ struct option_info
 	const char *votes;
 	const char *nodeid;
 	const char *mcast_addr;
+	const char *ip_addr;
 	const char *fence_type;
+	const char *autostart;
+	const char *exclusive;
+	const char *recovery;
+	const char *fs;
+	const char *script;
+	const char *mountpoint;
 	const char *configfile;
 	const char *outputfile;
 	int  do_delete;
@@ -121,6 +128,15 @@ static void delnode_usage(const char *name)
 	exit(0);
 }
 
+static void delservice_usage(const char *name)
+{
+	fprintf(stderr, "Usage: %s %s [options] <name>\n", prog_name, name);
+	config_usage(1);
+	help_usage();
+
+	exit(0);
+}
+
 static void addnodeid_usage(const char *name)
 {
 	fprintf(stderr, "Add node IDs to all nodes in the config file that don't have them.\n");
@@ -160,6 +176,15 @@ static void addnode_usage(const char *name)
 	exit(0);
 }
 
+static void addservice_usage(const char *name)
+{
+	fprintf(stderr, "Usage: %s %s [options] <servicename>\n", prog_name, name);
+	config_usage(1);
+	help_usage();
+
+	exit(0);
+}
+
 /* Is it really ?
  * Actually, we don't check that this is a valid multicast address(!),
  * merely that it is a valid IP[46] address.
@@ -378,15 +403,17 @@ static xmlNode *find_multicast_addr(xmlNode *clusternodes)
 	return NULL;
 }
 
-static xmlNode *find_node(xmlNode *clusternodes, const char *nodename)
+static xmlNode *do_find_node(xmlNode *root, const char *nodename,
+	const char *elem_name, const char *attrib_name)
 {
 	xmlNode *cur_node;
 
-	for (cur_node = clusternodes->children; cur_node; cur_node = cur_node->next)
+	for (cur_node = root->children; cur_node; cur_node = cur_node->next)
 	{
-		if (cur_node->type == XML_ELEMENT_NODE && strcmp((char *)cur_node->name, "clusternode") == 0)
+		if (cur_node->type == XML_ELEMENT_NODE &&
+			strcmp((char *)cur_node->name, elem_name) == 0)
 		{
-			xmlChar *name = xmlGetProp(cur_node, BAD_CAST "name");
+			xmlChar *name = xmlGetProp(cur_node, BAD_CAST attrib_name);
 			if (strcmp((char *)name, nodename) == 0)
 				return cur_node;
 		}
@@ -394,6 +421,31 @@ static xmlNode *find_node(xmlNode *clusternodes, const char *nodename)
 	return NULL;
 }
 
+static xmlNode *find_node(xmlNode *clusternodes, const char *nodename)
+{
+	return do_find_node(clusternodes, nodename, "clusternode", "name");
+}
+
+static xmlNode *find_service(xmlNode *root, const char *servicename)
+{
+	return do_find_node(root, servicename, "service", "name");
+}
+
+static xmlNode *find_fs_resource(xmlNode *root, const char *name)
+{
+	return do_find_node(root, name, "fs", "name");
+}
+
+static xmlNode *find_script_resource(xmlNode *root, const char *name)
+{
+	return do_find_node(root, name, "script", "name");
+}
+
+static xmlNode *find_ip_resource(xmlNode *root, const char *name)
+{
+	return do_find_node(root, name, "ip", "name");
+}
+
 /* Print name=value pairs for a (n XML) node.
  * "ignore" is a string to ignore if present as a property (probably already printed on the main line)
  */
@@ -518,6 +570,79 @@ static void add_clusternode(xmlNode *root_element, struct option_info *ninfo,
 	}
 }
 
+static void add_clusterservice(xmlNode *root_element, struct option_info *ninfo,
+			    int argc, char **argv, int optindex)
+{
+	xmlNode *rm;
+	xmlNode *rs;
+	xmlNode *newnode;
+
+	xmlNode *newfs = NULL;
+	xmlNode *newfsscript;
+	xmlNode *newfsip;
+
+	rm = findnode(root_element, "rm");
+	if (!rm)
+		die("Can't find \"rm\" in %s\n", ninfo->configfile);
+
+	/* Don't allow duplicate service names */
+	if (find_service(rm, ninfo->name))
+		die("service %s already exists in %s\n", ninfo->name,
+				ninfo->configfile);
+
+	rs = findnode(rm, "resources");
+	if (ninfo->fs && (!rs || !find_fs_resource(rs, ninfo->fs)))
+		die("fs resource %s doesn't exist in %s\n", ninfo->fs,
+				ninfo->configfile);
+	if (ninfo->script && (!rs || !find_script_resource(rs, ninfo->script)))
+		die("script resource %s doesn't exist in %s\n", ninfo->script,
+				ninfo->configfile);
+	if (ninfo->ip_addr && (!rs || !find_ip_resource(rs, ninfo->ip_addr)))
+		die("ip resource %s doesn't exist in %s\n", ninfo->ip_addr,
+				ninfo->configfile);
+
+	/* Add the new service */
+	newnode = xmlNewNode(NULL, BAD_CAST "service");
+	xmlSetProp(newnode, BAD_CAST "name", BAD_CAST ninfo->name);
+	xmlSetProp(newnode, BAD_CAST "autostart", BAD_CAST ninfo->autostart);
+	if (ninfo->exclusive)
+		xmlSetProp(newnode, BAD_CAST "exclusive",
+				BAD_CAST ninfo->exclusive);
+	xmlSetProp(newnode, BAD_CAST "recovery", BAD_CAST ninfo->recovery);
+	xmlAddChild(rm, newnode);
+
+	/* Add the fs reference */
+	if (ninfo->fs)
+	{
+		newfs = xmlNewNode(NULL, BAD_CAST "fs");
+		xmlSetProp(newfs, BAD_CAST "ref", BAD_CAST ninfo->fs);
+		xmlAddChild(newnode, newfs);
+	}
+
+	/* Add the script reference */
+	if (ninfo->script)
+	{
+		newfsscript = xmlNewNode(NULL, BAD_CAST "script");
+		xmlSetProp(newfsscript, BAD_CAST "ref", BAD_CAST ninfo->script);
+		if (newfs)
+			xmlAddChild(newfs, newfsscript);
+		else
+			xmlAddChild(newnode, newfsscript);
+	}
+
+	/* Add the ip reference */
+	if (ninfo->ip_addr)
+	{
+		newfsip = xmlNewNode(NULL, BAD_CAST "ip");
+		xmlSetProp(newfsip, BAD_CAST "ref", BAD_CAST
+				ninfo->ip_addr);
+		if (newfs)
+			xmlAddChild(newfs, newfsip);
+		else
+			xmlAddChild(newnode, newfsip);
+	}
+}
+
 static xmlDoc *open_configfile(struct option_info *ninfo)
 {
 	xmlDoc *doc;
@@ -562,6 +687,28 @@ static void del_clusternode(xmlNode *root_element, struct option_info *ninfo)
 	xmlUnlinkNode(oldnode);
 }
 
+static void del_clusterservice(xmlNode *root_element, struct option_info *ninfo)
+{
+	xmlNode *rm;
+	xmlNode *oldnode;
+
+	rm = findnode(root_element, "rm");
+	if (!rm)
+	{
+		fprintf(stderr, "Can't find \"rm\" in %s\n", ninfo->configfile);
+		exit(1);
+	}
+
+	oldnode = find_service(rm, ninfo->name);
+	if (!oldnode)
+	{
+		fprintf(stderr, "service %s does not exist in %s\n", ninfo->name, ninfo->configfile);
+		exit(1);
+	}
+
+	xmlUnlinkNode(oldnode);
+}
+
 struct option addnode_options[] =
 {
       { "votes", required_argument, NULL, 'v'},
@@ -613,6 +760,25 @@ struct option create_options[] =
       { NULL, 0, NULL, 0 },
 };
 
+struct option addservice_options[] =
+{
+      { "autostart", required_argument, NULL, 'a'},
+      { "exclusive", required_argument, NULL, 'x'},
+      { "recovery", required_argument, NULL, 'r'},
+      { "fs", required_argument, NULL, 'f'},
+      { "script", required_argument, NULL, 's'},
+      { "ip", required_argument, NULL, 'i'},
+      { "outputfile", required_argument, NULL, 'o'},
+      { "configfile", required_argument, NULL, 'c'},
+      { NULL, 0, NULL, 0 },
+};
+
+struct option delservice_options[] =
+{
+      { "outputfile", required_argument, NULL, 'o'},
+      { "configfile", required_argument, NULL, 'c'},
+      { NULL, 0, NULL, 0 },
+};
 
 static int next_nodeid(int startid, int *nodeids, int nodecount)
 {
@@ -966,6 +1132,196 @@ void list_nodes(int argc, char **argv)
 	}
 }
 
+void add_service(int argc, char **argv)
+{
+	struct option_info ninfo;
+	int opt;
+	xmlDoc *doc;
+	xmlNode *root_element;
+
+	memset(&ninfo, 0, sizeof(ninfo));
+	ninfo.autostart = "1";
+	ninfo.recovery = "relocate";
+
+	while ( (opt = getopt_long(argc, argv, "a:x:r:f:o:c:s:i:CFh?", addservice_options, NULL)) != EOF)
+	{
+		switch(opt)
+		{
+		case 'a':
+			validate_int_arg(opt, optarg);
+			ninfo.autostart = optarg;
+			break;
+
+		case 'x':
+			validate_int_arg(opt, optarg);
+			ninfo.exclusive = optarg;
+			break;
+
+		case 'r':
+			ninfo.recovery = strdup(optarg);
+			break;
+
+		case 'f':
+			ninfo.fs = strdup(optarg);
+			break;
+
+		case 's':
+			ninfo.script = strdup(optarg);
+			break;
+
+		case 'i':
+			ninfo.ip_addr = strdup(optarg);
+			break;
+
+		case 'c':
+			ninfo.configfile = strdup(optarg);
+			break;
+
+		case 'o':
+			ninfo.outputfile = strdup(optarg);
+			break;
+
+		case '?':
+		default:
+			addservice_usage(argv[0]);
+		}
+	}
+
+	/* Get service name parameter */
+	if (optind < argc)
+		ninfo.name = strdup(argv[optind]);
+	else
+		addservice_usage(argv[0]);
+
+
+	doc = open_configfile(&ninfo);
+
+	root_element = xmlDocGetRootElement(doc);
+
+	increment_version(root_element);
+
+	add_clusterservice(root_element, &ninfo, argc, argv, optind);
+
+	/* Write it out */
+	save_file(doc, &ninfo);
+	/* Shutdown libxml */
+	xmlCleanupParser();
+
+}
+
+void del_service(int argc, char **argv)
+{
+	struct option_info ninfo;
+	int opt;
+	xmlDoc *doc;
+	xmlNode *root_element;
+
+	memset(&ninfo, 0, sizeof(ninfo));
+
+	while ( (opt = getopt_long(argc, argv, "o:c:CFh?", delservice_options, NULL)) != EOF)
+	{
+		switch(opt)
+		{
+		case 'c':
+			ninfo.configfile = strdup(optarg);
+			break;
+
+		case 'o':
+			ninfo.outputfile = strdup(optarg);
+			break;
+
+		case '?':
+		default:
+			delservice_usage(argv[0]);
+		}
+	}
+
+	/* Get service name parameter */
+	if (optind < argc)
+		ninfo.name = strdup(argv[optind]);
+	else
+		delservice_usage(argv[0]);
+
+	doc = open_configfile(&ninfo);
+
+	root_element = xmlDocGetRootElement(doc);
+
+	increment_version(root_element);
+
+	del_clusterservice(root_element, &ninfo);
+
+	/* Write it out */
+	save_file(doc, &ninfo);
+}
+
+void list_services(int argc, char **argv)
+{
+	xmlNode *cur_service;
+	xmlNode *root_element;
+	xmlNode *rm;
+	xmlDocPtr doc;
+	struct option_info ninfo;
+	int opt;
+	int verbose = 0;
+
+	memset(&ninfo, 0, sizeof(ninfo));
+
+	while ( (opt = getopt_long(argc, argv, "c:vh?", list_options, NULL)) != EOF)
+	{
+		switch(opt)
+		{
+		case 'c':
+			ninfo.configfile = strdup(optarg);
+			break;
+		case 'v':
+			verbose++;
+			break;
+		case '?':
+		default:
+			list_usage(argv[0]);
+		}
+	}
+	doc = open_configfile(&ninfo);
+
+	root_element = xmlDocGetRootElement(doc);
+
+
+	printf("\nCluster name: %s, config_version: %s\n\n",
+	       (char *)cluster_name(root_element),
+	       (char *)find_version(root_element));
+
+	rm = findnode(root_element, "rm");
+	if (!rm)
+		die("Can't find \"rm\" in %s\n", ninfo.configfile);
+
+	printf("Name                             Autostart Exclusive Recovery\n");
+	for (cur_service = rm->children; cur_service;
+			cur_service = cur_service->next)
+	{
+		xmlChar *name, *autostart, *exclusive, *recovery;
+
+		if (!cur_service->type == XML_ELEMENT_NODE ||
+			strcmp((char *)cur_service->name, "service") != 0)
+			continue;
+
+		name = xmlGetProp(cur_service, BAD_CAST "name");
+		autostart = xmlGetProp(cur_service, BAD_CAST "autostart");
+		exclusive = xmlGetProp(cur_service, BAD_CAST "exclusive");
+		recovery = xmlGetProp(cur_service, BAD_CAST "recovery");
+
+		if (!autostart)
+			autostart = (unsigned char *)"0";
+		if (!exclusive)
+			exclusive = (unsigned char *)"0";
+		if (!recovery)
+			recovery = (unsigned char *)"-";
+
+		printf("%-32s       %3d       %3d %s\n", name,
+			atoi((char *)autostart), atoi((char *)exclusive),
+			(char *)recovery);
+	}
+}
+
 void create_skeleton(int argc, char **argv)
 {
 	char *fencename = NULL;
diff --git a/config/tools/ccs_tool/editconf.h b/config/tools/ccs_tool/editconf.h
index 1847e2c..be8945e 100644
--- a/config/tools/ccs_tool/editconf.h
+++ b/config/tools/ccs_tool/editconf.h
@@ -1,8 +1,11 @@
 void add_node(int argc, char **argv);
 void add_nodeids(int argc, char **argv);
+void add_service(int argc, char **argv);
 void add_fence(int argc, char **argv);
 void del_node(int argc, char **argv);
+void del_service(int argc, char **argv);
 void del_fence(int argc, char **argv);
 void list_nodes(int argc, char **argv);
+void list_services(int argc, char **argv);
 void list_fences(int argc, char **argv);
 void create_skeleton(int argc, char **argv);
-- 
1.7.1



  reply	other threads:[~2010-12-10 13:42 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-12-10 13:42 [Cluster-devel] [PATCH 0/8] [STABLE31] sccs_tool enhancement Dmitry Mishin
2010-12-10 13:42 ` Dmitry Mishin [this message]
2010-12-10 14:49   ` [Cluster-devel] [PATCH 1/8] Add "service" object manipulations Lon Hohberger
2010-12-10 14:51     ` Lon Hohberger
2010-12-10 13:42 ` [Cluster-devel] [PATCH 2/8] Unify 'del' functions Dmitry Mishin
2010-12-10 13:42 ` [Cluster-devel] [PATCH 3/8] Add "script" object manipulations Dmitry Mishin
2010-12-10 13:42 ` [Cluster-devel] [PATCH 4/8] Unify parsing of options Dmitry Mishin
2010-12-10 13:42 ` [Cluster-devel] [PATCH 5/8] Added "ip" object manipulations Dmitry Mishin
2010-12-10 13:42 ` [Cluster-devel] [PATCH 6/8] Added 'fs' " Dmitry Mishin
2010-12-10 13:42 ` [Cluster-devel] [PATCH 7/8] Added 'failoverdomain' " Dmitry Mishin
2010-12-10 13:42 ` [Cluster-devel] [PATCH 8/8] Added ability to reference domains from services Dmitry Mishin
2010-12-10 14:17 ` [Cluster-devel] [PATCH 0/8] [STABLE31] sccs_tool enhancement Fabio M. Di Nitto
2010-12-15  8:06 ` Fabio M. Di Nitto
  -- strict thread matches above, loose matches on Subject: below --
2010-12-10  9:00 [Cluster-devel] [PATCH 0/8] ccs_tool enhancement Dmitry Mishin
2010-12-10  9:00 ` [Cluster-devel] [PATCH 1/8] Add "service" object manipulations Dmitry Mishin

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1291988557-22348-2-git-send-email-dim@parallels.com \
    --to=dim@parallels.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.