I'm attaching a patch against cobbler git (stable) to support an LDAP-backed
serializer.
It's mode of operation is as follows:
1. Read-only from inside the cobbler TUI/WUI
- Users must handle adding the desired values to LDAP
2. Custom schema must be manually installed into LDAP server(s), but you can
customize the mappings between LDAP attributes and the cobbler object variables
(e.g. rather than "name" = "cn", you can have "name" = "uid" or something).
There are some gotchas regarding the way inheritance/overlays work with LDAP,
though. In particular, it doesn't handle the the NULL = "" mapping that the
YAML serializers do.
It also doesn't completely handle the way "<<inherit>>" and default values work
in the YAML serializers yet, so cobbler sync doesn't really work. This is the
showstopper, but I don't know what kind of policy to pursue here:
Do I emulate the behavior of the TUI/WUI inside the LDAP serializer, or depend
on the user to do so by setting "<<inherit>>" manually?
--
James Cape
http://jcape.ignore-your.tv/
"If there’s one thing I know, it’s that managers have the least
information about every technical issue, and they are the last
people who should be deciding anything"
-- Joel Spolsky
diff --git a/cobbler/modules/serializer_ldap.py b/cobbler/modules/serializer_ldap.py
new file mode 100644
index 0000000..dbb88d4
--- /dev/null
+++ b/cobbler/modules/serializer_ldap.py
@@ -0,0 +1,676 @@
+"""
+Serializer code for cobbler
+
+Copyright 2008, James Cape
+James Cape <[email protected]>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA
+"""
+
+"""
+Hungarian Notation:
+
+b: Boolean
+n: Integer Count
+rgX: Range/array of X
+mpXY: Map of X to Y
+grABCD: Graph of A to B to C to D
+sldn: String LDAP distinguishedName
+slf: String LDAP Filter
+sla: String LDAP Attribute (name)
+slv: String LDAP Value
+suri: String URI
+sit: String Item Type
+sda: String Datastruct Attribute (property name)
+gdv: Generic Datastruct Value
+sdma: String datastruct metadata key
+gdmv: Generic datastruct metadata value
+
+"""
+
+# vim: tabstop=4 expandtab shiftwidth=4
+
+import distutils.sysconfig
+import os
+import sys
+import glob
+import traceback
+import pdb
+
+plib = distutils.sysconfig.get_python_lib()
+mod_path="%s/cobbler" % plib
+sys.path.insert(0, mod_path)
+
+from utils import _
+import utils
+import cexceptions
+import os
+import ldap
+import ldap.dn
+import re
+import cobbler.api
+
+class LdapSerializer:
+ bInitialized = False
+
+ __shared_state = {}
+ # Graph of item-type to datastruct name to metadata key/value
+ _grSitSdaSdmaGdmvMetadata = {
+ 'system': {
+ 'owners': {
+ 'type': 'multi',
+ },
+ 'name': {
+ 'type': 'single',
+ },
+
+ 'profile': {
+ 'type': 'single',
+ 'default': None
+ },
+ 'image': {
+ 'type': 'single',
+ 'default': None
+ },
+
+ 'kernel_options': {
+ 'type': 'pairs',
+ 'default': '<<inherit>>'
+ },
+ 'kernel_options_post': {
+ 'type': 'pairs',
+ 'default': '<<inherit>>'
+ },
+ 'kickstart': {
+ 'type': 'single',
+ 'default': '<<inherit>>'
+ },
+ 'ks_meta': {
+ 'type': 'pairs',
+ 'default': '<<inherit>>'
+ },
+
+ 'parent': {
+ 'type': 'single',
+ 'default': ''
+ },
+
+ 'server': {
+ 'type': 'single',
+ 'default': '<<inherit>>'
+ },
+
+ 'virt_cpus': {
+ 'type': 'single',
+ 'default': '<<inherit>>'
+ },
+ 'virt_file_size': {
+ 'type': 'single',
+ 'default': '<<inherit>>'
+ },
+ 'virt_path': {
+ 'type': 'single',
+ 'default': '<<inherit>>'
+ },
+ 'virt_ram': {
+ 'type': 'single',
+ 'default': '<<inherit>>'
+ },
+ 'virt_type': {
+ 'type': 'single',
+ 'default': '<<inherit>>'
+ }
+ },
+
+ 'interface': {
+ 'ip_address': {
+ 'type': 'single',
+ 'default': ''
+ },
+ 'mac_address': {
+ 'type': 'single',
+ 'default': ''
+ },
+ 'hostname': {
+ 'type': 'single',
+ 'default': ''
+ },
+ 'gateway': {
+ 'type': 'single',
+ 'default': ''
+ },
+ 'subnet': {
+ 'type': 'single',
+ 'default': ''
+ },
+ 'dhcp_tag': {
+ 'type': 'single',
+ 'default': ''
+ },
+ 'virt_bridge': {
+ 'type': 'single',
+ 'default': ''
+ },
+ },
+
+ 'profile': {
+ 'owners': {
+ 'type': 'multi',
+ },
+ 'name': {
+ 'type': 'single',
+ },
+
+ 'parent': {
+ 'type': 'single',
+ },
+ 'distro': {
+ 'type': 'single',
+ 'default': '<<inherit>>'
+ },
+
+ 'dhcp_tag': {
+ 'type': 'single',
+ 'default': '<<inherit>>'
+ },
+
+ 'kernel_options': {
+ 'type': 'pairs',
+ 'default': '<<inherit>>'
+ },
+ 'kernel_options_post': {
+ 'type': 'pairs',
+ 'default': '<<inherit>>'
+ },
+ 'kickstart': {
+ 'type': 'single',
+ 'default': '<<inherit>>',
+ 'topdef': None
+ },
+ 'ks_meta': {
+ 'type': 'pairs',
+ 'default': '<<inherit>>'
+ },
+
+ 'repos': {
+ 'type': 'multi',
+ 'default': '<<inherit>>'
+ },
+ 'server': {
+ 'type': 'single',
+ 'default': '<<inherit>>'
+ },
+
+ 'virt_bridge': {
+ 'type': 'single',
+ 'default': '<<inherit>>'
+ },
+ 'virt_cpus': {
+ 'type': 'single',
+ 'default': '<<inherit>>'
+ },
+ 'virt_file_size': {
+ 'type': 'single',
+ 'default': '<<inherit>>'
+ },
+ 'virt_path': {
+ 'type': 'single',
+ 'default': '<<inherit>>'
+ },
+ 'virt_ram': {
+ 'type': 'single',
+ 'default': '<<inherit>>'
+ },
+ 'virt_type': {
+ 'type': 'single',
+ 'default': '<<inherit>>'
+ }
+ },
+
+ 'image': {
+ 'owners': {
+ 'type': 'multi',
+ 'default': ''
+ },
+ 'name': {
+ 'type': 'single',
+ 'default': ''
+ },
+
+ 'breed': {
+ 'type': 'single',
+ 'default': ''
+ },
+ 'arch': {
+ 'type': 'single',
+ 'default': ''
+ },
+ 'os_version': {
+ 'type': 'single',
+ 'default': ''
+ },
+
+ 'file': {
+ 'type': 'single',
+ 'default': ''
+ },
+ 'image_type': {
+ 'type': 'single',
+ 'default': ''
+ },
+ 'xml_file': {
+ 'type': 'single',
+ 'default': ''
+ },
+
+ 'virt_bridge': {
+ 'type': 'single',
+ 'default': '<<inherit>>'
+ },
+ 'virt_cpus': {
+ 'type': 'single',
+ 'default': '<<inherit>>'
+ },
+ 'virt_file_size': {
+ 'type': 'single',
+ 'default': '<<inherit>>'
+ },
+ 'virt_path': {
+ 'type': 'single',
+ 'default': '<<inherit>>'
+ },
+ 'virt_ram': {
+ 'type': 'single',
+ 'default': '<<inherit>>'
+ },
+ 'virt_type': {
+ 'type': 'single',
+ 'default': '<<inherit>>'
+ }
+ },
+
+ 'distro': {
+ 'owners': {
+ 'type': 'multi',
+ 'default': ''
+ },
+ 'name': {
+ 'type': 'single',
+ 'default': ''
+ },
+
+ 'breed': {
+ 'type': 'single',
+ 'default': ''
+ },
+ 'arch': {
+ 'type': 'single',
+ 'default': ''
+ },
+ 'os_version': {
+ 'type': 'single',
+ 'default': ''
+ },
+
+ 'initrd': {
+ 'type': 'single',
+ 'default': ''
+ },
+ 'kernel': {
+ 'type': 'single',
+ 'default': ''
+ },
+
+ 'kernel_options': {
+ 'type': 'pairs',
+ 'default': {}
+ },
+ 'kernel_options_post': {
+ 'type': 'pairs',
+ 'default': {}
+ },
+ 'ks_meta': {
+ 'type': 'pairs',
+ 'default': {}
+ }
+ },
+
+ 'repo': {
+ 'owners': {
+ 'type': 'multi',
+ 'default': ''
+ },
+ 'name': {
+ 'type': 'single',
+ 'default': ''
+ },
+ 'arch': {
+ 'type': 'single',
+ 'default': ''
+ },
+ 'createrepo_flags': {
+ 'type': 'single',
+ 'default': '-c cache'
+ },
+ 'keep_updated': {
+ 'type': 'single',
+ 'default': True
+ },
+ 'mirror': {
+ 'type': 'single',
+ 'default': ''
+ },
+ 'mirror_locally': {
+ 'type': 'single',
+ 'default': True
+ },
+ 'priority': {
+ 'type': 'single',
+ 'default': ''
+ },
+ 'rpm_list': {
+ 'type': 'single',
+ 'default': ''
+ },
+ 'yumopts': {
+ 'type': 'single',
+ 'default': ''
+ },
+ }
+ }
+ _mpSitRgSdaParents = {
+ 'system': [ 'parent', 'profile', 'image' ],
+ 'profile': [ 'parent', 'distro' ],
+ 'distro': [ 'parent' ],
+ 'image': [ 'parent' ],
+ 'repo': [ 'parent' ]
+ }
+
+ def __init__( self ):
+ """
+ Constructor, initializes the static class and opens the LDAP connection.
+ """
+
+ self.__dict__ = LdapSerializer.__shared_state
+
+ if not LdapSerializer.bInitialized:
+ LdapSerializer.bInitialized = True
+
+ self._settings = cobbler.api.BootAPI().settings()
+
+ bTls = False
+ if self._settings.ldap_port == '636':
+ usLdapServer = "ldaps://%s" % self._settings.ldap_server
+ else:
+ usLdapServer = "ldap://%s:%s" % ( self._settings.ldap_server, self._settings.ldap_port )
+
+ if str( self._settings.ldap_tls ).lower() in [ "on", "true", "yes", "1" ]:
+ bTls = True
+
+ self._cxnLdap = ldap.initialize( usLdapServer )
+
+ if bTls is True:
+ try:
+ self._cxnLdap.start_tls_s()
+ except:
+ traceback.print_exc()
+ return
+
+ if str( self._settings.ldap_anonymous_bind ).lower() not in [ "on", "true", "yes", "1" ]:
+ if self._settings.ldap_search_bind_dn == '' or self._settings.ldap_search_passwd == '':
+ raise "Explicit bind requested, but no bind DN or password given"
+
+ try:
+ self._cxnLdap.simple_bind_s( self._settings.ldap_search_bind_dn,
+ self._settings.ldap_search_passwd )
+ except:
+ traceback.print_exc()
+ return
+
+ return
+
+ def _get_item_base_dn( self, sitName ):
+ """
+ Retrieves the appropriate LDAP search base for the given Item Type
+ """
+
+ sldnRetval = self._settings.ldap_bases[ sitName ]
+ if sldnRetval[ -1 ] == ',':
+ sldnRetval = sldnRetval + self._settings.ldap_base_dn
+
+ return sldnRetval
+
+ def _get_filter_str( self, sitName, slvItemName=None ):
+ """
+ Retrieves the appropriate LDAP query filter for an item with the given name and type.
+ If the name is None, then the filter for the entire collection type is returned.
+ """
+
+ slfRetval = self._settings.ldap_filters[ sitName ]
+
+ # If we're given a particular name, modify the filter to search for that name
+ if slvItemName is not None:
+ slfRetval = "(&(%s=%s)%s)" % ( self._settings.ldap_attr_map[ sitName ][ 'name' ], slvItemName, slfRetval )
+
+ return slfRetval
+
+ def _recurse_item_depth( self, sitName, mpSlaRgSlvEntry, nDepth ):
+ """
+ Walks up the tree via LDAP searches to calculate the depth of a given item.
+ """
+
+ nStartDepth = nDepth
+ if sitName == "repo":
+ nDepth = 2
+ else:
+ for sdaParent in self._mpSitRgSdaParents[ sitName ]:
+ slaParent = self._settings.ldap_attr_map[ sitName ][ sdaParent ]
+
+ if mpSlaRgSlvEntry.has_key( slaParent ):
+ if sdaParent == 'parent':
+ sitSearchName = sitName
+ else:
+ sitSearchName = sdaParent
+
+ rgSlaParentAttrlist = [ self._settings.ldap_attr_map[ sitSearchName ][ 'name' ] ]
+ for sdaParentAttr in self._mpSitRgSdaParents[ sitSearchName ]:
+ rgSlaParentAttrlist.append( self._settings.ldap_attr_map[ sitSearchName ][ sdaParentAttr ] )
+
+ rgMpSlaRgSlvParents = self._cxnLdap.search_ext_s( base=self._get_item_base_dn( sitSearchName ),
+ scope=ldap.SCOPE_SUBTREE,
+ filterstr=self._get_filter_str( sitSearchName, mpSlaRgSlvEntry[ slaParent ][ 0 ] ),
+ attrlist=rgSlaParentAttrlist,
+ sizelimit=1 )
+
+ if len( rgMpSlaRgSlvParents ) > 0:
+ return self._recurse_item_depth( sitSearchName, rgMpSlaRgSlvParents[ 0 ][ 1 ], nDepth + 1 )
+
+ # Top of the tree
+ return nDepth
+
+ def _mpSlaRgSlvToMpSdaGdv( self, mpSlaRgSlvEntry, sitName ):
+ """
+ Parses the given LDAP entry into a YAML-style datastruct
+ """
+ mpSdaGdvRetval = {}
+ mpSdaGdvRetval[ 'depth' ] = self._recurse_item_depth( sitName, mpSlaRgSlvEntry, 0 )
+
+ # Parse the LDAP return into the result struct.
+ for ( sdaName, mpSdmaGdmvMetadata ) in self._grSitSdaSdmaGdmvMetadata[ sitName ].iteritems():
+ assert self._settings.ldap_attr_map.has_key( sitName )
+ assert self._settings.ldap_attr_map[ sitName ].has_key( sdaName )
+
+ slaName = self._settings.ldap_attr_map[ sitName ][ sdaName ]
+ if mpSlaRgSlvEntry.has_key( slaName ):
+ if mpSdmaGdmvMetadata[ 'type' ] == "single":
+ mpSdaGdvRetval[ sdaName ] = mpSlaRgSlvEntry[ slaName ][ 0 ]
+
+ elif mpSdmaGdmvMetadata[ 'type' ] == "pairs":
+ mpSdaGdvRetval[ sdaName ] = {}
+
+ for strVarPair in mpSlaRgSlvEntry[ slaName ]:
+ if strVarPair.find( '=' ) is not -1:
+ ( strVarKey, strVarValue ) = strVarPair.split( '=', 2 )
+ else:
+ strVarKey = strVarPair
+ strVarValue = None
+
+ mpSdaGdvRetval[ sdaName ][ strVarKey ] = strVarValue
+
+ elif mpSdmaGdmvMetadata[ 'type' ] == "bool":
+ mpSdaGdvRetval[ sdaName ] = ( mpSlaRgSlvEntry[ slaName ][ 0 ] )
+
+ elif mpSdmaGdmvMetadata[ 'type' ] == "multi":
+ if not mpSdaGdvRetval.has_key( sdaName ):
+ mpSdaGdvRetval[ sdaName ] = []
+
+ for strVarValue in mpSlaRgSlvEntry[ slaName ]:
+ mpSdaGdvRetval[ sdaName ].append( strVarValue )
+
+ elif mpSdmaGdmvMetadata.has_key( 'default' ):
+ mpSdaGdvRetval[ sdaName ] = mpSdmaGdmvMetadata[ 'default' ]
+
+ if sitName == "system":
+ # If this is a system record attempt, parse the interface substruct as well
+ regValueParser = re.compile( "^\{(\d+)\}(\S+)" )
+
+ for ( sdaName, mpSdmaGdmvMetadata ) in self._grSitSdaSdmaGdmvMetadata[ 'interface' ].iteritems():
+ assert self._settings.ldap_attr_map.has_key( 'interface' )
+ assert self._settings.ldap_attr_map[ 'interface' ].has_key( sdaName )
+
+ slaName = self._settings.ldap_attr_map[ 'interface' ][ sdaName ]
+ if mpSlaRgSlvEntry.has_key( slaName ):
+ for strValue in mpSlaRgSlvEntry[ slaName ]:
+ rmoMatch = regValueParser.match( strValue )
+
+ if rmoMatch is not None:
+ strVar = "intf%d" % int( rmoMatch.group( 1 ) )
+ strValue = rmoMatch.group( 2 )
+ else:
+ strVar = "intf0"
+
+ if not mpSdaGdvRetval.has_key( 'interfaces' ):
+ mpSdaGdvRetval[ 'interfaces' ] = {}
+
+ if not mpSdaGdvRetval[ 'interfaces' ].has_key( strVar ):
+ mpSdaGdvRetval[ 'interfaces' ][ strVar ] = {}
+
+ mpSdaGdvRetval[ 'interfaces' ][ strVar ][ sdaName ] = strValue
+ # Interfaces have no default values per-se, they should be blank if NULL
+
+ return mpSdaGdvRetval
+
+ def __depth_cmp( self, mpItem1, mpItem2 ):
+ """
+ Compares two YAML-style datastructs based on their "depth" members.
+ """
+ if not mpItem1.has_key( "depth" ):
+ return 1
+
+ if not mpItem2.has_key( "depth" ):
+ return -1
+
+ return cmp( mpItem1[ "depth" ], mpItem2[ "depth" ] )
+
+ def deserialize_item_raw( self, sitName, strItemName ):
+ """
+ Retrieves the datastruct for an item in the given collection, with the given name
+ """
+
+ try:
+ rgMpSlaRgSlvEntries = self._cxnLdap.search_ext_s( base=self._get_item_base_dn( sitName ),
+ scope=ldap.SCOPE_SUBTREE,
+ filterstr=self._get_filter_str( sitName, strItemName ),
+ sizelimit=1 )
+ except:
+ traceback.print_exc()
+ return None
+
+ if len( rgEntries ) == 0:
+ return None
+
+ return self._mpSlaRgSlvToMpSdaGdv( rgMpSlaRgSlvEntries[ 0 ][ 1 ], sitName )
+
+ def deserialize_raw( self, sitName ):
+ """
+ Retrieves a list of YAML-style datastructs of all items with the given collection type
+ """
+
+ try:
+ rgMpSlaRgSlvEntries = self._cxnLdap.search_s( base=self._get_item_base_dn( sitName ),
+ scope=ldap.SCOPE_SUBTREE,
+ filterstr=self._get_filter_str( sitName ) )
+ except:
+ traceback.print_exc()
+ return []
+
+ rgMpSdaGdvRetval = []
+ for ( sldnName, mpSlaRgSlvEntry ) in rgMpSlaRgSlvEntries:
+ rgMpSdaGdvRetval.append( self._mpSlaRgSlvToMpSdaGdv( mpSlaRgSlvEntry, sitName ) )
+
+ return rgMpSdaGdvRetval
+
+ def deserialize( self, obj, bTopological=False ):
+ """
+ Loads and applies the appropriate datastruct to the given object
+ """
+
+ if hasattr( obj, "name" ) and obj.name is not None:
+ mpSdaSvvDatastruct = self.deserialize_item_raw( obj.collection_type(), obj.name )
+ obj.from_datastruct( mpSdaSvvDatastruct )
+ return True
+ else:
+ rgMpSdaSvvDatastruct = self.deserialize_raw( obj.collection_type() )
+ if bTopological and type( rgMpSdaSvvDatastruct ) == list:
+ rgMpSdaSvvDatastruct.sort( self.__depth_cmp )
+
+ obj.from_datastruct( rgMpSdaSvvDatastruct )
+
+ return True
+
+
+# ############ #
+# PUBLIC API #
+# ############ #
+def register():
+ """
+ The mandatory cobbler module registration hook.
+ """
+ return "serializer"
+
+def serialize_item( obj, objItem ):
+ return False
+
+def serialize_delete( obj, strItemName ):
+ return False
+
+def deserialize_item_raw( strCollectionType, strItemName ):
+ return LdapSerializer().deserialize_item_raw( strCollectionType, strItemName )
+
+def serialize(obj):
+ return False
+
+def deserialize_raw( strCollectionType ):
+ return LdapSerializer().deserialize_raw( strCollectionType )
+
+def deserialize( obj, bTopological=False ):
+ return LdapSerializer().deserialize( obj, bTopological )
+
+if __name__ == "__main__":
+ if len( sys.argv ) > 2:
+ print deserialize_item_raw( sys.argv[ 1 ], sys.argv[ 2 ] )
+ else:
+ print deserialize_raw( sys.argv[ 1 ] )
diff --git a/cobbler/settings.py b/cobbler/settings.py
index f9da4d6..aacbb5e 100644
--- a/cobbler/settings.py
+++ b/cobbler/settings.py
@@ -26,6 +26,8 @@ from utils import _
TESTMODE = False
+# vim: tabstop=8 expandtab shiftwidth=4
+
# defaults is to be used if the config file doesn't contain the value
# we need.
@@ -55,6 +57,111 @@ DEFAULTS = {
"ldap_search_bind_dn" : '',
"ldap_search_passwd" : '',
"ldap_search_prefix" : 'uid=',
+ "ldap_bases" : {
+ "system" : "ou=Hosts,",
+ "profile" : "ou=Profiles,",
+ "image" : "ou=Images,",
+ "distro" : "ou=Distros,",
+ "repo" : "ou=Repos,"
+ },
+ "ldap_filters" : {
+ "system" : "(objectClass=cobblerSystem)",
+ "profile" : "(objectClass=cobblerProfile)",
+ "image" : "(objectClass=cobblerImage)",
+ "distro" : "(objectClass=cobblerDistro)",
+ "repo" : "(objectClass=cobblerRepo)",
+ },
+ "ldap_attr_map" : {
+ "system" : {
+ "name" : "cn",
+ "owners" : "owner",
+ "profile" : "cobblerProfileName",
+ "image" : "cobblerImageName",
+ "kernel_options" : "cobblerKernelOptions",
+ "kernel_options_post" : "cobblerKernelOptionsPost",
+ "kickstart" : "cobblerKickstart",
+ "ks_meta" : "cobblerKickstartMetadata",
+ "parent" : "cobblerSystemName",
+ "server" : "cobblerServer",
+ "virt_cpus" : "cobblerVirtCpus",
+ "virt_file_size" : "cobblerVirtFileSize",
+ "virt_path" : "cobblerVirtPath",
+ "virt_ram" : "cobblerVirtRam",
+ "virt_type" : "cobblerVirtType"
+ },
+ "interface" : {
+ "ip_address" : "ipHostNumber",
+ "mac_address" : "macAddress",
+ "hostname" : "host",
+ "gateway" : "cobblerGatewayNumber",
+ "subnet" : "cobblerNetmaskNumber",
+ "dhcp_tag" : "cobblerDhcpTag",
+ "virt_bridge" : "cobblerVirtBridge"
+ },
+ "profile" : {
+ "name" : "cn",
+ "owners" : "owner",
+ "dhcp_tag" : "cobblerDhcpTag",
+ "distro" : "cobblerDistroName",
+ "kernel_options" : "cobblerKernelOptions",
+ "kernel_options_post" : "cobblerKernelOptionsPost",
+ "kickstart" : "cobblerKickstart",
+ "ks_meta" : "cobblerKickstartMetadata",
+ "parent" : "cobblerProfileName",
+ "server" : "cobblerServer",
+ "repos" : "cobblerRepoName",
+ "virt_bridge" : "cobblerVirtBridge",
+ "virt_cpus" : "cobblerVirtCpus",
+ "virt_file_size" : "cobblerVirtFileSize",
+ "virt_path" : "cobblerVirtPath",
+ "virt_ram" : "cobblerVirtRam",
+ "virt_type" : "cobblerVirtType"
+ },
+ "image" : {
+ "name" : "cn",
+ "owners" : "owner",
+ "breed" : "cobblerBreed",
+ "arch" : "cobblerArchitecture",
+ "os_version" : "cobblerOsVersion",
+ "file" : "cobblerImageFile",
+ "image_type" : "cobblerImageType",
+ "parent" : "cobblerImageName",
+ "virt_bridge" : "cobblerVirtBridge",
+ "virt_cpus" : "cobblerVirtCpus",
+ "virt_file_size" : "cobblerVirtFileSize",
+ "virt_path" : "cobblerVirtPath",
+ "virt_ram" : "cobblerVirtRam",
+ "virt_type" : "cobblerVirtType",
+ "xml_file" : "cobblerImageXmlFile"
+ },
+ "distro" : {
+ "name" : "cn",
+ "owners" : "owner",
+ "arch" : "cobblerArchitecture",
+ "breed" : "cobblerBreed",
+ "os_version" : "cobblerOsVersion",
+ "initrd" : "cobblerInitrd",
+ "kernel" : "cobblerKernel",
+ "kernel_options" : "cobblerKernelOptions",
+ "kernel_options_post" : "cobblerKernelOptionsPost",
+ "kickstart" : "cobblerKickstart",
+ "ks_meta" : "cobblerKickstartMetadata",
+ "parent" : "cobblerDistroName"
+ },
+ "repo" : {
+ "name" : "cn",
+ "owners" : "owner",
+ "arch" : "cobblerArchitecture",
+ "createrepo_flags" : "cobblerCreaterepoFlags",
+ "keep_updated" : "cobblerKeepUpdated",
+ "mirror" : "cobblerMirrorURI",
+ "mirror_locally" : "cobblerMirrorLocally",
+ "parent" : "cobblerRepoName",
+ "priority" : "cobblerPriority",
+ "rpm_list" : "cobblerRpmList",
+ "yumopts" : "cobblerYumOptions"
+ },
+ },
"kerberos_realm" : "EXAMPLE.COM",
"kernel_options" : {
"lang" : " ",
diff --git a/config/settings b/config/settings
index ae4e676..a48fa7b 100644
--- a/config/settings
+++ b/config/settings
@@ -63,9 +63,10 @@ kernel_options:
lang: ' '
text: ~
-# configuration options if using the authn_ldap module. See the
-# the Wiki for details. This can be ignored if you are not using
-# LDAP for WebUI/XMLRPC authentication.
+# configuration options if using the authn_ldap module or LDAP
+# serialization. See the the Wiki for details. This can be ignored if
+# you are not using LDAP for WebUI/XMLRPC authentication or as a
+# data store.
ldap_server: "ldap.example.com"
ldap_base_dn: "DC=example,DC=com"
ldap_port: 389
@@ -73,8 +74,105 @@ ldap_tls: 1
ldap_anonymous_bind: 1
ldap_search_bind_dn: ''
ldap_search_passwd: ''
+
+# authn_ldap-specific options
ldap_search_prefix: 'uid='
+# LDAP serializer-specific options, override if using a different
+# schema than the one that ships with cobbler.
+#
+#ldap_filters:
+# system: '(objectClass=cobblerSystem)'
+# profile: '(objectClass=cobblerProfile)'
+# image: '(objectClass=cobblerImage)'
+# distro: '(objectClass=cobblerDistro)'
+# repo: '(objectClass=cobblerRepo)'
+#
+#ldap_attr_map:
+# system:
+# name: cn
+# owners: owner
+# profile: cobblerProfileName
+# image: cobblerImageName
+# kernel_options: cobblerKernelOptions
+# kernel_options_post: cobblerKernelOptionsPost
+# kickstart: cobblerKickstart
+# ks_meta: cobblerKickstartMetadata
+# parent: cobblerSystemName
+# server: cobblerServer
+# virt_cpus: cobblerVirtCpus
+# virt_file_size: cobblerVirtFileSize
+# virt_path: cobblerVirtPath
+# virt_ram: cobblerVirtRam
+# virt_type: cobblerVirtType
+# interface:
+# ip_address: ipHostNumber
+# mac_address: macAddress
+# hostname: host
+# gateway: cobblerGatewayNumber
+# subnet: cobblerNetmaskNumber
+# dhcp_tag: cobblerDhcpTag
+# virt_bridge: cobblerVirtBridge
+# profile:
+# name: cn
+# owners: owner
+# dhcp_tag: cobblerDhcpTag
+# distro: cobblerDistroName
+# kernel_options: cobblerKernelOptions
+# kernel_options_post: cobblerKernelOptionsPost
+# kickstart: cobblerKickstart
+# ks_meta: cobblerKickstartMetadata
+# parent: cobblerProfileName
+# repos: cobblerRepoName
+# server: cobblerServer
+# virt_bridge: cobblerVirtBridge
+# virt_cpus: cobblerVirtCpus
+# virt_file_size: cobblerVirtFileSize
+# virt_path: cobblerVirtPath
+# virt_ram: cobblerVirtRam
+# virt_type: cobblerVirtType
+# image:
+# name: cn
+# owners: owner
+# breed: cobblerBreed
+# arch: cobblerArchitecture
+# os_version: cobblerOsVersion
+# file: cobblerImageFile
+# image_type: cobblerImageType
+# parent: cobblerImageName
+# virt_bridge: cobblerVirtBridge
+# virt_cpus: cobblerVirtCpus
+# virt_file_size: cobblerVirtFileSize
+# virt_path: cobblerVirtPath
+# virt_ram: cobblerVirtRam
+# virt_type: cobblerVirtType
+# xml_file: cobblerImageXmlFile
+# distro:
+# name: cn
+# owners: owner
+# arch: cobblerArchitecture
+# breed: cobblerBreed
+# os_version: cobblerOsVersion
+# initrd: cobblerInitrd
+# kernel: cobblerKernel
+# kernel_options: cobblerKernelOptions
+# kernel_options_post: cobblerKernelOptionsPost
+# kickstart: cobblerKickstart
+# ks_meta: cobblerKickstartMetadata
+# parent: cobblerDistroName
+# repo:
+# name: cn
+# owners: owner
+# arch: cobblerArchitecture
+# createrepo_flags: cobblerCreaterepoFlags
+# keep_updated: cobblerKeepUpdated
+# mirror: cobblerMirrorURI
+# mirror_locally: cobblerMirrorLocally
+# parent: cobblerRepoName
+# priority: cobblerPriority
+# rpm_list: cobblerRpmList
+# yumopts: cobblerYumOptions
+
# set to 1 to enable Cobbler's DHCP management features.
# the choice of DHCP management engine is in /etc/cobbler/modules.conf
manage_dhcp: 0
diff --git a/contrib/ldap/cobbler.schema b/contrib/ldap/cobbler.schema
new file mode 100644
index 0000000..d8ab006
--- /dev/null
+++ b/contrib/ldap/cobbler.schema
@@ -0,0 +1,304 @@
+#
+# OpenLDAP schema file for Cobbler
+# Save as /etc/openldap/schema/cobbler.schema
+#
+
+objectIdentifier cobblerAttributes 1.3.6.1.4.1.31747.1.2
+objectIdentifier cobblerClasses 1.3.6.1.4.1.31747.2.2
+
+attributetype ( cobblerAttributes:1
+ NAME 'cobblerArchitecture'
+ DESC 'Cobbler Architecture'
+ EQUALITY caseExactMatch
+ SUBSTR caseExactSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
+
+attributetype ( cobblerAttributes:2
+ NAME 'cobblerBreed'
+ DESC 'Cobbler Distribution Breed'
+ EQUALITY caseExactMatch
+ SUBSTR caseExactSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
+
+attributetype ( cobblerAttributes:3
+ NAME 'cobblerCreaterepoFlags'
+ DESC 'Cobbler Createrepo Command-line Arguments'
+ EQUALITY caseExactMatch
+ SUBSTR caseExactSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
+
+attributetype ( cobblerAttributes:4
+ NAME 'cobblerDhcpTag'
+ DESC 'Cobbler DHCP Tag'
+ EQUALITY caseExactMatch
+ SUBSTR caseExactSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
+
+attributetype ( cobblerAttributes:5
+ NAME 'cobblerDistroName'
+ DESC 'Cobbler Parent Distribution Name'
+ EQUALITY caseExactMatch
+ SUBSTR caseExactSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
+
+attributetype ( cobblerAttributes:6
+ NAME 'cobblerGatewayNumber'
+ DESC 'Cobbler Interface Gateway IP Address'
+ EQUALITY caseIgnoreIA5Match
+ SUBSTR caseIgnoreIA5SubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{128} )
+
+attributetype ( cobblerAttributes:7
+ NAME 'cobblerImageFile'
+ DESC 'Cobbler image filename'
+ EQUALITY caseExactMatch
+ SUBSTR caseExactSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
+
+attributetype ( cobblerAttributes:8
+ NAME 'cobblerImageName'
+ DESC 'Cobbler Profile Name'
+ EQUALITY caseExactMatch
+ SUBSTR caseExactSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
+
+attributetype ( cobblerAttributes:9
+ NAME 'cobblerImageType'
+ DESC 'Cobbler image type'
+ EQUALITY caseExactMatch
+ SUBSTR caseExactSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
+
+attributetype ( cobblerAttributes:10
+ NAME 'cobblerImageXmlFile'
+ DESC 'Cobbler image associated XML file'
+ EQUALITY caseExactMatch
+ SUBSTR caseExactSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
+
+attributetype ( cobblerAttributes:11
+ NAME 'cobblerOsVersion'
+ DESC 'Cobbler OS Version'
+ EQUALITY caseExactMatch
+ SUBSTR caseExactSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
+
+attributetype ( cobblerAttributes:12
+ NAME 'cobblerInitrd'
+ DESC 'Cobbler Initrd Image'
+ EQUALITY caseExactMatch
+ SUBSTR caseExactSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
+
+attributetype ( cobblerAttributes:13
+ NAME 'cobblerKeepUpdated'
+ DESC 'Cobbler Update on Createrepo'
+ EQUALITY booleanMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE )
+
+attributetype ( cobblerAttributes:14
+ NAME 'cobblerKernel'
+ DESC 'Cobbler Kernel Image'
+ EQUALITY caseExactMatch
+ SUBSTR caseExactSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
+
+attributetype ( cobblerAttributes:15
+ NAME 'cobblerKernelMetadata'
+ DESC 'Cobbler Kernel Metadata'
+ EQUALITY caseExactMatch
+ SUBSTR caseExactSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
+
+attributetype ( cobblerAttributes:16
+ NAME 'cobblerKernelOptions'
+ DESC 'Cobbler Kernel Options'
+ EQUALITY caseExactMatch
+ SUBSTR caseExactSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
+
+attributetype ( cobblerAttributes:17
+ NAME 'cobblerKernelOptionsPost'
+ DESC 'Cobbler Post-Install Kernel Options'
+ EQUALITY caseExactMatch
+ SUBSTR caseExactSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
+
+attributetype ( cobblerAttributes:18
+ NAME 'cobblerKickstart'
+ DESC 'Cobbler Kickstart Filename'
+ EQUALITY caseExactMatch
+ SUBSTR caseExactSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
+
+attributetype ( cobblerAttributes:19
+ NAME 'cobblerKickstartMetadata'
+ DESC 'Cobbler kickstart command-line key=value pairs'
+ EQUALITY caseExactMatch
+ SUBSTR caseExactSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
+
+attributetype ( cobblerAttributes:20
+ NAME 'cobblerMirrorLocally'
+ DESC 'Cobbler Cache Copy on Createrepo'
+ EQUALITY booleanMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE )
+
+attributetype ( cobblerAttributes:21
+ NAME 'cobblerMirrorURI'
+ DESC 'Cobbler Upstream Repository URL'
+ EQUALITY caseExactMatch
+ SUBSTR caseExactSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
+
+attributetype ( cobblerAttributes:22
+ NAME 'cobblerNetbootEnabled'
+ DESC 'Cobbler netbooting is allowed for this sytem'
+ EQUALITY booleanMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE )
+
+attributetype ( cobblerAttributes:23
+ NAME 'cobblerNetmaskNumber'
+ DESC 'The IP netmask value(s) for an interface'
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{128} )
+
+attributetype ( cobblerAttributes:24
+ NAME 'cobblerProfileName'
+ DESC 'Cobbler Profile Name'
+ EQUALITY caseExactMatch
+ SUBSTR caseExactSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
+
+attributetype ( cobblerAttributes:25
+ NAME 'cobblerPriority'
+ DESC 'Cobbler Repository Priority'
+ EQUALITY integerMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetype ( cobblerAttributes:26
+ NAME 'cobblerRepoName'
+ DESC 'Cobbler Repositories Name'
+ EQUALITY caseExactMatch
+ SUBSTR caseExactSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
+
+attributetype ( cobblerAttributes:27
+ NAME 'cobblerRpmList'
+ DESC 'Cobbler Repository Mirroring Package Whitelist'
+ EQUALITY caseExactMatch
+ SUBSTR caseExactSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
+
+attributetype ( cobblerAttributes:28
+ NAME 'cobblerServer'
+ DESC 'Cobbler Server IP or Hostname'
+ EQUALITY caseExactMatch
+ SUBSTR caseExactSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
+
+attributetype ( cobblerAttributes:29
+ NAME 'cobblerSystemName'
+ DESC 'The name of the parent system'
+ EQUALITY caseExactMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
+
+attributetype ( cobblerAttributes:30
+ NAME 'cobblerVirtBridge'
+ DESC 'Cobbler VM Bridge'
+ EQUALITY caseExactMatch
+ SUBSTR caseExactSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
+
+attributetype ( cobblerAttributes:31
+ NAME 'cobblerVirtCpus'
+ DESC 'Cobbler VM CPU Count'
+ EQUALITY integerMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetype ( cobblerAttributes:32
+ NAME 'cobblerVirtFileSize'
+ DESC 'Cobbler VM Disk Size'
+ EQUALITY caseExactMatch
+ SUBSTR caseExactSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
+
+attributetype ( cobblerAttributes:33
+ NAME 'cobblerVirtPath'
+ DESC 'Cobbler VM Disk Location'
+ EQUALITY caseExactMatch
+ SUBSTR caseExactSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
+
+attributetype ( cobblerAttributes:34
+ NAME 'cobblerVirtRam'
+ DESC 'Cobbler VM Memory Allocation'
+ EQUALITY caseExactMatch
+ SUBSTR caseExactSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
+
+attributetype ( cobblerAttributes:35
+ NAME 'cobblerVirtType'
+ DESC 'Cobbler VM Type'
+ EQUALITY caseExactMatch
+ SUBSTR caseExactSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
+
+attributetype ( cobblerAttributes:36
+ NAME 'cobblerYumOptions'
+ DESC 'Cobbler Key/Value Pairs for Yum'
+ EQUALITY caseExactMatch
+ SUBSTR caseExactSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
+
+
+objectclass ( cobblerClasses:1
+ NAME 'cobblerObject'
+ DESC 'Structural object which can be used for distro/profile/repo/image classes when required'
+ SUP top
+ STRUCTURAL
+ MUST ( cn $ owner ) )
+
+objectclass ( cobblerClasses:2
+ NAME 'cobblerCommon'
+ DESC 'Common attributes used by all cobbler classes'
+ SUP top
+ AUXILIARY
+ MUST ( cn $ owner ) )
+
+objectclass ( cobblerClasses:3
+ NAME 'cobblerSystem'
+ DESC 'Cobbler host definition'
+ SUP cobblerCommon
+ AUXILIARY
+ MAY ( cobblerDhcpTag $ cobblerGatewayNumber $ cobblerImageName $ cobblerKernelOptions $ cobblerKernelOptionsPost $ cobblerKickstart $ cobblerKickstartMetadata $ cobblerNetbootEnabled $ cobblerNetmaskNumber $ cobblerProfileName $ cobblerServer $ cobblerSystemName $ cobblerVirtBridge $ cobblerVirtCpus $ cobblerVirtFileSize $ cobblerVirtPath $ cobblerVirtRam $ cobblerVirtType $ host $ ipHostNumber $ macAddress ) )
+
+objectclass ( cobblerClasses:4
+ NAME 'cobblerProfile'
+ DESC 'Cobbler profile definition'
+ SUP cobblerCommon
+ AUXILIARY
+ MAY ( cobblerDhcpTag $ cobblerDistroName $ cobblerKernelOptions $ cobblerKernelOptionsPost $ cobblerKickstart $ cobblerKickstartMetadata $ cobblerProfileName $ cobblerRepoName $ cobblerServer $ cobblerVirtBridge $ cobblerVirtCpus $ cobblerVirtFileSize $ cobblerVirtPath $ cobblerVirtRam $ cobblerVirtType ) )
+
+objectclass ( cobblerClasses:5
+ NAME 'cobblerDistro'
+ DESC 'Cobbler distro definition'
+ SUP cobblerCommon
+ AUXILIARY
+ MUST ( cobblerInitrd $ cobblerKernel )
+ MAY ( cobblerArchitecture $ cobblerBreed $ cobblerDistroName $ cobblerKernelOptions $ cobblerKernelOptionsPost $ cobblerKickstartMetadata $ cobblerOsVersion ) )
+
+objectclass ( cobblerClasses:6
+ NAME 'cobblerRepo'
+ DESC 'Cobbler repository definition'
+ SUP cobblerCommon
+ AUXILIARY
+ MUST ( cobblerMirrorURI )
+ MAY ( cobblerArchitecture $ cobblerCreaterepoFlags $ cobblerKeepUpdated $ cobblerMirrorLocally $ cobblerPriority $ cobblerRepoName $ cobblerRpmList $ cobblerYumOptions ) )
+
+objectclass ( cobblerClasses:7
+ NAME 'cobblerImage'
+ DESC 'Cobbler image definition'
+ SUP cobblerCommon
+ AUXILIARY
+ MAY ( cobblerArchitecture $ cobblerBreed $ cobblerImageFile $ cobblerImageName $ cobblerImageType $ cobblerImageXmlFile $ cobblerOsVersion $ cobblerVirtCpus $ cobblerVirtBridge $ cobblerVirtFileSize $ cobblerVirtPath $ cobblerVirtRam $ cobblerVirtType ) )
_______________________________________________
cobbler mailing list
[email protected]
https://fedorahosted.org/mailman/listinfo/cobbler