1
1
SQL_2012 ||= 'SQL_2012'
2
2
SQL_2014 ||= 'SQL_2014'
3
+ SQL_2016 ||= 'SQL_2016'
4
+
5
+ ALL_SQL_VERSIONS = [ SQL_2012 , SQL_2014 , SQL_2016 ]
3
6
4
7
module PuppetX
5
8
module Sqlserver
6
9
# https://msdn.microsoft.com/en-us/library/ms143786.aspx basic feature docs
7
10
class Features
8
11
private
9
12
10
- SQL_WMI_PATH ||= {
11
- SQL_2012 => 'ComputerManagement11' ,
12
- SQL_2014 => 'ComputerManagement12' ,
13
+ SQL_CONFIGURATION ||= {
14
+ SQL_2012 => {
15
+ :major_version => 11 ,
16
+ :wmi_path => 'ComputerManagement11' ,
17
+ :registry_path => '110' ,
18
+ } ,
19
+ SQL_2014 => {
20
+ :major_version => 12 ,
21
+ :wmi_path => 'ComputerManagement12' ,
22
+ :registry_path => '120' ,
23
+ } ,
24
+ SQL_2016 => {
25
+ :major_version => 13 ,
26
+ :wmi_path => 'ComputerManagement13' ,
27
+ :registry_path => '130' ,
28
+ }
13
29
}
14
30
15
31
SQL_REG_ROOT ||= 'Software\Microsoft\Microsoft SQL Server'
@@ -20,11 +36,12 @@ class Features
20
36
21
37
def self . connect ( version )
22
38
require 'win32ole'
23
- ver = SQL_WMI_PATH [ version ]
39
+ ver = SQL_CONFIGURATION [ version ] [ :wmi_path ]
24
40
context = WIN32OLE . new ( 'WbemScripting.SWbemNamedValueSet' )
25
41
context . Add ( "__ProviderArchitecture" , 64 )
26
42
locator = WIN32OLE . new ( 'WbemScripting.SWbemLocator' )
27
- locator . ConnectServer ( '' , "root/Microsoft/SqlServer/#{ ver } " , '' , '' , nil , nil , nil , context )
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 )
28
45
end
29
46
30
47
def self . get_parent_path ( key_path )
@@ -118,9 +135,11 @@ def self.get_instance_features(reg_root, instance_name)
118
135
# also reg Replication/IsInstalled set to 1
119
136
'SQL_Replication_Core_Inst' => 'Replication' , # SQL Server Replication
120
137
# also WMI: SqlService WHERE SQLServiceType = 1 # MSSQLSERVER
121
- 'SQL_Engine_Core_Inst' => 'SQLEngine' , # Database Engine Services
122
- 'SQL_FullText_Adv' => 'FullText' , # Full-Text and Semantic Extractions for Search
123
- 'SQL_DQ_Full' => 'DQ' , # Data Quality Services
138
+ 'SQL_Engine_Core_Inst' => 'SQLEngine' , # Database Engine Services
139
+ 'SQL_FullText_Adv' => 'FullText' , # Full-Text and Semantic Extractions for Search
140
+ 'SQL_DQ_Full' => 'DQ' , # Data Quality Services
141
+ 'sql_inst_mr' => 'ADVANCEDANALYTICS' , # R Services (In-Database)
142
+ 'SQL_Polybase_Core_Inst' => 'POLYBASE' , # PolyBase Query Service for External Data
124
143
}
125
144
126
145
feat_root = "#{ reg_root } \\ ConfigurationState"
@@ -144,18 +163,25 @@ def self.get_instance_features(reg_root, instance_name)
144
163
145
164
def self . get_shared_features ( version )
146
165
shared_features = {
147
- 'Connectivity_Full' => 'Conn' , # Client Tools Connectivity
148
- 'SDK_Full' => 'SDK' , # Client Tools SDK
149
- 'MDSCoreFeature' => 'MDS' , # Master Data Services
150
- 'Tools_Legacy_Full' => 'BC' , # Client Tools Backwards Compatibility
151
- 'SQL_SSMS_Full' => 'ADV_SSMS' , # Management Tools - Complete
152
- 'SQL_SSMS_Adv' => 'SSMS' , # Management Tools - Basic
166
+ 'Connectivity_Full' => 'Conn' , # Client Tools Connectivity
167
+ 'SDK_Full' => 'SDK' , # Client Tools SDK
168
+ 'MDSCoreFeature' => 'MDS' , # Master Data Services
169
+ 'Tools_Legacy_Full' => 'BC' , # Client Tools Backwards Compatibility
170
+ 'SQL_SSMS_Full' => 'ADV_SSMS' , # Management Tools - Complete (Does not exist in SQL 2016)
171
+ 'SQL_SSMS_Adv' => 'SSMS' , # Management Tools - Basic (Does not exist in SQL 2016)
172
+ 'SQL_DQ_CLIENT_Full' => 'DQC' , # Data Quality Client
173
+ 'SQL_BOL_Components' => 'BOL' , # Documentation Components
174
+ 'SQL_DReplay_Controller' => 'DREPLAY_CTLR' , # Distributed Replay Controller
175
+ 'SQL_DReplay_Client' => 'DREPLAY_CLT' , # Distributed Replay Client
176
+ 'sql_shared_mr' => 'SQL_SHARED_MR' , # R Server (Standalone)
177
+
153
178
# also WMI: SqlService WHERE SQLServiceType = 4 # MsDtsServer
154
- 'SQL_DTS_Full' => 'IS' , # Integration Services
179
+ 'SQL_DTS_Full' => 'IS' , # Integration Services
155
180
# currently ignoring Reporting Services Shared
181
+ # currently ignoring R Server Standalone
156
182
}
157
183
158
- reg_ver = ( version == SQL_2014 ? '120' : '110' )
184
+ reg_ver = SQL_CONFIGURATION [ version ] [ :registry_path ]
159
185
reg_root = "#{ SQL_REG_ROOT } \\ #{ reg_ver } \\ ConfigurationState"
160
186
161
187
get_sql_reg_val_features ( reg_root , shared_features )
@@ -185,11 +211,27 @@ def self.get_shared_features(version)
185
211
# }
186
212
# }
187
213
def self . get_instances
188
- version_instance_map = [ SQL_2012 , SQL_2014 ]
214
+ version_instance_map = ALL_SQL_VERSIONS
189
215
. map do |version |
216
+ major_version = SQL_CONFIGURATION [ version ] [ :major_version ]
217
+
190
218
instances = get_instance_names_by_ver ( version )
191
219
. map { |name | [ name , get_instance_info ( version , name ) ] }
192
220
221
+ # Instance names are unique on a single host, but not for a particular SQL Server version therefore
222
+ # it's possible to request information for a valid instance_name but not for version. In this case
223
+ # we just reject any instances that have no information
224
+ instances . reject! { |value | value [ 1 ] . nil? }
225
+
226
+ # Unfortunately later SQL versions can return previous version SQL instances. We can weed these out
227
+ # by inspecting the major version of the instance_version
228
+ instances . reject! do |value |
229
+ return true if value [ 1 ] [ 'version' ] . nil?
230
+ ver = Gem ::Version . new ( value [ 1 ] [ 'version' ] )
231
+ # Segment 0 is the major version number of the SQL Instance
232
+ ver . segments [ 0 ] != major_version
233
+ end
234
+
193
235
[ version , Hash [ instances ] ]
194
236
end
195
237
@@ -203,10 +245,9 @@ def self.get_instances
203
245
# "SQL_2014" => []
204
246
# }
205
247
def self . get_features
206
- {
207
- SQL_2012 => get_shared_features ( SQL_2012 ) ,
208
- SQL_2014 => get_shared_features ( SQL_2014 ) ,
209
- }
248
+ features = { }
249
+ ALL_SQL_VERSIONS . each { |version | features [ version ] = get_shared_features ( version ) }
250
+ features
210
251
end
211
252
212
253
# returns a hash containing instance details
@@ -225,8 +266,13 @@ def self.get_features
225
266
# "RS"
226
267
# ]
227
268
# }
228
- def self . get_instance_info ( version = SQL_2014 , instance_name )
269
+ def self . get_instance_info ( version , instance_name )
270
+ return nil if version . nil?
229
271
sql_instance = get_wmi_instance_info ( version , instance_name )
272
+ # Instance names are unique on a single host, but not for a particular SQL Server version therefore
273
+ # it's possible to request information for a valid instance_name but not for version. In this case
274
+ # we just return nil.
275
+ return nil if sql_instance [ 'reg_root' ] . nil?
230
276
feats = get_instance_features ( sql_instance [ 'reg_root' ] , sql_instance [ 'name' ] )
231
277
sql_instance . merge ( { 'features' => feats } )
232
278
end
0 commit comments