[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

Re: [Cluster-devel] [RFC] [PATCH] LDAP support for cluster suite



Here's an updated patch. This works with Fedora Directory Server and has a few more options you can set.

--
Chrissie

Christine Caulfield wrote:
This code is EXTREMELY experimental. The OID numbers in the schema are totally fictitious and will probably conflict with something else (this will change).

I have tested it with a basic cman setup, but, in theory, it should be able to configure openais on its own or anything else if you can figure out how to load the data. It's been tested on an openldap server, results with other servers would be interesting, and I will do that too sometime later. It's taken me long enough to get enough of a handle on LDAP to get this far!

I'll check it into git when I've had a little more time to play with it and I've got some real OID numbers for you.

To use it, copy the config_ldap.lcrso into /usr/libexec/lcrso and start cman with

# cman_tool join -C ldapconfig -d

(-d is especially recommended!)

Feel free to try this code and email the list with any results good, or bad. But please don't come running to me if steals all your chocolates or dribbles red wine all down your best party frock.

Chrissie

diff --git a/config/Makefile b/config/Makefile
index e83caa3..3dca87a 100644
--- a/config/Makefile
+++ b/config/Makefile
@@ -14,4 +14,4 @@
 include ../make/defines.mk
 include $(OBJDIR)/make/passthrough.mk
 
-SUBDIRS=libs tools
+SUBDIRS=libs tools ldap
diff --git a/config/plugins/ldap/99cluster.ldif b/config/plugins/ldap/99cluster.ldif
new file mode 100644
index 0000000..00afbce
--- /dev/null
+++ b/config/plugins/ldap/99cluster.ldif
@@ -0,0 +1,81 @@
+# WARNING made up OID numbers
+dn: cn=schema
+attributeTypes: (
+  1.3.6.1.4.1.2312.8.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.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.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.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.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.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.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.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
+  )
+objectClasses: ( 
+     1.3.6.1.4.1.2312.8.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.2.2 NAME 'rhcsNode' SUP top AUXILIARY
+     DESC 'Cluster node entry'
+     MUST ( name $ rhcsNodeid )
+     MAY rhcsVotes
+   )
+objectClasses: ( 
+     1.3.6.1.4.1.2312.8.2.2 NAME 'rhcsCman' SUP top AUXILIARY
+     DESC 'Cluster node entry'
+     MUST ( cn $ name $ rhcsNodeid )
+     MAY ( rhcsCluster-id $ rhcsTwo_node $ rhcsExpeced_votes $ rhcsMax_queued )
+   )
+objectClasses: ( 
+     1.3.6.1.4.1.2312.8.2.3 NAME 'rhcsTotem' SUP top AUXILIARY
+     DESC 'Totem options'
+     MUST ( cn )
+     MAY ( rhcsToken )
+   )
diff --git a/config/plugins/ldap/Makefile b/config/plugins/ldap/Makefile
new file mode 100644
index 0000000..47d89b5
--- /dev/null
+++ b/config/plugins/ldap/Makefile
@@ -0,0 +1,39 @@
+###############################################################################
+###############################################################################
+##
+##  Copyright (C) 2004-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.
+##
+###############################################################################
+###############################################################################
+
+TARGET= config_ldap.lcrso
+
+LCRSOT=$(TARGET)
+
+all: depends ${TARGET}
+
+include ../../../make/defines.mk
+include $(OBJDIR)/make/cobj.mk
+include $(OBJDIR)/make/clean.mk
+include $(OBJDIR)/make/install.mk
+include $(OBJDIR)/make/uninstall.mk
+
+CFLAGS += -fPIC
+CFLAGS += -I${incdir}
+
+LDFLAGS += -lldap
+
+OBJS=	configldap.o
+
+${TARGET}: ${OBJS}
+	$(CC) -shared -Wl,-soname,$@ -o $@ $^ $(LDFLAGS)
+
+depends:
+
+clean: generalclean 
+
+-include $(OBJS:.o=.d)
diff --git a/config/plugins/ldap/configldap.c b/config/plugins/ldap/configldap.c
new file mode 100644
index 0000000..808af21
--- /dev/null
+++ b/config/plugins/ldap/configldap.c
@@ -0,0 +1,267 @@
+/******************************************************************************
+*******************************************************************************
+**
+**  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
+#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(LDAPDN dn)
+{
+	int i=0;
+	int j;
+
+	while (dn[i]) {
+		for (j=0; j < dn[i][0][0].la_attr.bv_len; j++)
+			if (dn[i][0][0].la_attr.bv_val[j] == '-')
+				dn[i][0][0].la_attr.bv_val[j] = '_';
+		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=0;
+	unsigned int parent_handle = OBJECT_PARENT_HANDLE;
+	unsigned int object_handle=0;
+
+	/*
+	 * Find the start and end positions first.
+	 * start is where the 'cluster' entry is.
+	 * end   is the end of the list
+	 */
+	do {
+		if (!gotstart && !strncmp("cluster", dn[i][0][0].la_value.bv_val, 7)) {
+			gotstart = 1;
+			start = i;
+		}
+		i++;
+	} while (dn[i]);
+	end = i-3;
+
+	for (i=end; i>=start; i--) {
+		objdb->object_find_reset(parent_handle);
+		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_underscores(parsed_dn);
+
+			/* Create a new object if the top-level is NOT name= */
+			printf("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;
+					}
+					/*
+					 * Add a key - but ignore "objectClass" & "cn" attributes
+					 * as the 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..26f3953
--- /dev/null
+++ b/config/plugins/ldap/example.ldif
@@ -0,0 +1,45 @@
+
+dn: cn=cluster,dc=chrissie,dc=net
+cn: cluster
+objectClass: rhcsCluster
+name: cc_cluster
+rhcsConfig-version: 45
+
+
+dn: cn=cman,cn=cluster,dc=chrissie,dc=net
+cn: cman
+objectClass: rhcsCman
+rhcsCluster-id: 444
+
+dn: cn=totem,cn=cluster,dc=chrissie,dc=net
+cn: totem
+objectClass: rhcsTotem
+
+
+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
+
+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

[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]