summaryrefslogtreecommitdiffstats
path: root/lib/puppet/util
diff options
context:
space:
mode:
Diffstat (limited to 'lib/puppet/util')
-rw-r--r--lib/puppet/util/adsi.rb278
-rw-r--r--lib/puppet/util/autoload.rb2
-rw-r--r--lib/puppet/util/cacher.rb82
-rw-r--r--lib/puppet/util/rdoc/parser.rb4
-rw-r--r--lib/puppet/util/run_mode.rb4
-rw-r--r--lib/puppet/util/settings.rb9
-rw-r--r--lib/puppet/util/settings/file_setting.rb2
7 files changed, 302 insertions, 79 deletions
diff --git a/lib/puppet/util/adsi.rb b/lib/puppet/util/adsi.rb
new file mode 100644
index 000000000..f865743e2
--- /dev/null
+++ b/lib/puppet/util/adsi.rb
@@ -0,0 +1,278 @@
+module Puppet::Util::ADSI
+ class << self
+ def connectable?(uri)
+ begin
+ !! connect(uri)
+ rescue
+ false
+ end
+ end
+
+ def connect(uri)
+ begin
+ WIN32OLE.connect(uri)
+ rescue Exception => e
+ raise Puppet::Error.new( "ADSI connection error: #{e}" )
+ end
+ end
+
+ def create(name, resource_type)
+ Puppet::Util::ADSI.connect(computer_uri).Create(resource_type, name)
+ end
+
+ def delete(name, resource_type)
+ Puppet::Util::ADSI.connect(computer_uri).Delete(resource_type, name)
+ end
+
+ def computer_name
+ unless @computer_name
+ buf = " " * 128
+ Win32API.new('kernel32', 'GetComputerName', ['P','P'], 'I').call(buf, buf.length.to_s)
+ @computer_name = buf.unpack("A*")
+ end
+ @computer_name
+ end
+
+ def computer_uri
+ "WinNT://#{computer_name}"
+ end
+
+ def wmi_resource_uri( host = '.' )
+ "winmgmts:{impersonationLevel=impersonate}!//#{host}/root/cimv2"
+ end
+
+ def uri(resource_name, resource_type)
+ "#{computer_uri}/#{resource_name},#{resource_type}"
+ end
+
+ def execquery(query)
+ connect(wmi_resource_uri).execquery(query)
+ end
+ end
+
+ class User
+ extend Enumerable
+
+ attr_accessor :native_user
+ attr_reader :name
+ def initialize(name, native_user = nil)
+ @name = name
+ @native_user = native_user
+ end
+
+ def native_user
+ @native_user ||= Puppet::Util::ADSI.connect(uri)
+ end
+
+ def self.uri(name)
+ Puppet::Util::ADSI.uri(name, 'user')
+ end
+
+ def uri
+ self.class.uri(name)
+ end
+
+ def self.logon(name, password)
+ fLOGON32_LOGON_NETWORK = 3
+ fLOGON32_PROVIDER_DEFAULT = 0
+
+ logon_user = Win32API.new("advapi32", "LogonUser", ['P', 'P', 'P', 'L', 'L', 'P'], 'L')
+ close_handle = Win32API.new("kernel32", "CloseHandle", ['P'], 'V')
+
+ token = ' ' * 4
+ if logon_user.call(name, "", password, fLOGON32_LOGON_NETWORK, fLOGON32_PROVIDER_DEFAULT, token) != 0
+ close_handle.call(token.unpack('L')[0])
+ true
+ else
+ false
+ end
+ end
+
+ def [](attribute)
+ native_user.Get(attribute)
+ end
+
+ def []=(attribute, value)
+ native_user.Put(attribute, value)
+ end
+
+ def commit
+ begin
+ native_user.SetInfo unless native_user.nil?
+ rescue Exception => e
+ raise Puppet::Error.new( "User update failed: #{e}" )
+ end
+ self
+ end
+
+ def password_is?(password)
+ self.class.logon(name, password)
+ end
+
+ def add_flag(flag_name, value)
+ flag = native_user.Get(flag_name) rescue 0
+
+ native_user.Put(flag_name, flag | value)
+
+ commit
+ end
+
+ def password=(password)
+ native_user.SetPassword(password)
+ commit
+ fADS_UF_DONT_EXPIRE_PASSWD = 0x10000
+ add_flag("UserFlags", fADS_UF_DONT_EXPIRE_PASSWD)
+ end
+
+ def groups
+ # WIN32OLE objects aren't enumerable, so no map
+ groups = []
+ native_user.Groups.each {|g| groups << g.Name}
+ groups
+ end
+
+ def add_to_groups(*group_names)
+ group_names.each do |group_name|
+ Puppet::Util::ADSI::Group.new(group_name).add_member(@name)
+ end
+ end
+ alias add_to_group add_to_groups
+
+ def remove_from_groups(*group_names)
+ group_names.each do |group_name|
+ Puppet::Util::ADSI::Group.new(group_name).remove_member(@name)
+ end
+ end
+ alias remove_from_group remove_from_groups
+
+ def set_groups(desired_groups, minimum = true)
+ return if desired_groups.nil? or desired_groups.empty?
+
+ desired_groups = desired_groups.split(',').map(&:strip)
+
+ current_groups = self.groups
+
+ # First we add the user to all the groups it should be in but isn't
+ groups_to_add = desired_groups - current_groups
+ add_to_groups(*groups_to_add)
+
+ # Then we remove the user from all groups it is in but shouldn't be, if
+ # that's been requested
+ groups_to_remove = current_groups - desired_groups
+ remove_from_groups(*groups_to_remove) unless minimum
+ end
+
+ def self.create(name)
+ new(name, Puppet::Util::ADSI.create(name, 'user'))
+ end
+
+ def self.exists?(name)
+ Puppet::Util::ADSI::connectable?(User.uri(name))
+ end
+
+ def self.delete(name)
+ Puppet::Util::ADSI.delete(name, 'user')
+ end
+
+ def self.each(&block)
+ wql = Puppet::Util::ADSI.execquery("select * from win32_useraccount")
+
+ users = []
+ wql.each do |u|
+ users << new(u.name, u)
+ end
+
+ users.each(&block)
+ end
+ end
+
+ class Group
+ extend Enumerable
+
+ attr_accessor :native_group
+ attr_reader :name
+ def initialize(name, native_group = nil)
+ @name = name
+ @native_group = native_group
+ end
+
+ def uri
+ self.class.uri(name)
+ end
+
+ def self.uri(name)
+ Puppet::Util::ADSI.uri(name, 'group')
+ end
+
+ def native_group
+ @native_group ||= Puppet::Util::ADSI.connect(uri)
+ end
+
+ def commit
+ begin
+ native_group.SetInfo unless native_group.nil?
+ rescue Exception => e
+ raise Puppet::Error.new( "Group update failed: #{e}" )
+ end
+ self
+ end
+
+ def add_members(*names)
+ names.each do |name|
+ native_group.Add(Puppet::Util::ADSI::User.uri(name))
+ end
+ end
+ alias add_member add_members
+
+ def remove_members(*names)
+ names.each do |name|
+ native_group.Remove(Puppet::Util::ADSI::User.uri(name))
+ end
+ end
+ alias remove_member remove_members
+
+ def members
+ # WIN32OLE objects aren't enumerable, so no map
+ members = []
+ native_group.Members.each {|m| members << m.Name}
+ members
+ end
+
+ def set_members(desired_members)
+ return if desired_members.nil? or desired_members.empty?
+
+ current_members = self.members
+
+ # First we add all missing members
+ members_to_add = desired_members - current_members
+ add_members(*members_to_add)
+
+ # Then we remove all extra members
+ members_to_remove = current_members - desired_members
+ remove_members(*members_to_remove)
+ end
+
+ def self.create(name)
+ new(name, Puppet::Util::ADSI.create(name, 'group'))
+ end
+
+ def self.exists?(name)
+ Puppet::Util::ADSI.connectable?(Group.uri(name))
+ end
+
+ def self.delete(name)
+ Puppet::Util::ADSI.delete(name, 'group')
+ end
+
+ def self.each(&block)
+ wql = Puppet::Util::ADSI.execquery( "select * from win32_group" )
+
+ groups = []
+ wql.each do |g|
+ groups << new(g.name, g)
+ end
+
+ groups.each(&block)
+ end
+ end
+end
diff --git a/lib/puppet/util/autoload.rb b/lib/puppet/util/autoload.rb
index 6537a4a4e..2e8710ab1 100644
--- a/lib/puppet/util/autoload.rb
+++ b/lib/puppet/util/autoload.rb
@@ -1,5 +1,4 @@
require 'puppet/util/warnings'
-require 'puppet/util/cacher'
# Autoload paths, either based on names or all at once.
class Puppet::Util::Autoload
@@ -7,7 +6,6 @@ class Puppet::Util::Autoload
include Puppet::Util
include Puppet::Util::Warnings
- include Puppet::Util::Cacher
include Puppet::Util::Autoload::FileCache
@autoloaders = {}
diff --git a/lib/puppet/util/cacher.rb b/lib/puppet/util/cacher.rb
index 3dddec0d4..136c9973e 100644
--- a/lib/puppet/util/cacher.rb
+++ b/lib/puppet/util/cacher.rb
@@ -1,25 +1,6 @@
require 'monitor'
module Puppet::Util::Cacher
- module Expirer
- attr_reader :timestamp
-
- # Cause all cached values to be considered expired.
- def expire
- @timestamp = Time.now
- end
-
- # Is the provided timestamp earlier than our expiration timestamp?
- # If it is, then the associated value is expired.
- def dependent_data_expired?(ts)
- return false unless timestamp
-
- timestamp > ts
- end
- end
-
- extend Expirer
-
# Our module has been extended in a class; we can only add the Instance methods,
# which become *class* methods in the class.
def self.extended(other)
@@ -40,27 +21,26 @@ module Puppet::Util::Cacher
module ClassMethods
# Provide a means of defining an attribute whose value will be cached.
# Must provide a block capable of defining the value if it's flushed..
- def cached_attr(name, options = {}, &block)
+ def cached_attr(name, ttl, &block)
init_method = "init_#{name}"
define_method(init_method, &block)
+ set_attr_ttl(name, ttl)
+
define_method(name) do
cached_value(name)
end
define_method(name.to_s + "=") do |value|
# Make sure the cache timestamp is set
- cache_timestamp
- value_cache.synchronize { value_cache[name] = value }
- end
-
- if ttl = options[:ttl]
- set_attr_ttl(name, ttl)
+ value_cache.synchronize do
+ value_cache[name] = value
+ set_expiration(name)
+ end
end
end
def attr_ttl(name)
- return nil unless @attr_ttls
@attr_ttls[name]
end
@@ -72,57 +52,25 @@ module Puppet::Util::Cacher
# Methods that get added to instances.
module InstanceMethods
-
- def expire
- # Only expire if we have an expirer. This is
- # mostly so that we can comfortably handle cases
- # like Puppet::Type instances, which use their
- # catalog as their expirer, and they often don't
- # have a catalog.
- if e = expirer
- e.expire
- end
- end
-
- def expirer
- Puppet::Util::Cacher
- end
-
private
- def cache_timestamp
- @cache_timestamp ||= Time.now
- end
-
def cached_value(name)
value_cache.synchronize do
- # Allow a nil expirer, in which case we regenerate the value every time.
- if expired_by_expirer?(name)
- value_cache.clear
- @cache_timestamp = Time.now
- elsif expired_by_ttl?(name)
- value_cache.delete(name)
+ if value_cache[name].nil? or expired_by_ttl?(name)
+ value_cache[name] = send("init_#{name}")
+ set_expiration(name)
end
- value_cache[name] = send("init_#{name}") unless value_cache.include?(name)
value_cache[name]
end
end
- def expired_by_expirer?(name)
- if expirer.nil?
- return true unless self.class.attr_ttl(name)
- end
- expirer.dependent_data_expired?(cache_timestamp)
- end
-
def expired_by_ttl?(name)
- return false unless self.class.respond_to?(:attr_ttl)
- return false unless ttl = self.class.attr_ttl(name)
-
- @ttl_timestamps ||= {}
- @ttl_timestamps[name] ||= Time.now
+ @attr_expirations[name] < Time.now
+ end
- (Time.now - @ttl_timestamps[name]) > ttl
+ def set_expiration(name)
+ @attr_expirations ||= {}
+ @attr_expirations[name] = Time.now + self.class.attr_ttl(name)
end
def value_cache
diff --git a/lib/puppet/util/rdoc/parser.rb b/lib/puppet/util/rdoc/parser.rb
index 762ce25f0..a8996ee9a 100644
--- a/lib/puppet/util/rdoc/parser.rb
+++ b/lib/puppet/util/rdoc/parser.rb
@@ -113,7 +113,9 @@ class Parser
Puppet::Module.modulepath.each do |mp|
# check that fullpath is a descendant of mp
dirname = fullpath
- while (dirname = File.dirname(dirname)) != '/'
+ previous = dirname
+ while (dirname = File.dirname(previous)) != previous
+ previous = dirname
return nil if File.identical?(dirname,mp)
end
end
diff --git a/lib/puppet/util/run_mode.rb b/lib/puppet/util/run_mode.rb
index 450cbf1a6..6028aef29 100644
--- a/lib/puppet/util/run_mode.rb
+++ b/lib/puppet/util/run_mode.rb
@@ -27,14 +27,14 @@ module Puppet
def conf_dir
which_dir(
- (Puppet.features.microsoft_windows? ? File.join(Dir::WINDOWS, "puppet", "etc") : "/etc/puppet"),
+ (Puppet.features.microsoft_windows? ? File.join(Dir::COMMON_APPDATA, "PuppetLabs", "puppet", "etc") : "/etc/puppet"),
"~/.puppet"
)
end
def var_dir
which_dir(
- (Puppet.features.microsoft_windows? ? File.join(Dir::WINDOWS, "puppet", "var") : "/var/lib/puppet"),
+ (Puppet.features.microsoft_windows? ? File.join(Dir::COMMON_APPDATA, "PuppetLabs", "puppet", "var") : "/var/lib/puppet"),
"~/.puppet/var"
)
end
diff --git a/lib/puppet/util/settings.rb b/lib/puppet/util/settings.rb
index 4559e9af3..caaf61b7b 100644
--- a/lib/puppet/util/settings.rb
+++ b/lib/puppet/util/settings.rb
@@ -2,13 +2,11 @@ require 'puppet'
require 'sync'
require 'getoptlong'
require 'puppet/external/event-loop'
-require 'puppet/util/cacher'
require 'puppet/util/loadedfile'
# The class for handling configuration files.
class Puppet::Util::Settings
include Enumerable
- include Puppet::Util::Cacher
require 'puppet/util/settings/setting'
require 'puppet/util/settings/file_setting'
@@ -401,11 +399,10 @@ class Puppet::Util::Settings
}
end
- # Cache this in an easily clearable way, since we were
- # having trouble cleaning it up after tests.
- cached_attr(:file) do
+ def file
+ return @file if @file
if path = self[:config] and FileTest.exist?(path)
- Puppet::Util::LoadedFile.new(path)
+ @file = Puppet::Util::LoadedFile.new(path)
end
end
diff --git a/lib/puppet/util/settings/file_setting.rb b/lib/puppet/util/settings/file_setting.rb
index 776398ef4..0fa65d846 100644
--- a/lib/puppet/util/settings/file_setting.rb
+++ b/lib/puppet/util/settings/file_setting.rb
@@ -86,7 +86,7 @@ class Puppet::Util::Settings::FileSetting < Puppet::Util::Settings::Setting
path = File.expand_path(path)
return nil unless type == :directory or create_files? or File.exist?(path)
- return nil if path =~ /^\/dev/
+ return nil if path =~ /^\/dev/ or path =~ /^[A-Z]:\/dev/i
resource = Puppet::Resource.new(:file, path)