Please review pull request #643: (#12392) Windows eventlog opened by (joshcooper)
Description:
This commit adds an eventlog log destination and logs to it by default on Windows. As part of this, we now have a puppet message resource dll, which the install.rb script will register during installation. It also adds an acceptance test to verify that messages are being written to the eventlog on Windows.
- Opened: Mon Apr 09 16:21:39 UTC 2012
- Based on: puppetlabs:2.7.x (8ceaaf002a5562b6bd78541a25762e1e7740f933)
- Requested merge: joshcooper:ticket/2.7.x/12392-eventlog (8d2ff895175346ca419e586f6352ec7f8cfdcf06)
Diff follows:
diff --git a/acceptance/tests/windows/eventlog.rb b/acceptance/tests/windows/eventlog.rb
new file mode 100644
index 0000000..ab4f2a6
--- /dev/null
+++ b/acceptance/tests/windows/eventlog.rb
@@ -0,0 +1,26 @@
+test_name "Write to Windows eventlog"
+
+confine :to, :platform => 'windows'
+
+def get_cmd(host)
+ if options[:type] =~ /pe/
+ "#{host['puppetbindir']}/ruby"
+ else
+ 'ruby'
+ end
+end
+
+agents.each do |agent|
+ # get remote time
+ now = on(agent, "#{get_cmd(agent)} -e \"puts Time.now.utc.strftime('%m/%d/%Y %H:%M:%S')\"").stdout.chomp
+
+ # generate an error, no master on windows boxes
+ on agent, puppet_agent('--server', '127.0.0.1', '--test'), :acceptable_exit_codes => [1]
+
+ # make sure there's a Puppet error message in the log
+ # cygwin + ssh + wmic hangs trying to read stdin, so echo '' |
+ on agent, "cmd /c echo '' | wmic ntevent where \"LogFile='Application' and SourceName='Puppet' and TimeWritten >= '#{now}'\" get Message,Type /format:csv" do
+ fail_test "Event not found in Application event log" unless
+ stdout =~ /Could not retrieve catalog from remote server.*,Error/m
+ end
+end
diff --git a/conf/windows/eventlog/Rakefile b/conf/windows/eventlog/Rakefile
new file mode 100755
index 0000000..ff3df33
--- /dev/null
+++ b/conf/windows/eventlog/Rakefile
@@ -0,0 +1,32 @@
+require 'rubygems'
+require 'rake'
+require 'fileutils'
+require 'rbconfig'
+
+BASENAME = "puppetres"
+
+task :default do
+ sh 'rake -T'
+end
+
+desc 'Build puppet eventlog message dll'
+task :dist => ['out', "#{BASENAME}.dll"]
+
+directory 'out'
+
+rule '.rc' => '.mc' do |t|
+ sh "mc -b -r out -h out #{t.source}"
+end
+
+rule '.res' => '.rc' do |t|
+ sh "rc -nologo -r -fo out/#{t.name} out/#{t.source}"
+end
+
+rule '.dll' => '.res' do |t|
+ sh "link -nologo -dll -noentry -machine:x86 -out:out/#{t.name} out/#{t.source}"
+end
+
+desc 'Delete generated files'
+task :clean do
+ FileUtils.rm_rf('out')
+end
diff --git a/conf/windows/eventlog/puppetres.dll b/conf/windows/eventlog/puppetres.dll
new file mode 100755
index 0000000..f894500
Binary files /dev/null and b/conf/windows/eventlog/puppetres.dll differ
diff --git a/conf/windows/eventlog/puppetres.mc b/conf/windows/eventlog/puppetres.mc
new file mode 100755
index 0000000..7a9a05c
--- /dev/null
+++ b/conf/windows/eventlog/puppetres.mc
@@ -0,0 +1,18 @@
+MessageId=0x1
+SymbolicName=PUPPET_INFO
+Language=English
+%1
+.
+
+MessageId=0x2
+SymbolicName=PUPPET_WARN
+Language=English
+%1
+.
+
+MessageId=0x3
+SymbolicName=PUPPET_ERROR
+Language=English
+%1
+.
+
diff --git a/install.rb b/install.rb
index 126461a..a55d929 100755
--- a/install.rb
+++ b/install.rb
@@ -86,7 +86,29 @@ def do_configs(configs, target, strip = 'conf/')
else
FileUtils.install(cf, ocf, {:mode => 0644, :verbose => true})
end
- end
+ end
+
+ if $operatingsystem == 'windows'
+ src_dll = 'conf/windows/eventlog/puppetres.dll'
+ dst_dll = File.join(InstallOptions.bin_dir, 'puppetres.dll')
+ if $haveftools
+ File.install(src_dll, dst_dll, 0644, true)
+ else
+ FileUtils.install(src_dll, dst_dll, {:mode => 0644, :verbose => true})
+ end
+
+ require 'win32/registry'
+ include Win32::Registry::Constants
+
+ begin
+ Win32::Registry::HKEY_LOCAL_MACHINE.create('SYSTEM\CurrentControlSet\services\eventlog\Application\Puppet', KEY_ALL_ACCESS | 0x0100) do |reg|
+ reg.write_s('EventMessageFile', dst_dll.tr('/', '\\'))
+ reg.write_i('TypesSupported', 0x7)
+ end
+ rescue Win32::Registry::Error => e
+ warn "Failed to create puppet eventlog registry key: #{e}"
+ end
+ end
end
def do_bins(bins, target, strip = 's?bin/')
diff --git a/lib/puppet/feature/eventlog.rb b/lib/puppet/feature/eventlog.rb
new file mode 100644
index 0000000..e1b909d
--- /dev/null
+++ b/lib/puppet/feature/eventlog.rb
@@ -0,0 +1,6 @@
+require 'puppet/util/feature'
+
+if Puppet.features.microsoft_windows?
+ Puppet.features.rubygems?
+ Puppet.features.add(:eventlog, :libs => %{win32/eventlog})
+end
diff --git a/lib/puppet/util/log.rb b/lib/puppet/util/log.rb
index c0a94f9..000e01e 100644
--- a/lib/puppet/util/log.rb
+++ b/lib/puppet/util/log.rb
@@ -196,7 +196,9 @@ def Log.reopen
end
def self.setup_default
- Log.newdestination(Puppet.features.syslog? ? :syslog : Puppet[:puppetdlog])
+ Log.newdestination(
+ (Puppet.features.syslog? ? :syslog :
+ (Puppet.features.eventlog? ? :eventlog : Puppet[:puppetdlog])))
end
# Is the passed level a valid log level?
diff --git a/lib/puppet/util/log/destinations.rb b/lib/puppet/util/log/destinations.rb
index 607e112..364d5ed 100644
--- a/lib/puppet/util/log/destinations.rb
+++ b/lib/puppet/util/log/destinations.rb
@@ -228,3 +228,41 @@ def handle(msg)
end
end
+Puppet::Util::Log.newdesttype :eventlog do
+ def self.suitable?(obj)
+ Puppet.features.eventlog?
+ end
+
+ def initialize
+ @eventlog = Win32::EventLog.open("Application")
+ end
+
+ def to_native(level)
+ case level
+ when :debug,:info,:notice
+ [Win32::EventLog::INFO, 0x01]
+ when :warning
+ [Win32::EventLog::WARN, 0x02]
+ when :err,:alert,:emerg,:crit
+ [Win32::EventLog::ERROR, 0x03]
+ end
+ end
+
+ def handle(msg)
+ native_type, native_id = to_native(msg.level)
+
+ @eventlog.report_event(
+ :source => "Puppet",
+ :event_type => native_type,
+ :event_id => native_id,
+ :data ="" (msg.source and msg.source != 'Puppet' ? "#{msg.source}: " : '') + msg.to_s
+ )
+ end
+
+ def close
+ if @eventlog
+ @eventlog.close
+ @eventlog = nil
+ end
+ end
+end
diff --git a/spec/unit/util/log_spec.rb b/spec/unit/util/log_spec.rb
index 6dd365e..18d9b99 100755
--- a/spec/unit/util/log_spec.rb
+++ b/spec/unit/util/log_spec.rb
@@ -22,8 +22,17 @@
Puppet::Util::Log.setup_default
end
+ it "should fall back to :eventlog" do
+ Puppet.features.stubs(:syslog?).returns(false)
+ Puppet.features.stubs(:eventlog?).returns(true)
+ Puppet::Util::Log.expects(:newdestination).with(:eventlog)
+
+ Puppet::Util::Log.setup_default
+ end
+
it "should fall back to :file" do
Puppet.features.stubs(:syslog?).returns(false)
+ Puppet.features.stubs(:eventlog?).returns(false)
Puppet::Util::Log.expects(:newdestination).with(Puppet[:puppetdlog])
Puppet::Util::Log.setup_default
@@ -72,6 +81,46 @@
end
end
+ describe Puppet::Util::Log::DestEventlog, :if => Puppet.features.microsoft_windows? do
+ require 'win32/eventlog'
+
+ before :each do
+ Win32::EventLog.stubs(:open).returns(mock 'mylog')
+ Win32::EventLog.stubs(:report_event)
+ Win32::EventLog.stubs(:close)
+ Puppet.features.stubs(:eventlog?).returns(true)
+ end
+
+ it "should restrict its suitability" do
+ Puppet.features.expects(:eventlog?).returns(false)
+
+ Puppet::Util::Log::DestEventlog.suitable?('whatever').should == false
+ end
+
+ it "should open the 'Application' event log" do
+ Win32::EventLog.expects(:open).with('Application')
+
+ Puppet::Util::Log.newdestination(:eventlog)
+ end
+
+ it "should close the event log" do
+ log = mock('myeventlog')
+ log.expects(:close)
+ Win32::EventLog.expects(:open).returns(log)
+
+ Puppet::Util::Log.newdestination(:eventlog)
+ Puppet::Util::Log.close(:eventlog)
+ end
+
+ it "should handle each puppet log level" do
+ log = Puppet::Util::Log::DestEventlog.new
+
+ Puppet::Util::Log.eachlevel do |level|
+ log.to_native(level).should be_is_a(Array)
+ end
+ end
+ end
+
describe "instances" do
before do
Puppet::Util::Log.stubs(:newmessage)
-- You received this message because you are subscribed to the Google Groups "Puppet Developers" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to [email protected].
For more options, visit this group at http://groups.google.com/group/puppet-dev?hl=en.
