1
+ require 'puppet/util/windows'
2
+
1
3
SQL_2012 ||= 'SQL_2012'
2
4
SQL_2014 ||= 'SQL_2014'
3
5
SQL_2016 ||= 'SQL_2016'
@@ -10,39 +12,26 @@ module Sqlserver
10
12
class Features
11
13
private
12
14
15
+ include Puppet ::Util ::Windows ::Registry
16
+ extend Puppet ::Util ::Windows ::Registry
17
+
13
18
SQL_CONFIGURATION ||= {
14
19
SQL_2012 => {
15
20
:major_version => 11 ,
16
- :wmi_path => 'ComputerManagement11' ,
17
21
:registry_path => '110' ,
18
22
} ,
19
23
SQL_2014 => {
20
24
:major_version => 12 ,
21
- :wmi_path => 'ComputerManagement12' ,
22
25
:registry_path => '120' ,
23
26
} ,
24
27
SQL_2016 => {
25
28
:major_version => 13 ,
26
- :wmi_path => 'ComputerManagement13' ,
27
29
:registry_path => '130' ,
28
30
}
29
31
}
30
32
31
33
SQL_REG_ROOT ||= 'Software\Microsoft\Microsoft SQL Server'
32
-
33
- # http://msdn.microsoft.com/en-us/library/windows/desktop/aa384129(v=vs.85).aspx
34
- KEY_WOW64_64KEY ||= 0x100
35
- KEY_READ ||= 0x20019
36
-
37
- def self . connect ( version )
38
- require 'win32ole'
39
- ver = SQL_CONFIGURATION [ version ] [ :wmi_path ]
40
- context = WIN32OLE . new ( 'WbemScripting.SWbemNamedValueSet' )
41
- context . Add ( "__ProviderArchitecture" , 64 )
42
- locator = WIN32OLE . new ( 'WbemScripting.SWbemLocator' )
43
- # WMI Path must use backslashes. Ruby 2.3 can cause crashes with forward slashes
44
- locator . ConnectServer ( nil , "root\\ Microsoft\\ SqlServer\\ #{ ver } " , nil , nil , nil , nil , nil , context )
45
- end
34
+ HKLM ||= 'HKEY_LOCAL_MACHINE'
46
35
47
36
def self . get_parent_path ( key_path )
48
37
# should be the same as SQL_REG_ROOT
@@ -55,81 +44,66 @@ def self.get_reg_key_val(win32_reg_key, val_name, reg_type)
55
44
nil
56
45
end
57
46
58
- def self . get_sql_reg_val_features ( key_name , reg_val_feat_hash )
59
- require 'win32/registry'
47
+ def self . key_exists? ( path )
48
+ begin
49
+ open ( HKLM , path , KEY_READ | KEY64 ) { }
50
+ return true
51
+ rescue
52
+ return false
53
+ end
54
+ end
60
55
56
+ def self . get_sql_reg_val_features ( key_name , reg_val_feat_hash )
61
57
vals = [ ]
62
-
63
58
begin
64
- hklm = Win32 ::Registry ::HKEY_LOCAL_MACHINE
65
- vals = hklm . open ( key_name , KEY_READ | KEY_WOW64_64KEY ) do |key |
59
+ vals = open ( HKLM , key_name , KEY_READ | KEY64 ) do |key |
66
60
reg_val_feat_hash
67
61
. select { |val_name , _ | get_reg_key_val ( key , val_name , Win32 ::Registry ::REG_DWORD ) == 1 }
68
62
. map { |_ , feat_name | feat_name }
69
63
end
70
- rescue Win32 :: Registry ::Error # subkey doesn't exist
64
+ rescue Puppet :: Util :: Windows ::Error # subkey doesn't exist
71
65
end
72
66
73
67
vals
74
68
end
75
69
76
- def self . get_sql_reg_key_features ( key_name , reg_key_feat_hash , instance_name )
77
- require 'win32/registry'
70
+ def self . get_reg_instance_info ( friendly_version )
71
+ instance_root = 'SOFTWARE\Microsoft\Microsoft SQL Server\Instance Names'
72
+ return [ ] unless key_exists? ( instance_root )
73
+ discovered = { }
74
+ open ( HKLM , "#{ instance_root } " , KEY_READ | KEY64 ) do |registry |
75
+ each_key ( registry ) do |instance_type , _ |
76
+ open ( HKLM , "#{ instance_root } \\ #{ instance_type } " , KEY_READ | KEY64 ) do |instance |
77
+ each_value ( instance ) do |short_name , _ , long_name |
78
+ root = "Software\\ Microsoft\\ Microsoft SQL Server\\ #{ long_name } "
79
+ discovered [ short_name ] ||= {
80
+ 'name' => short_name ,
81
+ 'reg_root' => [ ] ,
82
+ 'version' => open ( HKLM , "#{ root } \\ MSSQLServer\\ CurrentVersion" , KEY_READ | KEY64 ) { |r | values ( r ) [ 'CurrentVersion' ] } ,
83
+ 'version_friendly' => friendly_version
84
+ }
85
+
86
+ discovered [ short_name ] [ 'reg_root' ] . push ( root )
87
+ end
88
+ end
89
+ end
90
+ end
91
+ discovered . values
92
+ end
78
93
94
+ def self . get_sql_reg_key_features ( key_name , reg_key_feat_hash , instance_name )
79
95
installed = reg_key_feat_hash . select do |subkey , feat_name |
80
96
begin
81
- hklm = Win32 ::Registry ::HKEY_LOCAL_MACHINE
82
- hklm . open ( "#{ key_name } \\ #{ subkey } " , KEY_READ | KEY_WOW64_64KEY ) do |feat_key |
97
+ open ( HKLM , "#{ key_name } \\ #{ subkey } " , KEY_READ | KEY64 ) do |feat_key |
83
98
get_reg_key_val ( feat_key , instance_name , Win32 ::Registry ::REG_SZ )
84
99
end
85
- rescue Win32 :: Registry ::Error # subkey doesn't exist
100
+ rescue Puppet :: Util :: Windows ::Error # subkey doesn't exist
86
101
end
87
102
end
88
103
89
104
installed . values
90
105
end
91
106
92
- def self . get_wmi_property_values ( wmi , query , prop_name = 'PropertyStrValue' )
93
- vals = [ ]
94
-
95
- wmi . ExecQuery ( query ) . each do |v |
96
- vals . push ( v . Properties_ ( prop_name ) . Value )
97
- end
98
-
99
- vals
100
- end
101
-
102
- def self . get_instance_names_by_ver ( version )
103
- query = 'SELECT InstanceName FROM ServerSettings'
104
- get_wmi_property_values ( connect ( version ) , query , 'InstanceName' )
105
- rescue WIN32OLERuntimeError => e # version doesn't exist
106
- # WBEM_E_INVALID_NAMESPACE from wbemcli.h
107
- return [ ] if e . message =~ /8004100e/im
108
- raise
109
- end
110
-
111
- def self . get_sql_property_values ( version , instance_name , property_name )
112
- query = <<-END
113
- SELECT * FROM SqlServiceAdvancedProperty
114
- WHERE PropertyName='#{ property_name } '
115
- AND SqlServiceType=1 AND ServiceName LIKE '%#{ instance_name } '
116
- END
117
- # WMI LIKE query to substring match since ServiceName will be of the format
118
- # MSSQLSERVER (first install) or MSSQL$MSSQLSERVER (second install)
119
-
120
- get_wmi_property_values ( connect ( version ) , query )
121
- end
122
-
123
- def self . get_wmi_instance_info ( version , instance_name )
124
- {
125
- 'name' => instance_name ,
126
- 'version_friendly' => version ,
127
- 'version' => get_sql_property_values ( version , instance_name , 'VERSION' ) . first ,
128
- # typically Software\Microsoft\Microsoft SQL Server\MSSQL11.MSSQLSERVER
129
- 'reg_root' => get_sql_property_values ( version , instance_name , 'REGROOT' ) . first ,
130
- }
131
- end
132
-
133
107
def self . get_instance_features ( reg_root , instance_name )
134
108
instance_features = {
135
109
# also reg Replication/IsInstalled set to 1
@@ -215,8 +189,9 @@ def self.get_instances
215
189
. map do |version |
216
190
major_version = SQL_CONFIGURATION [ version ] [ :major_version ]
217
191
218
- instances = get_instance_names_by_ver ( version )
219
- . map { |name | [ name , get_instance_info ( version , name ) ] }
192
+ instances = get_reg_instance_info ( version ) . map do |instance |
193
+ [ instance [ 'name' ] , get_instance_info ( version , instance ) ]
194
+ end
220
195
221
196
# Instance names are unique on a single host, but not for a particular SQL Server version therefore
222
197
# it's possible to request information for a valid instance_name but not for version. In this case
@@ -266,15 +241,17 @@ def self.get_features
266
241
# "RS"
267
242
# ]
268
243
# }
269
- def self . get_instance_info ( version , instance_name )
244
+ def self . get_instance_info ( version , sql_instance )
270
245
return nil if version . nil?
271
- sql_instance = get_wmi_instance_info ( version , instance_name )
272
246
# Instance names are unique on a single host, but not for a particular SQL Server version therefore
273
247
# it's possible to request information for a valid instance_name but not for version. In this case
274
248
# we just return nil.
275
249
return nil if sql_instance [ 'reg_root' ] . nil?
276
- feats = get_instance_features ( sql_instance [ 'reg_root' ] , sql_instance [ 'name' ] )
277
- sql_instance . merge ( { 'features' => feats } )
250
+
251
+ feats = sql_instance [ 'reg_root' ] . map do |reg_root |
252
+ get_instance_features ( reg_root , sql_instance [ 'name' ] )
253
+ end
254
+ sql_instance . merge ( { 'features' => feats . uniq } )
278
255
end
279
256
end
280
257
end
0 commit comments