Cluster Project branch, master, updated. cluster-2.99.05-23-gee712cf

ccaulfield@sourceware.org ccaulfield@sourceware.org
Thu Jun 26 16:25:00 GMT 2008


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Cluster Project".

http://sources.redhat.com/git/gitweb.cgi?p=cluster.git;a=commitdiff;h=ee712cf5e8d6213c509d1dc536dac70332ae63fe

The branch, master has been updated
       via  ee712cf5e8d6213c509d1dc536dac70332ae63fe (commit)
      from  a006cbd31804652e23ab5dde423b2b2e7fa03f76 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit ee712cf5e8d6213c509d1dc536dac70332ae63fe
Author: Christine Caulfield <ccaulfie@redhat.com>
Date:   Thu Jun 26 17:22:23 2008 +0100

    [CONFIG] Add ldap configurator
    
    This is an openais configuration plugin to read the cluster config
    from an LDAP server. A schema file is included that provides just
    enough information to get a cluster running, more will follow.
    
    There is also an example ldif file to show how to load the information
    into the database.
    
    The defaults are slightly odd at the moment, I'll fix those as it develops
    and document how to override them. In the mean time see the top of the
    source code.
    
    Signed-off-by: Christine Caulfield <ccaulfie@redhat.com>

-----------------------------------------------------------------------

Summary of changes:
 config/plugins/Makefile               |    2 +-
 config/plugins/ldap/99cluster.ldif    |  120 ++++++++++++++
 config/plugins/{xml => ldap}/Makefile |    8 +-
 config/plugins/ldap/configldap.c      |  284 +++++++++++++++++++++++++++++++++
 config/plugins/ldap/example.ldif      |   89 ++++++++++
 5 files changed, 497 insertions(+), 6 deletions(-)
 create mode 100644 config/plugins/ldap/99cluster.ldif
 copy config/plugins/{xml => ldap}/Makefile (71%)
 create mode 100644 config/plugins/ldap/configldap.c
 create mode 100644 config/plugins/ldap/example.ldif

diff --git a/config/plugins/Makefile b/config/plugins/Makefile
index 1305555..a067c80 100644
--- a/config/plugins/Makefile
+++ b/config/plugins/Makefile
@@ -1,4 +1,4 @@
 include ../../make/defines.mk
 include $(OBJDIR)/make/passthrough.mk
 
-SUBDIRS=xml
+SUBDIRS=xml ldap
diff --git a/config/plugins/ldap/99cluster.ldif b/config/plugins/ldap/99cluster.ldif
new file mode 100644
index 0000000..2f0091d
--- /dev/null
+++ b/config/plugins/ldap/99cluster.ldif
@@ -0,0 +1,120 @@
+# Schema for Red Hat cluster suite LDAP configuration
+# 2008, Christine Caulfield ccaulfie@redhat.com
+#
+# This schema is incomplete, and probably always will be
+#
+
+dn: cn=schema
+attributeTypes: (
+  1.3.6.1.4.1.2312.8.1.1.1 NAME 'rhcsConfig-version'
+  DESC 'An integer describing the configuration version'
+  EQUALITY integerMatch
+  SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
+  SINGLE-VALUE
+  )
+attributeTypes: (
+  1.3.6.1.4.1.2312.8.1.1.2 NAME 'rhcsNodeid'
+  DESC 'An integer describing the node ID number'
+  EQUALITY integerMatch
+  SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
+  SINGLE-VALUE
+  )
+attributeTypes: (
+  1.3.6.1.4.1.2312.8.1.1.3 NAME 'rhcsCluster-id'
+  DESC 'An integer describing the cluster ID number'
+  EQUALITY integerMatch
+  SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
+  SINGLE-VALUE
+  )
+attributeTypes: (
+  1.3.6.1.4.1.2312.8.1.1.4 NAME 'rhcsVotes'
+  DESC 'An integer describing the number of votes a node has'
+  EQUALITY integerMatch
+  SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
+  SINGLE-VALUE
+  )
+attributeTypes: (
+  1.3.6.1.4.1.2312.8.1.1.5 NAME 'rhcsTwo-node'
+  DESC 'set to 1 for two_node mode'
+  EQUALITY integerMatch
+  SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
+  SINGLE-VALUE
+  )
+attributeTypes: (
+  1.3.6.1.4.1.2312.8.1.1.6 NAME 'rhcsExpected-votes'
+  DESC 'An integer describing the number of votes expected for the whole cluster'
+  EQUALITY integerMatch
+  SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
+  SINGLE-VALUE
+  )
+attributeTypes: (
+  1.3.6.1.4.1.2312.8.1.1.7 NAME 'rhcsMax-queued'
+  DESC 'An integer describing the maximum number of outstanding client requests to cman'
+  EQUALITY integerMatch
+  SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
+  SINGLE-VALUE
+  )
+attributeTypes: (
+  1.3.6.1.4.1.2312.8.1.1.8 NAME 'rhcsToken'
+  DESC 'An integer describing the totem token timeout'
+  EQUALITY integerMatch
+  SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
+  SINGLE-VALUE
+  )
+attributeTypes: (
+  1.3.6.1.4.1.2312.8.1.1.9 NAME 'rhcsAgent'
+  DESC 'The fencing agent to use'
+  EQUALITY caseIgnoreIA5Match
+  SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+  SINGLE-VALUE
+  )
+attributeTypes: (
+  1.3.6.1.4.1.2312.8.1.1.10 NAME 'rhcsUsername'
+  DESC 'Username to log into the fencing agent'
+  EQUALITY caseIgnoreIA5Match
+  SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+  SINGLE-VALUE
+  )
+attributeTypes: (
+  1.3.6.1.4.1.2312.8.1.1.11 NAME 'rhcsPassword'
+  DESC 'Password to log into the fencing agent'
+  EQUALITY caseIgnoreIA5Match
+  SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+  SINGLE-VALUE
+  )
+attributeTypes: (
+  1.3.6.1.4.1.2312.8.1.1.12 NAME 'rhcsIpaddr'
+  DESC 'IP Address the fencing agent'
+  EQUALITY caseIgnoreIA5Match
+  SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+  SINGLE-VALUE
+  )
+objectClasses: ( 
+     1.3.6.1.4.1.2312.8.1.2.1 NAME 'rhcsCluster' SUP top STRUCTURAL
+     DESC 'Cluster top-level entry'
+     MUST ( cn $ name $ rhcsConfig-version )
+   )
+objectClasses: ( 
+     1.3.6.1.4.1.2312.8.1.2.2 NAME 'rhcsNode' SUP top STRUCTURAL
+     DESC 'Cluster node entry'
+     MUST ( name $ rhcsNodeid )
+     MAY rhcsVotes
+   )
+objectClasses: ( 
+     1.3.6.1.4.1.2312.8.1.2.3 NAME 'rhcsCman' SUP top STRUCTURAL
+     DESC 'Cluster node entry'
+     MUST ( cn $ name $ rhcsNodeid )
+     MAY ( rhcsCluster-id $ rhcsTwo-node $ rhcsExpected-votes $ rhcsMax-queued )
+   )
+objectClasses: ( 
+     1.3.6.1.4.1.2312.8.1.2.4 NAME 'rhcsTotem' SUP top STRUCTURAL
+     DESC 'Totem options'
+     MUST ( cn )
+     MAY ( rhcsToken )
+   )
+objectClasses: ( 
+     1.3.6.1.4.1.2312.8.1.2.5 NAME 'rhcsFencedevice' SUP top STRUCTURAL
+     DESC 'A Fence device'
+     MUST ( name $ rhcsAgent )
+     MAY ( rhcsIpaddr $ rhcsUsername $ rhcsPassword )
+   )
diff --git a/config/plugins/xml/Makefile b/config/plugins/ldap/Makefile
similarity index 71%
copy from config/plugins/xml/Makefile
copy to config/plugins/ldap/Makefile
index 9274336..efd764c 100644
--- a/config/plugins/xml/Makefile
+++ b/config/plugins/ldap/Makefile
@@ -1,4 +1,4 @@
-TARGET= config_xml.lcrso
+TARGET= config_ldap.lcrso
 
 LCRSOT=$(TARGET)
 
@@ -11,13 +11,11 @@ include $(OBJDIR)/make/install.mk
 include $(OBJDIR)/make/uninstall.mk
 
 CFLAGS += -fPIC
-CFLAGS += `xml2-config --cflags`
-CFLAGS += -I${cmanincdir}/../daemon
 CFLAGS += -I${incdir}
 
-LDFLAGS += `xml2-config --libs`
+LDFLAGS += -lldap
 
-OBJS=	config.o
+OBJS=	configldap.o
 
 ${TARGET}: ${OBJS}
 	$(CC) -shared -Wl,-soname,$@ -o $@ $^ $(LDFLAGS)
diff --git a/config/plugins/ldap/configldap.c b/config/plugins/ldap/configldap.c
new file mode 100644
index 0000000..9e718b1
--- /dev/null
+++ b/config/plugins/ldap/configldap.c
@@ -0,0 +1,284 @@
+/******************************************************************************
+*******************************************************************************
+**
+**  Copyright (C) 2008 Red Hat, Inc.  All rights reserved.
+**
+**  This copyrighted material is made available to anyone wishing to use,
+**  modify, copy, or redistribute it subject to the terms and conditions
+**  of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <netinet/in.h>
+#include <stdio.h>
+
+// CC: temp until I tame SASL ... is this necessary?
+#define LDAP_DEPRECATED 1
+#include <ldap.h>
+
+/* openais headers */
+#include <openais/service/objdb.h>
+#include <openais/service/swab.h>
+#include <openais/totem/totemip.h>
+#include <openais/totem/totempg.h>
+#include <openais/totem/aispoll.h>
+#include <openais/service/service.h>
+#include <openais/service/config.h>
+#include <openais/lcr/lcr_comp.h>
+#include <openais/service/swab.h>
+
+#define DEFAULT_LDAP_URL "ldap:///"
+#define DEFAULT_LDAP_BASEDN "cn=cluster,dc=chrissie,dc=net"
+
+static int ldap_readconfig(struct objdb_iface_ver0 *objdb, char **error_string);
+static int init_config(struct objdb_iface_ver0 *objdb, char *error_string);
+static char error_reason[1024];
+
+/*
+ * Exports the interface for the service
+ */
+
+static struct config_iface_ver0 ldapconfig_iface_ver0 = {
+	.config_readconfig        = ldap_readconfig
+};
+
+static struct lcr_iface ifaces_ver0[2] = {
+	{
+		.name		       	= "ldapconfig",
+		.version	       	= 0,
+		.versions_replace      	= 0,
+		.versions_replace_count	= 0,
+		.dependencies	       	= 0,
+		.dependency_count      	= 0,
+		.constructor	       	= NULL,
+		.destructor	       	= NULL,
+		.interfaces	       	= NULL,
+	}
+};
+
+static struct lcr_comp ldap_comp_ver0 = {
+	.iface_count				= 1,
+	.ifaces					= ifaces_ver0,
+};
+
+
+
+__attribute__ ((constructor)) static void ldap_comp_register(void) {
+	lcr_interfaces_set(&ifaces_ver0[0], &ldapconfig_iface_ver0);
+	lcr_component_register(&ldap_comp_ver0);
+};
+
+static int ldap_readconfig(struct objdb_iface_ver0 *objdb, char **error_string)
+{
+	int ret;
+
+	/* Read config tree from LDAP */
+	if (!(ret = init_config(objdb, error_reason)))
+	    sprintf(error_reason, "%s", "Successfully read config from LDAP\n");
+
+        *error_string = error_reason;
+
+	return ret;
+}
+
+/* Specify the search criteria here. */
+static char *ldap_url = DEFAULT_LDAP_URL;
+static char *ldap_basedn = DEFAULT_LDAP_BASEDN;
+
+/*
+ * Convert hyphens to underscores in all attribute names
+ */
+static void convert_underscores(char *s, int len)
+{
+	int j;
+
+	for (j=0; j < len; j++) {
+		if (s[j] == '-')
+			s[j] = '_';
+	}
+}
+
+static void convert_dn_underscores(LDAPDN dn)
+{
+	int i=0;
+
+	while (dn[i]) {
+		convert_underscores(dn[i][0][0].la_attr.bv_val, dn[i][0][0].la_attr.bv_len);
+		i++;
+	}
+}
+
+/*
+ * Return the parent object of a DN.
+ * Actually, this returns the LAST parent with that name. which should (!) be correct.
+ */
+static unsigned int find_parent(struct objdb_iface_ver0 *objdb, LDAPDN dn, int startdn)
+{
+	int i=startdn;
+	int gotstart=0;
+	int start=0, end=startdn;
+	unsigned int parent_handle = OBJECT_PARENT_HANDLE;
+	unsigned int object_handle=0;
+
+//	fprintf(stderr, "CC: find parent: startdn=%d\n", startdn);
+
+	/*
+	 * Find the start and end positions first.
+	 * start is where the 'cluster' entry is.
+	 * end   is the end of the list
+	 */
+	do {
+//		fprintf(stderr, "CC: %d: seen %s\n", i,dn[i][0][0].la_value.bv_val);
+		if (!gotstart && dn[i][0][0].la_value.bv_len == 7 &&
+		    !strncmp("cluster", dn[i][0][0].la_value.bv_val, 7)) {
+			gotstart = 1;
+			start = i;
+		}
+		i++;
+	} while (dn[i]);
+	if (start <= 0)
+		return parent_handle;
+
+//	fprintf(stderr, "CC: find parent: start=%d, end=%d\n", start, end);
+
+	for (i=start; i>=end; i--) {
+		objdb->object_find_reset(parent_handle);
+//		fprintf(stderr, "CC: %d: looking for %s\n", i,dn[i][0][0].la_value.bv_val);
+		if (!objdb->object_find(parent_handle,
+					dn[i][0][0].la_value.bv_val, dn[i][0][0].la_value.bv_len,
+					&object_handle)) {
+			parent_handle = object_handle;
+		}
+	}
+	return object_handle;
+}
+
+/* The real work starts here */
+static int init_config(struct objdb_iface_ver0 *objdb, char *error_string)
+{
+	LDAP *ld;
+	LDAPMessage *result, *e;
+	char *dn;
+	int version, rc;
+	unsigned int parent_handle = OBJECT_PARENT_HANDLE;
+	unsigned int object_handle;
+
+	if (getenv("LDAP_URL"))
+		ldap_url = getenv("LDAP_URL");
+	if (getenv("LDAP_BASEDN"))
+		ldap_basedn = getenv("LDAP_BASEDN");
+
+	/* Connect to the LDAP server */
+	if (ldap_initialize(&ld, ldap_url)) {
+		perror("ldap_initialize");
+		return -1;
+	}
+	version = LDAP_VERSION3;
+	ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &version);
+
+	/*
+	 * CC: Do I need to use sasl ?!
+	 */
+	rc = ldap_simple_bind_s(ld, getenv("LDAP_BINDDN"), getenv("LDAP_BINDPWD"));
+	if (rc != LDAP_SUCCESS) {
+		fprintf(stderr, "ldap_simple_bind_s: %s\n", ldap_err2string(rc));
+		return -1;
+	}
+
+	/* Search the whole tree from the base DN provided */
+	rc = ldap_search_ext_s(ld, ldap_basedn, LDAP_SCOPE_SUBTREE, "(objectClass=*)", NULL, 0,
+			       NULL, NULL, NULL, 0, &result);
+	if (rc != LDAP_SUCCESS) {
+		fprintf(stderr, "ldap_search_ext_s: %s\n", ldap_err2string(rc));
+		return 1;
+	}
+	for (e = ldap_first_entry(ld, result); e != NULL;
+	     e = ldap_next_entry(ld, e)) {
+		if ((dn = ldap_get_dn(ld, e)) != NULL) {
+			char *attr;
+			BerElement *attr_ber;
+			LDAPDN parsed_dn;
+
+			/* Make it parsable so we can discern the hierarchy */
+			if (ldap_str2dn(dn, &parsed_dn, LDAP_DN_PEDANTIC)) {
+				strcpy(error_reason, strerror(errno));
+				return -1;
+			}
+
+			/*
+			 * LDAP doesn't allow underscores in dn names so we replace hypens with
+			 * underscores so we can have thing like config_version, appear as
+			 * config-version in ldap
+			 */
+			convert_dn_underscores(parsed_dn);
+
+			/* Create a new object if the top-level is NOT name= */
+//			printf("CC: dn: %s\n", dn);
+			if (strncmp(parsed_dn[0][0][0].la_attr.bv_val, "name", 4)) {
+				parent_handle = find_parent(objdb, parsed_dn, 0);
+
+				objdb->object_create(parent_handle, &object_handle, parsed_dn[0][0][0].la_value.bv_val,
+						     parsed_dn[0][0][0].la_value.bv_len);
+			}
+			else {
+				parent_handle = find_parent(objdb, parsed_dn, 2);
+				/* Create a new object with the same name as the current one */
+				objdb->object_create(parent_handle, &object_handle, parsed_dn[1][0][0].la_value.bv_val,
+						     parsed_dn[1][0][0].la_value.bv_len);
+
+			}
+
+			/* Finished with the text representation */
+			ldap_memfree(dn);
+
+			/* Store the attributes as keys */
+			attr = ldap_first_attribute(ld, e, &attr_ber);
+			while (attr) {
+				int i;
+				struct berval **val_ber;
+
+				val_ber = ldap_get_values_len(ld, e, attr);
+				i=0;
+				while (val_ber[i]) {
+					/*
+					 * If the attribute starts "rhcs" then remove that bit
+					 * and make the first letter lower case so it matches the
+					 * cluster.conf entry.
+					 * so, after the above underscore change too:
+					 *   eg 'rhcsConfig-version' becomes 'config_version'. magic!
+					 */
+					if (strncmp(attr, "rhcs", 4) == 0) {
+						memmove(attr, attr+4, strlen(attr+4)+1);
+						attr[0] |= 0x60;
+					}
+					convert_underscores(attr, strlen(attr));
+
+					/*
+					 * Add a key - but ignore "objectClass" & "cn" attributes
+					 * as they don't provide anything we can use
+					 */
+					if (strcmp("objectClass", attr) &&
+					    strcmp("cn", attr))
+						objdb->object_key_create(object_handle, attr, strlen(attr),
+									 val_ber[i]->bv_val,
+									 val_ber[i]->bv_len+1);
+					i++;
+				}
+				ldap_memfree(attr);
+				attr = ldap_next_attribute(ld, e, attr_ber);
+				ldap_value_free_len(val_ber);
+			}
+			ldap_memfree(attr);
+			ber_free(attr_ber, 0);
+		}
+	}
+	ldap_msgfree(result);
+
+	ldap_unbind(ld);
+	return 0;
+}
diff --git a/config/plugins/ldap/example.ldif b/config/plugins/ldap/example.ldif
new file mode 100644
index 0000000..e7cb99d
--- /dev/null
+++ b/config/plugins/ldap/example.ldif
@@ -0,0 +1,89 @@
+
+# Example cluster LDIF file
+dn: cn=cluster,dc=chrissie,dc=net
+cn: cluster
+objectClass: rhcsCluster
+name: cc_cluster
+rhcsConfig-version: 1
+
+# Some cman parameters
+dn: cn=cman,cn=cluster,dc=chrissie,dc=net
+cn: cman
+objectClass: rhcsCman
+rhcsCluster-id: 444
+
+# Some totem parameters
+dn: cn=totem,cn=cluster,dc=chrissie,dc=net
+cn: totem
+objectClass: rhcsTotem
+rhcsToken: 21000
+
+# Define nodes
+dn: cn=clusternodes,cn=cluster,dc=chrissie,dc=net
+cn: clusternodes
+objectClass: nsContainer
+
+
+dn: cn=clusternode,cn=clusternodes,cn=cluster,dc=chrissie,dc=net
+cn: clusternode
+objectClass: nsContainer
+
+
+dn: name=jeltz,cn=clusternode,cn=clusternodes,cn=cluster,dc=chrissie,dc=net
+objectClass: rhcsNode
+name: jeltz
+rhcsNodeid: 1
+rhcsVotes: 2
+
+# Define a fence agent for this node ...!
+dn: cn=fence,name=jeltz,cn=clusternode,cn=clusternodes,cn=cluster,dc=chrissie,dc=net
+cn: fence
+objectclass: nsContainer
+
+dn: cn=method,cn=fence,name=jeltz,cn=clusternode,cn=clusternodes,cn=cluster,dc=chrissie,dc=net
+cn: method
+objectclass: nsContainer
+
+dn: name=apc,cn=method,cn=fence,name=jeltz,cn=clusternode,cn=clusternodes,cn=cluster,dc=chrissie,dc=net
+name: apc
+objectclass: nsContainer
+
+dn: cn=device,name=apc,cn=method,cn=fence,name=jeltz,cn=clusternode,cn=clusternodes,cn=cluster,dc=chrissie,dc=net
+cn: device
+objectclass: nsContainer
+
+dn: name=myapc,cn=device,name=apc,cn=method,cn=fence,name=jeltz,cn=clusternode,cn=clusternodes,cn=cluster,dc=chrissie,dc=net
+name: myapc
+objectclass: nsContainer
+port=4
+
+dn: name=arthur,cn=clusternode,cn=clusternodes,cn=cluster,dc=chrissie,dc=net
+objectClass: rhcsNode
+name: arthur
+rhcsNodeid: 10
+rhcsVotes: 1
+
+dn: name=ford,cn=clusternode,cn=clusternodes,cn=cluster,dc=chrissie,dc=net
+objectClass: rhcsNode
+name: ford
+rhcsNodeid: 32
+rhcsVotes: 1
+
+# Fence agent
+
+dn: cn=fencedevices,cn=cluster,dc=chrissie,dc=net
+cn: fencedevices
+objectClass: nsContainer
+
+dn: cn=fencedevice,cn=fencedevices,cn=cluster,dc=chrissie,dc=net
+cn: fencedevice
+objectClass: nsContainer
+
+
+dn: name=myapc,cn=fencedevice,cn=fencedevices,cn=cluster,dc=chrissie,dc=net
+objectClass: rhcsFencedevice
+name: myapc
+rhcsAgent: fence_apc
+rhcsIpaddr: myapc.chrissie.net
+rhcsUsername: apc
+rhcsPassword: apc
\ No newline at end of file


hooks/post-receive
--
Cluster Project



More information about the Cluster-cvs mailing list