Skip to content

Commit 84f75b7

Browse files
committed
(MODULES-5031) Modify facts for SQL Server 2016
Previously the custom facts for the module only supported SQL Server 2012 and 2014. This commit updates the facts to support usage on SQL Server 2016, and adds additional feature detection for features that have been added in Server 2016, or missed out on Server 2014.
1 parent a8d7398 commit 84f75b7

File tree

1 file changed

+68
-22
lines changed

1 file changed

+68
-22
lines changed

lib/puppet_x/sqlserver/features.rb

Lines changed: 68 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,31 @@
11
SQL_2012 ||= 'SQL_2012'
22
SQL_2014 ||= 'SQL_2014'
3+
SQL_2016 ||= 'SQL_2016'
4+
5+
ALL_SQL_VERSIONS = [SQL_2012, SQL_2014, SQL_2016]
36

47
module PuppetX
58
module Sqlserver
69
# https://msdn.microsoft.com/en-us/library/ms143786.aspx basic feature docs
710
class Features
811
private
912

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+
}
1329
}
1430

1531
SQL_REG_ROOT ||= 'Software\Microsoft\Microsoft SQL Server'
@@ -20,11 +36,12 @@ class Features
2036

2137
def self.connect(version)
2238
require 'win32ole'
23-
ver = SQL_WMI_PATH[version]
39+
ver = SQL_CONFIGURATION[version][:wmi_path]
2440
context = WIN32OLE.new('WbemScripting.SWbemNamedValueSet')
2541
context.Add("__ProviderArchitecture", 64)
2642
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)
2845
end
2946

3047
def self.get_parent_path(key_path)
@@ -118,9 +135,11 @@ def self.get_instance_features(reg_root, instance_name)
118135
# also reg Replication/IsInstalled set to 1
119136
'SQL_Replication_Core_Inst' => 'Replication', # SQL Server Replication
120137
# 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
124143
}
125144

126145
feat_root = "#{reg_root}\\ConfigurationState"
@@ -144,18 +163,25 @@ def self.get_instance_features(reg_root, instance_name)
144163

145164
def self.get_shared_features(version)
146165
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+
153178
# also WMI: SqlService WHERE SQLServiceType = 4 # MsDtsServer
154-
'SQL_DTS_Full' => 'IS', # Integration Services
179+
'SQL_DTS_Full' => 'IS', # Integration Services
155180
# currently ignoring Reporting Services Shared
181+
# currently ignoring R Server Standalone
156182
}
157183

158-
reg_ver = (version == SQL_2014 ? '120' : '110')
184+
reg_ver = SQL_CONFIGURATION[version][:registry_path]
159185
reg_root = "#{SQL_REG_ROOT}\\#{reg_ver}\\ConfigurationState"
160186

161187
get_sql_reg_val_features(reg_root, shared_features)
@@ -185,11 +211,27 @@ def self.get_shared_features(version)
185211
# }
186212
# }
187213
def self.get_instances
188-
version_instance_map = [SQL_2012, SQL_2014]
214+
version_instance_map = ALL_SQL_VERSIONS
189215
.map do |version|
216+
major_version = SQL_CONFIGURATION[version][:major_version]
217+
190218
instances = get_instance_names_by_ver(version)
191219
.map { |name| [ name, get_instance_info(version, name) ] }
192220

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+
193235
[ version, Hash[instances] ]
194236
end
195237

@@ -203,10 +245,9 @@ def self.get_instances
203245
# "SQL_2014" => []
204246
# }
205247
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
210251
end
211252

212253
# returns a hash containing instance details
@@ -225,8 +266,13 @@ def self.get_features
225266
# "RS"
226267
# ]
227268
# }
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?
229271
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?
230276
feats = get_instance_features(sql_instance['reg_root'], sql_instance['name'])
231277
sql_instance.merge({'features' => feats})
232278
end

0 commit comments

Comments
 (0)