diff options
author | luke <luke@980ebf18-57e1-0310-9a29-db15c13687c0> | 2006-08-14 06:21:03 +0000 |
---|---|---|
committer | luke <luke@980ebf18-57e1-0310-9a29-db15c13687c0> | 2006-08-14 06:21:03 +0000 |
commit | 12452ee9ca294563f2e2724ff36f179004f9846f (patch) | |
tree | bee6053e8164f4a8dbf214f1898fafecb1d61f2f /lib/puppet/provider/nameservice.rb | |
parent | 4d6120a1f77cfe76fafbe32caa5d853449562376 (diff) | |
download | puppet-12452ee9ca294563f2e2724ff36f179004f9846f.tar.gz puppet-12452ee9ca294563f2e2724ff36f179004f9846f.tar.xz puppet-12452ee9ca294563f2e2724ff36f179004f9846f.zip |
Merging r1468 from the implementations branch with r1438 from when the branch was first created.
git-svn-id: https://reductivelabs.com/svn/puppet/trunk@1469 980ebf18-57e1-0310-9a29-db15c13687c0
Diffstat (limited to 'lib/puppet/provider/nameservice.rb')
-rw-r--r-- | lib/puppet/provider/nameservice.rb | 319 |
1 files changed, 319 insertions, 0 deletions
diff --git a/lib/puppet/provider/nameservice.rb b/lib/puppet/provider/nameservice.rb new file mode 100644 index 000000000..96c1b6f4d --- /dev/null +++ b/lib/puppet/provider/nameservice.rb @@ -0,0 +1,319 @@ +require 'puppet' + +# This is the parent class of all NSS classes. They're very different in +# their backend, but they're pretty similar on the front-end. This class +# provides a way for them all to be as siilar as possible. +class Puppet::Provider::NameService < Puppet::Provider + class << self + + def list + objects = [] + listbyname do |name| + obj = nil + check = model.validstates + if obj = model[name] + obj[:check] = check + else + # unless it exists, create it as an unmanaged object + obj = model.create(:name => name, :check => check) + end + + next unless obj # In case there was an error somewhere + + objects << obj + yield obj if block_given? + end + + objects + end + + def option(name, option) + name = name.intern if name.is_a? String + if defined? @options and @options.include? name and @options[name].include? option + return @options[name][option] + else + return nil + end + end + + def options(name, hash) + unless model.validstate?(name) + raise Puppet::DevError, "%s is not a valid state for %s" % + [name, model.name] + end + @options ||= {} + @options[name] ||= {} + + # Set options individually, so we can call the options method + # multiple times. + hash.each do |param, value| + @options[name][param] = value + end + end + + # List everything out by name. Abstracted a bit so that it works + # for both users and groups. + def listbyname + names = [] + Etc.send("set%sent" % section()) + begin + while ent = Etc.send("get%sent" % section()) + names << ent.name + if block_given? + yield ent.name + end + end + ensure + Etc.send("end%sent" % section()) + end + + return names + end + + # This is annoying, but there really aren't that many options, + # and this *is* built into Ruby. + def section + unless defined? @model + raise Puppet::DevError, + "Cannot determine Etc section without a model" + + end + + if @model.name == :group + "gr" + else + "pw" + end + end + + def disabled_validate(name, value) + name = name.intern if name.is_a? String + if @checks.include? name + block = @checks[name][:block] + unless block.call(value) + raise ArgumentError, "Invalid value %s: %s" % + [value, @checks[name][:error]] + end + end + end + + def verify(name, error, &block) + name = name.intern if name.is_a? String + @checks ||= {} + @checks[name] = {:error => error, :block => block} + end + + private + + def op(state) + @ops[state.name] || ("-" + state.name) + end + end + + # Autogenerate either a uid or a gid. This is hard-coded: we can only + # generate one field type per class. + def autogen + highest = 0 + + group = method = nil + case @model.class.name + when :user: group = :passwd; method = :uid + when :group: group = :group; method = :gid + else + raise Puppet::DevError, "Invalid model name %s" % model + end + + # Make sure we don't use the same value multiple times + if defined? @@prevauto + @@prevauto += 1 + else + Etc.send(group) { |obj| + if obj.gid > highest + unless obj.send(method) > 65000 + highest = obj.send(method) + end + end + } + + @@prevauto = highest + 1 + end + + return @@prevauto + end + + def autogen_gid + autogen(@model.class.name) + end + + def autogen_uid + autogen(@model.class.name) + end + + def create + self.ensure = :present + end + + def delete + self.ensure = :absent + end + + def ensure + if exists? + :present + else + :absent + end + end + + # This is only used when creating or destroying the object. + def ensure=(value) + cmd = nil + event = nil + case value + when :absent + # we need to remove the object... + unless exists? + info "already absent" + # the object already doesn't exist + return nil + end + + # again, needs to be set by the ind. state or its + # parent + cmd = self.deletecmd + type = "delete" + when :present + if exists? + info "already exists" + # The object already exists + return nil + end + + # blah blah, define elsewhere, blah blah + cmd = self.addcmd + type = "create" + end + + begin + execute(cmd) + rescue Puppet::ExecutionFailure => detail + raise Puppet::Error, "Could not %s %s %s: %s" % + [type, @model.class.name, @model.name, detail] + end + end + + # Does our object exist? + def exists? + if getinfo(true) + return true + else + return false + end + end + + # Retrieve a specific value by name. + def get(param) + if hash = getinfo(false) + return hash[param] + else + return nil + end + end + + # Retrieve what we can about our object + def getinfo(refresh) + if @objectinfo.nil? or refresh == true + @etcmethod ||= ("get" + self.class.section().to_s + "nam").intern + begin + @objectinfo = Etc.send(@etcmethod, @model[:name]) + rescue ArgumentError => detail + @objectinfo = nil + end + end + + # Now convert our Etc struct into a hash. + if @objectinfo + return info2hash(@objectinfo) + else + return nil + end + end + + # The list of all groups the user is a member of. Different + # user mgmt systems will need to override this method. + def groups + groups = [] + + # Reset our group list + Etc.setgrent + + user = @model[:name] + + # Now iterate across all of the groups, adding each one our + # user is a member of + while group = Etc.getgrent + members = group.mem + + if members.include? user + groups << group.name + end + end + + # We have to close the file, so each listing is a separate + # reading of the file. + Etc.endgrent + + groups.join(",") + end + + # Convert the Etc struct into a hash. + def info2hash(info) + hash = {} + self.class.model.validstates.each do |param| + method = posixmethod(param) + if info.respond_to? method + hash[param] = info.send(posixmethod(param)) + end + end + + return hash + end + + def initialize(model) + super + + @objectinfo = nil + end + + # + def method_missing(name, *args) + name = name.to_s + + # Make sure it's a valid state. We go up our class structure instead of + # our model's because the model is fake during testing. + unless self.class.model.validstate?(name.sub("=",'')) + raise Puppet::DevError, "%s is not a valid %s state" % + [name, @model.class.name] + end + + # Each class has to override this manually + if name =~ /=/ + set(name.to_s.sub("=", ''), *args) + else + return get(name.intern) || :absent + end + end + + def set(param, value) + #self.class.validate(param, value) + cmd = modifycmd(param, value) + begin + execute(cmd) + rescue Puppet::ExecutionFailure => detail + raise Puppet::Error, "Could not set %s on %s[%s]: %s" % + [param, @model.class.name, @model.name, detail] + end + end +end + +# $Id$ |