[Pkg-puppet-devel] [SCM] Puppet packaging for Debian branch, master, updated. debian/0.24.6-1-356-g5718585
James Turnbull
james at lovedthanlost.net
Fri Jan 23 14:21:45 UTC 2009
The following commit has been merged in the master branch:
commit d978668c03f42ce314245c23b06179f6a62f3d67
Author: Nigel Kersten <nigelk at google.com>
Date: Tue Nov 25 08:32:46 2008 -0800
Lots of DirectoryService work. New Computer Type. Users now use password hashes. Groups now support setting members as attributes of the group for OS X.
diff --git a/lib/puppet/provider/computer/computer.rb b/lib/puppet/provider/computer/computer.rb
new file mode 100644
index 0000000..76d0f18
--- /dev/null
+++ b/lib/puppet/provider/computer/computer.rb
@@ -0,0 +1,22 @@
+require 'puppet/provider/nameservice/directoryservice'
+
+Puppet::Type.type(:computer).provide :directoryservice, :parent => Puppet::Provider::NameService::DirectoryService do
+ desc "Computer object management using DirectoryService on OS X.
+
+ Note that these are distinctly different kinds of objects to 'hosts',
+ as they require a MAC address and can have all sorts of policy attached to
+ them.
+
+ This provider only manages Computer objects in the local directory service
+ domain, not in remote directories.
+
+ If you wish to manage /etc/hosts on Mac OS X, then simply use the host
+ type as per other platforms.
+ "
+
+ confine :operatingsystem => :darwin
+ defaultfor :operatingsystem => :darwin
+
+ # hurray for abstraction. The nameservice directoryservice provider can
+ # handle everything we need. super.
+end
\ No newline at end of file
diff --git a/lib/puppet/provider/group/directoryservice.rb b/lib/puppet/provider/group/directoryservice.rb
index 4066222..2f39305 100644
--- a/lib/puppet/provider/group/directoryservice.rb
+++ b/lib/puppet/provider/group/directoryservice.rb
@@ -16,8 +16,9 @@ require 'puppet/provider/nameservice/directoryservice'
Puppet::Type.type(:group).provide :directoryservice, :parent => Puppet::Provider::NameService::DirectoryService do
desc "Group management using DirectoryService on OS X."
-
+
commands :dscl => "/usr/bin/dscl"
confine :operatingsystem => :darwin
- #defaultfor :operatingsystem => :darwin
+ defaultfor :operatingsystem => :darwin
+ has_feature :manages_members
end
diff --git a/lib/puppet/provider/nameservice/directoryservice.rb b/lib/puppet/provider/nameservice/directoryservice.rb
index ecd5fa6..0e8002c 100644
--- a/lib/puppet/provider/nameservice/directoryservice.rb
+++ b/lib/puppet/provider/nameservice/directoryservice.rb
@@ -16,6 +16,7 @@ require 'puppet'
require 'puppet/provider/nameservice'
require 'facter/util/plist'
+
class Puppet::Provider::NameService
class DirectoryService < Puppet::Provider::NameService
# JJM: Dive into the eigenclass
@@ -27,6 +28,7 @@ class DirectoryService < Puppet::Provider::NameService
attr_writer :ds_path
end
+
# JJM 2007-07-24: Not yet sure what initvars() does. I saw it in netinfo.rb
# I do know, however, that it makes methods "work" =)
# e.g. addcmd isn't available if this method call isn't present.
@@ -37,6 +39,7 @@ class DirectoryService < Puppet::Provider::NameService
initvars()
commands :dscl => "/usr/bin/dscl"
+ commands :dseditgroup => "/usr/sbin/dseditgroup"
confine :operatingsystem => :darwin
defaultfor :operatingsystem => :darwin
@@ -56,6 +59,9 @@ class DirectoryService < Puppet::Provider::NameService
'RealName' => :comment,
'Password' => :password,
'GeneratedUID' => :guid,
+ 'IPAddress' => :ip_address,
+ 'ENetAddress' => :en_address,
+ 'GroupMembership' => :members,
}
# JJM The same table as above, inverted.
@@ns_to_ds_attribute_map = {
@@ -67,6 +73,9 @@ class DirectoryService < Puppet::Provider::NameService
:comment => 'RealName',
:password => 'Password',
:guid => 'GeneratedUID',
+ :en_address => 'ENetAddress',
+ :ip_address => 'IPAddress',
+ :members => 'GroupMembership',
}
@@password_hash_dir = "/var/db/shadow/hash"
@@ -137,7 +146,10 @@ class DirectoryService < Puppet::Provider::NameService
dscl_plist.keys().each do |key|
ds_attribute = key.sub("dsAttrTypeStandard:", "")
next unless (@@ds_to_ns_attribute_map.keys.include?(ds_attribute) and type_properties.include? @@ds_to_ns_attribute_map[ds_attribute])
- ds_value = dscl_plist[key][0] # only care about the first entry...
+ ds_value = dscl_plist[key]
+ if not @@ds_to_ns_attribute_map[ds_attribute] == :members # only members uses arrays so far
+ ds_value = ds_value[0]
+ end
attribute_hash[@@ds_to_ns_attribute_map[ds_attribute]] = ds_value
end
@@ -229,7 +241,6 @@ class DirectoryService < Puppet::Provider::NameService
if ensure_value == :present
@resource.class.validproperties.each do |name|
next if name == :ensure
-
# LAK: We use property.sync here rather than directly calling
# the settor method because the properties might do some kind
# of conversion. In particular, the user gid property might
@@ -261,18 +272,36 @@ class DirectoryService < Puppet::Provider::NameService
end
end
- def modifycmd(property, value)
- # JJM: This method will assemble a exec vector which modifies
- # a single property and it's value using dscl.
- # JJM: With /usr/bin/dscl, the -create option will destroy an
- # existing property record if it exists
- exec_arg_vector = self.class.get_exec_preamble("-create", @resource[:name])
- # JJM: The following line just maps the NS name to the DS name
- # e.g. { :uid => 'UniqueID' }
- exec_arg_vector << @@ns_to_ds_attribute_map[symbolize(property)]
- # JJM: The following line sends the actual value to set the property to
- exec_arg_vector << value.to_s
- return exec_arg_vector
+ # NBK: we override @parent.set as we need to execute a series of commands
+ # to deal with array values, rather than the single command nameservice.rb
+ # expects to be returned by modifycmd. Thus we don't bother defining modifycmd.
+
+ def set(param, value)
+ self.class.validate(param, value)
+ current_members = @property_value_cache_hash[:members]
+ if param == :members
+ # If we are meant to be authoritative for the group membership
+ # then remove all existing members who haven't been specified
+ # in the manifest.
+ if @resource[:auth_membership] and not current_members.nil?
+ remove_unwanted_members(current_members, value)
+ end
+
+ # if they're not a member, make them one.
+ add_members(current_members, value)
+ else
+ exec_arg_vector = self.class.get_exec_preamble("-create", @resource[:name])
+ # JJM: The following line just maps the NS name to the DS name
+ # e.g. { :uid => 'UniqueID' }
+ exec_arg_vector << @@ns_to_ds_attribute_map[symbolize(param)]
+ # JJM: The following line sends the actual value to set the property to
+ exec_arg_vector << value.to_s
+ begin
+ execute(exec_arg_vector)
+ rescue Puppet::ExecutionFailure => detail
+ raise Puppet::Error, "Could not set %s on %s[%s]: %s" % [param, @resource.class.name, @resource.name, detail]
+ end
+ end
end
# NBK: we override @parent.create as we need to execute a series of commands
@@ -307,20 +336,50 @@ class DirectoryService < Puppet::Provider::NameService
end
# Now we create all the standard properties
- Puppet::Type.type(:user).validproperties.each do |property|
+ Puppet::Type.type(@resource.class.name).validproperties.each do |property|
next if property == :ensure
if value = @resource.should(property) and value != ""
- exec_arg_vector = self.class.get_exec_preamble("-create", @resource[:name])
- exec_arg_vector << @@ns_to_ds_attribute_map[symbolize(property)]
- next if property == :password # skip setting the password here
- exec_arg_vector << value.to_s
+ if property == :members
+ add_members(nil, value)
+ else
+ exec_arg_vector = self.class.get_exec_preamble("-create", @resource[:name])
+ exec_arg_vector << @@ns_to_ds_attribute_map[symbolize(property)]
+ next if property == :password # skip setting the password here
+ exec_arg_vector << value.to_s
+ begin
+ execute(exec_arg_vector)
+ rescue Puppet::ExecutionFailure => detail
+ raise Puppet::Error, "Could not create %s %s: %s" %
+ [@resource.class.name, @resource.name, detail]
+ end
+ end
+ end
+ end
+ end
+
+ def remove_unwanted_members(current_members, new_members)
+ current_members.each do |member|
+ if not value.include?(member)
+ cmd = [:dseditgroup, "-o", "edit", "-n", ".", "-d", member, @resource[:name]]
begin
- execute(exec_arg_vector)
+ execute(cmd)
rescue Puppet::ExecutionFailure => detail
- raise Puppet::Error, "Could not create %s %s: %s" %
- [@resource.class.name, @resource.name, detail]
- end
- end
+ raise Puppet::Error, "Could not set %s on %s[%s]: %s" % [param, @resource.class.name, @resource.name, detail]
+ end
+ end
+ end
+ end
+
+ def add_members(current_members, new_members)
+ new_members.each do |user|
+ if current_members.nil? or not current_members.include?(user)
+ cmd = [:dseditgroup, "-o", "edit", "-n", ".", "-a", user, @resource[:name]]
+ begin
+ execute(cmd)
+ rescue Puppet::ExecutionFailure => detail
+ raise Puppet::Error, "Could not set %s on %s[%s]: %s" % [param, @resource.class.name, @resource.name, detail]
+ end
+ end
end
end
@@ -376,4 +435,4 @@ class DirectoryService < Puppet::Provider::NameService
return @property_value_cache_hash
end
end
-end
+end
\ No newline at end of file
diff --git a/lib/puppet/type/computer.rb b/lib/puppet/type/computer.rb
new file mode 100644
index 0000000..0c0a709
--- /dev/null
+++ b/lib/puppet/type/computer.rb
@@ -0,0 +1,59 @@
+Puppet::Type.newtype(:computer) do
+
+ @doc = "Computer object management using DirectoryService on OS X.
+
+ Note that these are distinctly different kinds of objects to 'hosts',
+ as they require a MAC address and can have all sorts of policy attached to
+ them.
+
+ This provider only manages Computer objects in the local directory service
+ domain, not in remote directories.
+
+ If you wish to manage /etc/hosts on Mac OS X, then simply use the host
+ type as per other platforms.
+
+ This type primarily exists to create localhost Computer objects that MCX
+ policy can then be attached to."
+
+ # ensurable
+
+ # We autorequire the computer object in case it is being managed at the
+ # file level by Puppet.
+
+ autorequire(:file) do
+ if self[:name]
+ "/var/db/dslocal/nodes/Default/computers/#{self[:name]}.plist"
+ else
+ nil
+ end
+ end
+
+ newproperty(:ensure, :parent => Puppet::Property::Ensure) do
+ newvalue(:present) do
+ provider.create
+ end
+
+ newvalue(:absent) do
+ Puppet.notice "prop ensure = absent"
+ provider.delete
+ end
+ end
+
+ newparam(:name) do
+ desc "The "
+ isnamevar
+ end
+
+ newparam(:realname) do
+ desc "realname"
+ end
+
+ newproperty(:en_address) do
+ desc "The MAC address of the primary network interface. Must match en0."
+ end
+
+ newproperty(:ip_address) do
+ desc "The IP Address of the Computer object."
+ end
+
+end
\ No newline at end of file
diff --git a/lib/puppet/type/group.rb b/lib/puppet/type/group.rb
index 29486d3..1167962 100755
--- a/lib/puppet/type/group.rb
+++ b/lib/puppet/type/group.rb
@@ -11,15 +11,22 @@ require 'facter'
module Puppet
newtype(:group) do
- @doc = "Manage groups. This type can only create groups. Group
- membership must be managed on individual users. This resource type
- uses the prescribed native tools for creating groups and generally
- uses POSIX APIs for retrieving information about them. It does
- not directly modify ``/etc/group`` or anything.
+ @doc = "Manage groups. On most platforms this can only create groups.
+ Group membership must be managed on individual users.
+
+ On OS X, group membership is managed as an attribute of the group.
+ This resource type uses the prescribed native tools for creating
+ groups and generally uses POSIX APIs for retrieving information
+ about them. It does not directly modify ``/etc/group`` or anything.
For most platforms, the tools used are ``groupadd`` and its ilk;
- for Mac OS X, NetInfo is used. This is currently unconfigurable,
- but if you desperately need it to be so, please contact us."
+ for Mac OS X, dscl/dseditgroup are used.
+
+ This is currently unconfigurable, but if you desperately need it
+ to be so, please contact us."
+
+ feature :manages_members,
+ "For directories where membership is an attribute of groups not users."
ensurable do
desc "Create or remove the group."
@@ -73,13 +80,28 @@ module Puppet
return gid
end
end
+
+ newproperty(:members, :array_matching => :all, :required_features => :manages_members) do
+ desc "The members of the group. For directory services where group
+ membership is stored in the group objects, not the users."
+
+ def change_to_s(currentvalue, newvalue)
+ currentvalue = currentvalue.join(",") if currentvalue != :absent
+ newvalue = newvalue.join(",")
+ super(currentvalue, newvalue)
+ end
+ end
+
+ newparam(:auth_membership) do
+ desc "whether the provider is authoritative for group membership."
+ defaultto true
+ end
newparam(:name) do
desc "The group name. While naming limitations vary by
system, it is advisable to keep the name to the degenerate
limitations, which is a maximum of 8 characters beginning with
a letter."
-
isnamevar
end
diff --git a/spec/unit/type/computer.rb b/spec/unit/type/computer.rb
new file mode 100755
index 0000000..ec3c797
--- /dev/null
+++ b/spec/unit/type/computer.rb
@@ -0,0 +1,86 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../spec_helper'
+
+require 'puppet/type/computer'
+
+computer = Puppet::Type.type(:computer)
+
+describe Puppet.type(:computer), " when checking computer objects" do
+ before :each do
+ provider_class = Puppet::Type::Computer.provider(Puppet::Type::Computer.providers[0])
+ Puppet::Type::Computer.expects(:defaultprovider).returns provider_class
+ @resource = Puppet::Type::Computer.create(
+ :name => "puppetcomputertest",
+ :en_address => "aa:bb:cc:dd:ee:ff",
+ :ip_address => "1.2.3.4")
+ @properties = {}
+ @ensure = Puppet::Type::Computer.attrclass(:ensure).new(:resource => @resource)
+ end
+
+ after :each do
+ computer.clear
+ provider_class = nil
+ Puppet::Type::Computer.provider(nil)
+ end
+
+ it "should be able to create a instance" do
+ provider_class = Puppet::Type::Computer.provider(Puppet::Type::Computer.providers[0])
+ Puppet::Type::Computer.expects(:defaultprovider).returns provider_class
+ computer.create(:name => "bar").should_not be_nil
+ end
+
+ properties = [:en_address, :ip_address]
+ params = [:name]
+
+ properties.each do |property|
+ it "should have a %s property" % property do
+ computer.attrclass(property).ancestors.should be_include(Puppet::Property)
+ end
+
+ it "should have documentation for its %s property" % property do
+ computer.attrclass(property).doc.should be_instance_of(String)
+ end
+
+ it "should accept :absent as a value" do
+ prop = computer.attrclass(property).new(:resource => @resource)
+ prop.should = :absent
+ prop.should.must == :absent
+ end
+ end
+
+ params.each do |param|
+ it "should have a %s parameter" % param do
+ computer.attrclass(param).ancestors.should be_include(Puppet::Parameter)
+ end
+
+ it "should have documentation for its %s parameter" % param do
+ computer.attrclass(param).doc.should be_instance_of(String)
+ end
+ end
+
+ describe "default values" do
+ before do
+ provider_class = computer.provider(computer.providers[0])
+ computer.expects(:defaultprovider).returns provider_class
+ end
+
+ it "should be nil for en_address" do
+ computer.create(:name => :en_address)[:en_address].should == nil
+ end
+
+ it "should be nil for ip_address" do
+ computer.create(:name => :ip_address)[:ip_address].should == nil
+ end
+ end
+
+ describe "when managing the ensure property" do
+ it "should support a :present value" do
+ lambda { @ensure.should = :present }.should_not raise_error
+ end
+
+ it "should support an :absent value" do
+ lambda { @ensure.should = :absent }.should_not raise_error
+ end
+ end
+end
\ No newline at end of file
--
Puppet packaging for Debian
More information about the Pkg-puppet-devel
mailing list