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

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



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/ldap/Makefile b/config/ldap/Makefile
new file mode 100644
index 0000000..da98efb
--- /dev/null
+++ b/config/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/ldap/cluster.schema b/config/ldap/cluster.schema
new file mode 100644
index 0000000..89e10b2
--- /dev/null
+++ b/config/ldap/cluster.schema
@@ -0,0 +1,57 @@
+# Cluster LDAP schema.
+# (c) 2008 Red Hat Inc
+# Christine Caulfield <ccaulfie redhat com>
+#
+
+# This file should be read at LDAP server startup
+# eg insert the following line into /etc/openldap/slapd.conf
+#
+#    include         /use/share/cluster/cluster.schema
+
+
+# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+# WARNING! the OID numbers here a mde up and NOT official!
+# I WILL fix this in the near future when I get an official assignment.
+# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+
+attributeType: (
+  42.3.6.1.1.1.1.0 NAME 'configversion'
+  DESC 'An integer describing the configuration version'
+  EQUALITY integerMatch
+  SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
+  SINGLE-VALUE
+  )
+attributeType: (
+  42.3.6.1.1.1.1.1 NAME 'nodeid'
+  DESC 'An integer describing the node ID number'
+  EQUALITY integerMatch
+  SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
+  SINGLE-VALUE
+  )
+attributeType: (
+  42.3.6.1.1.1.1.2 NAME 'clusterid'
+  DESC 'An integer describing the cluster ID number'
+  EQUALITY integerMatch
+  SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
+  SINGLE-VALUE
+  )
+attributeType: (
+  42.3.6.1.1.1.1.5 NAME 'votes'
+  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
+  )
+objectclass ( 
+     42.44.2.5.6.5 NAME 'rhcsCluster' SUP olcSchemaConfig STRUCTURAL
+     DESC 'Cluster top-level entry'
+     MUST ( name $ configversion )
+     MAY clusterid
+   )
+objectclass ( 
+     42.44.2.5.6.6 NAME 'rhcsNode' SUP top AUXILIARY
+     DESC 'Cluster node entry'
+     MUST ( name $ nodeid )
+     MAY votes
+   )
diff --git a/config/ldap/configldap.c b/config/ldap/configldap.c
new file mode 100644
index 0000000..5516504
--- /dev/null
+++ b/config/ldap/configldap.c
@@ -0,0 +1,226 @@
+/******************************************************************************
+*******************************************************************************
+**
+**  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 <syslog.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=redhat,dc=com"
+
+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;
+
+	/* We need to set this up to internal defaults too early */
+	openlog("openais", LOG_CONS|LOG_PID, LOG_LOCAL4);
+
+	/* Read low-level totem/aisexec etc config 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;
+
+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.
+	   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;
+}
+
+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: I need to fix this, and use sasl!!!
+	 */
+	rc = ldap_simple_bind_s( ld, NULL, NULL );
+	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;
+			}
+
+			/* 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]) {
+					/* Add a key - but ignore "objectClass" attributes! */
+					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++;
+				}
+
+				attr = ldap_next_attribute(ld, e, attr_ber);
+				ldap_value_free_len(val_ber);
+			}
+			ber_free(attr_ber, 0);
+		}
+	}
+	ldap_msgfree( result );
+
+	ldap_unbind( ld );
+	return( 0 );
+}
diff --git a/config/ldap/example.ldif b/config/ldap/example.ldif
new file mode 100644
index 0000000..251b612
--- /dev/null
+++ b/config/ldap/example.ldif
@@ -0,0 +1,70 @@
+# An example cluster.conf LDAP schema.
+# (c) 2008 Red Hat Inc
+# Christine Caulfield <ccaulfie redhat com>
+#
+# This adds three nodes, ford, arthur & jeltz to the configuration.
+#
+# The syntax is slightly odd for LDA because it doesn't allow multiple entries
+# with the same DN as XML does: 
+#   eg: cluster.conf uses 
+#       <clusternode name="xxx" nodeid="y"/>
+#       <clusternode name="vvv" nodeid="z"/>
+#
+# So the LDAP parser here checks for DNs starting 'name=' and removes the
+# 'name' portion when importing into the openais objdb. It also removes "cn="
+# and "objectClass=" entries as they just waste space when loaded.
+#
+
+dn: dc=redhat,dc=com
+objectClass: dcObject
+objectClass: olcSchemaConfig
+dc: redhat
+
+dn: cn=cluster,dc=redhat,dc=com
+cn: cluster
+objectClass: rhcsCluster
+objectClass: olcSchemaConfig
+name: cc_cluster
+configversion: 45
+
+
+dn: cn=cman,cn=cluster,dc=redhat,dc=com
+cn: cman
+objectClass: olcSchemaConfig
+
+
+dn: cn=totem,cn=cluster,dc=redhat,dc=com
+cn: totem
+objectClass: olcSchemaConfig
+
+
+dn: cn=clusternodes,cn=cluster,dc=redhat,dc=com
+cn: clusternodes
+objectClass: olcSchemaConfig
+
+
+dn: cn=clusternode,cn=clusternodes,cn=cluster,dc=redhat,dc=com
+cn: clusternode
+objectClass: olcSchemaConfig
+
+
+dn: name=jeltz,cn=clusternode,cn=clusternodes,cn=cluster,dc=redhat,dc=com
+objectClass: rhcsNode
+objectClass: olcSchemaConfig
+name: jeltz
+nodeid: 1
+votes: 2
+
+dn: name=arthur,cn=clusternode,cn=clusternodes,cn=cluster,dc=redhat,dc=com
+objectClass: rhcsNode
+objectClass: olcSchemaConfig
+name: arthur
+nodeid: 10
+votes: 1
+
+dn: name=ford,cn=clusternode,cn=clusternodes,cn=cluster,dc=redhat,dc=com
+objectClass: rhcsNode
+objectClass: olcSchemaConfig
+name: ford
+nodeid: 32
+votes: 1

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