summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNick Lewis <nick@puppetlabs.com>2011-08-09 13:04:25 -0700
committerJacob Helwig <jacob@puppetlabs.com>2011-08-19 13:52:59 -0700
commit4f7170a0fd7d77d7d9941001cdb7dbcb0662d6b4 (patch)
tree7040d63c6c64078bd3daaa4eaafc4795a3f23d6b
parentf19a0ea8c12c06bb01ddfe53e47e3a02ae87bdbb (diff)
downloadpuppet-4f7170a0fd7d77d7d9941001cdb7dbcb0662d6b4.tar.gz
puppet-4f7170a0fd7d77d7d9941001cdb7dbcb0662d6b4.tar.xz
puppet-4f7170a0fd7d77d7d9941001cdb7dbcb0662d6b4.zip
(#8408) Add a default user provider for Windows
This provider, windows_adsi, uses the Puppet::Util::ADSI module to manage users. It can currently only manage group memberships, comments, and home directories, which are the only fields that can be managed via ADSI. Based on work by: Joel Rosario <joel.r@.internal.directi.com> Based on work by: Cameron Thomas <cameron@puppetlabs.com> Reviewed-By: Matt Robinson <matt@puppetlabs.com> (cherry picked from commit ac00e9e289f8fdc81f060e7dd289e1a8e0f133c0)
-rw-r--r--lib/puppet/provider/user/windows_adsi.rb71
-rw-r--r--spec/unit/provider/user/windows_adsi_spec.rb110
2 files changed, 181 insertions, 0 deletions
diff --git a/lib/puppet/provider/user/windows_adsi.rb b/lib/puppet/provider/user/windows_adsi.rb
new file mode 100644
index 000000000..9250def59
--- /dev/null
+++ b/lib/puppet/provider/user/windows_adsi.rb
@@ -0,0 +1,71 @@
+require 'puppet/util/adsi'
+
+Puppet::Type.type(:user).provide :windows_adsi do
+ desc "User management for Windows"
+
+ defaultfor :operatingsystem => :windows
+ confine :operatingsystem => :windows
+ confine :feature => :microsoft_windows
+
+ has_features :manages_homedir
+
+ def user
+ @user ||= Puppet::Util::ADSI::User.new(@resource[:name])
+ end
+
+ def groups
+ user.groups.join(',')
+ end
+
+ def groups=(groups)
+ user.set_groups(groups, @resource[:membership] == :minimum)
+ end
+
+ def create
+ @user = Puppet::Util::ADSI::User.create(@resource[:name])
+ [:comment, :home, :groups].each do |prop|
+ send("#{prop}=", @resource[prop]) if @resource[prop]
+ end
+ end
+
+ def exists?
+ Puppet::Util::ADSI::User.exists?(@resource[:name])
+ end
+
+ def delete
+ Puppet::Util::ADSI::User.delete(@resource[:name])
+ end
+
+ # Only flush if we created or modified a user, not deleted
+ def flush
+ @user.commit if @user
+ end
+
+ def comment
+ user['Description']
+ end
+
+ def comment=(value)
+ user['Description'] = value
+ end
+
+ def home
+ user['HomeDirectory']
+ end
+
+ def home=(value)
+ user['HomeDirectory'] = value
+ end
+
+ [:uid, :gid, :shell].each do |prop|
+ define_method(prop) { nil }
+
+ define_method("#{prop}=") do |v|
+ warning "No support for managing property #{prop} of user #{@resource[:name]} on Windows"
+ end
+ end
+
+ def self.instances
+ Puppet::Util::ADSI::User.map { |u| new(:ensure => :present, :name => u.name) }
+ end
+end
diff --git a/spec/unit/provider/user/windows_adsi_spec.rb b/spec/unit/provider/user/windows_adsi_spec.rb
new file mode 100644
index 000000000..073a3d328
--- /dev/null
+++ b/spec/unit/provider/user/windows_adsi_spec.rb
@@ -0,0 +1,110 @@
+#!/usr/bin/env ruby
+
+require 'spec_helper'
+
+describe Puppet::Type.type(:user).provider(:windows_adsi) do
+ let(:resource) do
+ Puppet::Type.type(:user).new(
+ :title => 'testuser',
+ :comment => 'Test J. User',
+ :provider => :windows_adsi
+ )
+ end
+
+ let(:provider) { resource.provider }
+
+ let(:connection) { stub 'connection' }
+
+ before :each do
+ Puppet::Util::ADSI.stubs(:computer_name).returns('testcomputername')
+ Puppet::Util::ADSI.stubs(:connect).returns connection
+ end
+
+ describe ".instances" do
+ it "should enumerate all users" do
+ names = ['user1', 'user2', 'user3']
+ stub_users = names.map{|n| stub(:name => n)}
+
+ connection.stubs(:execquery).with("select * from win32_useraccount").returns(stub_users)
+
+ described_class.instances.map(&:name).should =~ names
+ end
+ end
+
+ it "should provide access to a Puppet::Util::ADSI::User object" do
+ provider.user.should be_a(Puppet::Util::ADSI::User)
+ end
+
+ describe "when managing groups" do
+ it 'should return the list of groups as a comma-separated list' do
+ provider.user.stubs(:groups).returns ['group1', 'group2', 'group3']
+
+ provider.groups.should == 'group1,group2,group3'
+ end
+
+ it "should return absent if there are no groups" do
+ provider.user.stubs(:groups).returns []
+
+ provider.groups.should == ''
+ end
+
+ it 'should be able to add a user to a set of groups' do
+ resource[:membership] = :minimum
+ provider.user.expects(:set_groups).with('group1,group2', true)
+
+ provider.groups = 'group1,group2'
+
+ resource[:membership] = :inclusive
+ provider.user.expects(:set_groups).with('group1,group2', false)
+
+ provider.groups = 'group1,group2'
+ end
+ end
+
+ describe "when creating a user" do
+ it "should create the user on the system and set its other properties" do
+ resource[:groups] = ['group1', 'group2']
+ resource[:membership] = :inclusive
+ resource[:comment] = 'a test user'
+ resource[:home] = 'C:\Users\testuser'
+
+ user = stub 'user'
+ Puppet::Util::ADSI::User.expects(:create).with('testuser').returns user
+
+ user.stubs(:groups).returns(['group2', 'group3'])
+
+ user.expects(:set_groups).with('group1,group2', false)
+ user.expects(:[]=).with('Description', 'a test user')
+ user.expects(:[]=).with('HomeDirectory', 'C:\Users\testuser')
+
+ provider.create
+ end
+ end
+
+ it 'should be able to test whether a user exists' do
+ Puppet::Util::ADSI.stubs(:connect).returns stub('connection')
+ provider.should be_exists
+
+ Puppet::Util::ADSI.stubs(:connect).returns nil
+ provider.should_not be_exists
+ end
+
+ it 'should be able to delete a user' do
+ connection.expects(:Delete).with('user', 'testuser')
+
+ provider.delete
+ end
+
+ it "should commit the user when flushed" do
+ provider.user.expects(:commit)
+
+ provider.flush
+ end
+
+ [:uid, :gid, :shell].each do |prop|
+ it "should warn when trying to manage the #{prop} property" do
+ provider.expects(:warning).with { |msg| msg =~ /No support for managing property #{prop}/ }
+ provider.send("#{prop}=", 'foo')
+ end
+ end
+end