summaryrefslogtreecommitdiffstats
path: root/lib/puppet/util
diff options
context:
space:
mode:
Diffstat (limited to 'lib/puppet/util')
-rw-r--r--lib/puppet/util/ldap.rb5
-rw-r--r--lib/puppet/util/ldap/connection.rb57
-rw-r--r--lib/puppet/util/ldap/generator.rb45
-rw-r--r--lib/puppet/util/ldap/manager.rb281
-rw-r--r--lib/puppet/util/settings.rb2
-rw-r--r--lib/puppet/util/storage.rb4
-rw-r--r--lib/puppet/util/variables.rb38
7 files changed, 393 insertions, 39 deletions
diff --git a/lib/puppet/util/ldap.rb b/lib/puppet/util/ldap.rb
new file mode 100644
index 000000000..33f01f789
--- /dev/null
+++ b/lib/puppet/util/ldap.rb
@@ -0,0 +1,5 @@
+#
+# Created by Luke Kanies on 2008-3-23.
+# Copyright (c) 2008. All rights reserved.
+module Puppet::Util::Ldap
+end
diff --git a/lib/puppet/util/ldap/connection.rb b/lib/puppet/util/ldap/connection.rb
new file mode 100644
index 000000000..abcc07ecb
--- /dev/null
+++ b/lib/puppet/util/ldap/connection.rb
@@ -0,0 +1,57 @@
+#
+# Created by Luke Kanies on 2008-3-23.
+# Copyright (c) 2008. All rights reserved.
+require 'puppet/util/ldap'
+
+class Puppet::Util::Ldap::Connection
+ attr_accessor :host, :port, :user, :password, :reset, :ssl
+
+ attr_reader :connection
+
+ def close
+ connection.unbind if connection.bound?
+ end
+
+ def initialize(host, port, options = {})
+ raise Puppet::Error, "Could not set up LDAP Connection: Missing ruby/ldap libraries" unless Puppet.features.ldap?
+
+ @host, @port = host, port
+
+ options.each do |param, value|
+ begin
+ send(param.to_s + "=", value)
+ rescue
+ raise ArgumentError, "LDAP connections do not support %s parameters" % param
+ end
+ end
+ end
+
+ # Create a per-connection unique name.
+ def name
+ [host, port, user, password, ssl].collect { |p| p.to_s }.join("/")
+ end
+
+ # Should we reset the connection?
+ def reset?
+ reset
+ end
+
+ # Start our ldap connection.
+ def start
+ begin
+ case ssl
+ when :tls:
+ @connection = LDAP::SSLConn.new(host, port, true)
+ when true:
+ @connection = LDAP::SSLConn.new(host, port)
+ else
+ @connection = LDAP::Conn.new(host, port)
+ end
+ @connection.set_option(LDAP::LDAP_OPT_PROTOCOL_VERSION, 3)
+ @connection.set_option(LDAP::LDAP_OPT_REFERRALS, LDAP::LDAP_OPT_ON)
+ @connection.simple_bind(user, password)
+ rescue => detail
+ raise Puppet::Error, "Could not connect to LDAP: %s" % detail
+ end
+ end
+end
diff --git a/lib/puppet/util/ldap/generator.rb b/lib/puppet/util/ldap/generator.rb
new file mode 100644
index 000000000..2a868b0d9
--- /dev/null
+++ b/lib/puppet/util/ldap/generator.rb
@@ -0,0 +1,45 @@
+#
+# Created by Luke Kanies on 2008-3-28.
+# Copyright (c) 2008. All rights reserved.
+require 'puppet/util/ldap'
+
+class Puppet::Util::Ldap::Generator
+ # Declare the attribute we'll use to generate the value.
+ def from(source)
+ @source = source
+ return self
+ end
+
+ # Actually do the generation.
+ def generate(value = nil)
+ if value.nil?
+ @generator.call
+ else
+ @generator.call(value)
+ end
+ end
+
+ # Initialize our generator with the name of the parameter
+ # being generated.
+ def initialize(name)
+ @name = name
+ end
+
+ def name
+ @name.to_s
+ end
+
+ def source
+ if defined?(@source) and @source
+ @source.to_s
+ else
+ nil
+ end
+ end
+
+ # Provide the code that does the generation.
+ def with(&block)
+ @generator = block
+ return self
+ end
+end
diff --git a/lib/puppet/util/ldap/manager.rb b/lib/puppet/util/ldap/manager.rb
new file mode 100644
index 000000000..9761fc753
--- /dev/null
+++ b/lib/puppet/util/ldap/manager.rb
@@ -0,0 +1,281 @@
+require 'puppet/util/ldap'
+require 'puppet/util/ldap/connection'
+require 'puppet/util/ldap/generator'
+
+# The configuration class for LDAP providers, plus
+# connection handling for actually interacting with ldap.
+class Puppet::Util::Ldap::Manager
+ attr_reader :objectclasses, :puppet2ldap, :location, :rdn
+
+ # A null-op that just returns the config.
+ def and
+ return self
+ end
+
+ # Set the offset from the search base and return the config.
+ def at(location)
+ @location = location
+ return self
+ end
+
+ # The basic search base.
+ def base
+ [location, Puppet[:ldapbase]].join(",")
+ end
+
+ # Convert the name to a dn, then pass the args along to
+ # our connection.
+ def create(name, attributes)
+ attributes = attributes.dup
+
+ # Add the objectclasses
+ attributes["objectClass"] = objectclasses.collect { |o| o.to_s }
+ attributes["objectClass"] << "top" unless attributes["objectClass"].include?("top")
+
+ attributes[rdn.to_s] = [name]
+
+ # Generate any new values we might need.
+ generate(attributes)
+
+ # And create our resource.
+ connect { |conn| conn.add dn(name), attributes }
+ end
+
+ # Open, yield, and close the connection. Cannot be left
+ # open, at this point.
+ def connect
+ raise ArgumentError, "You must pass a block to #connect" unless block_given?
+
+ unless defined?(@connection) and @connection
+ if Puppet[:ldaptls]
+ ssl = :tls
+ elsif Puppet[:ldapssl]
+ ssl = true
+ else
+ ssl = false
+ end
+ options = {:ssl => ssl}
+ if user = Puppet[:ldapuser] and user != ""
+ options[:user] = user
+ end
+ if password = Puppet[:ldappassword] and password != ""
+ options[:password] = password
+ end
+ @connection = Puppet::Util::Ldap::Connection.new(Puppet[:ldapserver], Puppet[:ldapport], options)
+ end
+ @connection.start
+ begin
+ yield @connection.connection
+ ensure
+ @connection.close
+ end
+ return nil
+ end
+
+ # Convert the name to a dn, then pass the args along to
+ # our connection.
+ def delete(name)
+ connect { |connection| connection.delete dn(name) }
+ end
+
+ # Calculate the dn for a given resource.
+ def dn(name)
+ ["#{rdn.to_s}=%s" % name, base].join(",")
+ end
+
+ # Convert an ldap-style entry hash to a provider-style hash.
+ def entry2provider(entry)
+ raise ArgumentError, "Could not get dn from ldap entry" unless entry["dn"]
+
+ # DN is always a single-entry array. Strip off the bits before the
+ # first comma, then the bits after the remaining equal sign. This is the
+ # name.
+ name = entry["dn"].dup.pop.split(",").shift.split("=").pop
+
+ result = {:name => name}
+
+ @ldap2puppet.each do |ldap, puppet|
+ result[puppet] = entry[ldap.to_s] || :absent
+ end
+
+ result
+ end
+
+ # Create our normal search filter.
+ def filter
+ return "objectclass=%s" % objectclasses[0] if objectclasses.length == 1
+ return "(&(objectclass=" + objectclasses.join(")(objectclass=") + "))"
+ end
+
+ # Find the associated entry for a resource. Returns a hash, minus
+ # 'dn', or nil if the entry cannot be found.
+ def find(name)
+ result = nil
+ connect do |conn|
+ begin
+ conn.search2(dn(name), 0, "objectclass=*") do |result|
+ # Convert to puppet-appropriate attributes
+ return entry2provider(result)
+ end
+ rescue => detail
+ return nil
+ end
+ end
+ end
+
+ # Declare a new attribute generator.
+ def generates(parameter)
+ @generators << Puppet::Util::Ldap::Generator.new(parameter)
+ @generators[-1]
+ end
+
+ # Generate any extra values we need to make the ldap entry work.
+ def generate(values)
+ return unless @generators.length > 0
+
+ @generators.each do |generator|
+ # Don't override any values that might exist.
+ next if values[generator.name]
+
+ if generator.source
+ unless value = values[generator.source]
+ raise ArgumentError, "%s must be defined to generate %s" % [generator.source, generator.name]
+ end
+ result = generator.generate(value)
+ else
+ result = generator.generate
+ end
+
+ result = [result] unless result.is_a?(Array)
+ result = result.collect { |r| r.to_s }
+
+ values[generator.name] = result
+ end
+ end
+
+ def initialize
+ @rdn = :cn
+ @generators = []
+ end
+
+ # Specify what classes this provider models.
+ def manages(*classes)
+ @objectclasses = classes
+ return self
+ end
+
+ # Specify the attribute map. Assumes the keys are the puppet
+ # attributes, and the values are the ldap attributes, and creates a map
+ # for each direction.
+ def maps(attributes)
+ # The map with the puppet attributes as the keys
+ @puppet2ldap = attributes
+
+ # and the ldap attributes as the keys.
+ @ldap2puppet = attributes.inject({}) { |map, ary| map[ary[1]] = ary[0]; map }
+
+ return self
+ end
+
+ # Return the ldap name for a puppet attribute.
+ def ldap_name(attribute)
+ @puppet2ldap[attribute].to_s
+ end
+
+ # Convert the name to a dn, then pass the args along to
+ # our connection.
+ def modify(name, mods)
+ connect { |connection| connection.modify dn(name), mods }
+ end
+
+ # Specify the rdn that we use to build up our dn.
+ def named_by(attribute)
+ @rdn = attribute
+ self
+ end
+
+ # Return the puppet name for an ldap attribute.
+ def puppet_name(attribute)
+ @ldap2puppet[attribute]
+ end
+
+ # Search for all entries at our base. A potentially expensive search.
+ def search(sfilter = nil)
+ sfilter ||= filter()
+
+ result = []
+ connect do |conn|
+ conn.search2(base, 1, sfilter) do |entry|
+ result << entry2provider(entry)
+ end
+ end
+ return nil if result.empty?
+ return result
+ end
+
+ # Update the ldap entry with the desired state.
+ def update(name, is, should)
+ if should[:ensure] == :absent
+ Puppet.info "Removing %s from ldap" % dn(name)
+ delete(name)
+ return
+ end
+
+ # We're creating a new entry
+ if is.empty? or is[:ensure] == :absent
+ Puppet.info "Creating %s in ldap" % dn(name)
+ # Remove any :absent params and :ensure, then convert the names to ldap names.
+ attrs = ldap_convert(should)
+ create(name, attrs)
+ return
+ end
+
+ # We're modifying an existing entry. Yuck.
+
+ mods = []
+ # For each attribute we're deleting that is present, create a
+ # modify instance for deletion.
+ [is.keys, should.keys].flatten.uniq.each do |property|
+ # They're equal, so do nothing.
+ next if is[property] == should[property]
+
+ attributes = ldap_convert(should)
+
+ prop_name = ldap_name(property).to_s
+
+ # We're creating it.
+ if is[property] == :absent or is[property].nil?
+ mods << LDAP::Mod.new(LDAP::LDAP_MOD_ADD, prop_name, attributes[prop_name])
+ next
+ end
+
+ # We're deleting it
+ if should[property] == :absent or should[property].nil?
+ mods << LDAP::Mod.new(LDAP::LDAP_MOD_DELETE, prop_name, [])
+ next
+ end
+
+ # We're replacing an existing value
+ mods << LDAP::Mod.new(LDAP::LDAP_MOD_REPLACE, prop_name, attributes[prop_name])
+ end
+
+ modify(name, mods)
+ end
+
+ # Is this a complete ldap configuration?
+ def valid?
+ location and objectclasses and ! objectclasses.empty? and puppet2ldap
+ end
+
+ private
+
+ # Convert a hash of attributes to ldap-like forms. This mostly means
+ # getting rid of :ensure and making sure everything's an array of strings.
+ def ldap_convert(attributes)
+ attributes.reject { |param, value| value == :absent or param == :ensure }.inject({}) do |result, ary|
+ value = (ary[1].is_a?(Array) ? ary[1] : [ary[1]]).collect { |v| v.to_s }
+ result[ldap_name(ary[0])] = value
+ result
+ end
+ end
+end
diff --git a/lib/puppet/util/settings.rb b/lib/puppet/util/settings.rb
index 1b953c95e..eec86625d 100644
--- a/lib/puppet/util/settings.rb
+++ b/lib/puppet/util/settings.rb
@@ -123,7 +123,7 @@ class Puppet::Util::Settings
if pval = self.value(varname)
pval
else
- raise Puppet::DevError, "Could not find value for %s" % parent
+ raise Puppet::DevError, "Could not find value for %s" % value
end
end
diff --git a/lib/puppet/util/storage.rb b/lib/puppet/util/storage.rb
index 9358a28e9..dc4e9cd71 100644
--- a/lib/puppet/util/storage.rb
+++ b/lib/puppet/util/storage.rb
@@ -6,6 +6,10 @@ class Puppet::Util::Storage
include Singleton
include Puppet::Util
+ def self.state
+ return @@state
+ end
+
def initialize
self.class.load
end
diff --git a/lib/puppet/util/variables.rb b/lib/puppet/util/variables.rb
deleted file mode 100644
index 1a78ef5c1..000000000
--- a/lib/puppet/util/variables.rb
+++ /dev/null
@@ -1,38 +0,0 @@
-module Puppet::Util::Variables
- def inithooks
- @instance_init_hooks.dup
- end
-
- def initvars
- return unless defined? @class_init_hooks
- self.inithooks.each do |var, value|
- if value.is_a?(Class)
- instance_variable_set("@" + var.to_s, value.new)
- else
- instance_variable_set("@" + var.to_s, value)
- end
- end
- end
-
- def instancevar(hash)
- @instance_init_hooks ||= {}
-
- unless method_defined?(:initvars)
- define_method(:initvars) do
- self.class.inithooks.each do |var, value|
- if value.is_a?(Class)
- instance_variable_set("@" + var.to_s, value.new)
- else
- instance_variable_set("@" + var.to_s, value)
- end
- end
- end
- end
- hash.each do |var, value|
- raise("Already initializing %s" % var) if @instance_init_hooks[var]
-
- @instance_init_hooks[var] = value
- end
- end
-end
-