[FACT-1082] COM initialization prior to ruby COM initialization Created: 2015/06/30  Updated: 2015/07/22  Resolved: 2015/07/07

Status: Closed
Project: Facter
Component/s: None
Affects Version/s: FACT 3.0.0
Fix Version/s: FACT 3.0.2

Type: Bug Priority: Major
Reporter: Travis Fields Assignee: Unassigned
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: 0 minutes
Time Spent: 10 minutes
Original Estimate: Not Specified

Template:
Story Points: 1
Sprint: Client 2015-07-08
Release Notes: Bug Fix
Release Notes Summary: Using WIN32OLE from Ruby as part of a custom fact in command-line Facter results in an error. This is fixed.

 Description   

OLE COM initialized prior to Ruby causing issue with later COM calls.
SQLSERVER Instances Fact
sqlserver ole calls

[4:01 PM] Ethan J. Brown: it looks like Facter initializes COM in the wmi class (inside Leatherman) at https://github.com/puppetlabs/leatherman/blob/master/windows/src/wmi.cc#L34
[4:01 PM] Ethan J. Brown: CoInitializeEx(0, COINIT_MULTITHREADED)
		Ruby initializes COM at https://github.com/ruby/ruby/blob/c19d37375074987b36413af6bf83df7262ce227d/ext/win32ole/win32ole.c#L...
[4:02 PM] Ethan J. Brown: hr = OleInitialize(NULL);
		so if you call Puppet -> Facter, everything is OK
[4:02 PM] Michael Smith: oh single vs multithreaded?
[4:02 PM] Ethan J. Brown: however if you call in the reverse to resolve a custom fact
		then barf
[4:03 PM] Ethan J. Brown: OleInitialize calls CoInitializeEx internally to initialize the COM library on the current apartment. Because OLE operations are not thread-safe, OleInitialize specifies the concurrency model as single-thread apartment.
		Once the concurrency model for an apartment is set, it cannot be changed. A call to OleInitialize on an apartment that was previously initialized as multithreaded will fail and return RPC_E_CHANGED_MODE.
		https://msdn.microsoft.com/en-us/library/windows/desktop/ms690134(v=vs.85).aspx
[4:04 PM] Michael Smith: yeah, so we accept that it might've been initialized with single-threaded, but ruby errors out
		so I guess we have to initialize apartmentthreaded? ugh
		We could do so only when loaded in ruby...
		Wait, I'm still not sure how that happens.
[4:06 PM] Travis Fields: it is when cfacter is called prior to ruby, if puppet is called first the fact that is returned is correct with no errors
[4:06 PM] Ethan J. Brown: the output from Travis is at https://gist.github.com/cyberious/52410266b650afd94b59
[4:06 PM] Peter Huene: facter initializes COM then tries to resolve a custom fact that uses ruby's COM support
		since ruby doesn't handle RPC_E_CHANGED_MODE it seems, boom
[4:07 PM] Ethan J. Brown: correct
[4:07 PM] Michael Smith: ok, so we just have to always use single-threaded.
		Well, we don't multi-thread queries to COM yet, so shouldn't cause any issues to change.



 Comments   
Comment by Michael Smith [ 2015/07/06 ]

Michael Smith need to handle merge to Leatherman.

https://github.com/puppetlabs/leatherman/pull/44

Comment by Shaigy Nixon [X] (Inactive) [ 2015/07/07 ]

Before fix:

 
Administrator@qbtu7afcpcjsiom ~
$ cat foo.rb
require 'win32ole'
Facter.add('foo') do
  setcode do
    'bar'
  end
end
 
Administrator@qbtu7afcpcjsiom ~
$ cmd /c facter foo --custom-dir ./
2015-07-07 21:38:30.705964 ERROR puppetlabs.facter - error while resolving custom facts in C:/cygwin64\home\Administrator\foo.rb: fail: OLE initialize
    HRESULT error code:0x80010106
      Cannot change thread mode after it is set.

After fix:
Validated on win2012r2-rubyx64 on stable SHA: fb45a01412998ccdadf7ac8a8084adb586e74832

Administrator@rzr0vbxn5bmfbhx ~
$ cmd /c facter --version
3.0.1 (commit 248b3c5fba9eaf879fdf9b62d59911c168f4cdfa)
 
Administrator@rzr0vbxn5bmfbhx ~
$ cat foo.rb
require 'win32ole'
 
Facter.add('foo') do
  setcode do
    'bar'
  end
end
 
Administrator@rzr0vbxn5bmfbhx ~
$ cmd /c facter foo --custom-dir ./
bar

Generated at Thu May 28 11:55:14 PDT 2020 using Jira 8.5.2#805002-sha1:a66f9354b9e12ac788984e5d84669c903a370049.