From 339fe569ce6bcaa2694ddd06622fd241ea50a7e8 Mon Sep 17 00:00:00 2001 From: Travis Fields Date: Sun, 19 Apr 2015 22:10:12 -0700 Subject: [PATCH] (FM-2303) - Added support for install_switches and support there of Add init class to insert file required to run sqlserver discovery Refactor discovery to be ran with facter instead of manually by provider, this will help to expose other facts to different defines and providers on the system --- files/sqlserver.psm1 | 110 ++++++++++++++++++ lib/facter/sqlserver_hash.rb | 27 +++++ lib/facter/sqlserver_instances_array.rb | 31 +++++ lib/puppet/provider/sqlserver.rb | 41 ------- .../provider/sqlserver_features/mssql.rb | 8 +- .../provider/sqlserver_instance/mssql.rb | 21 +--- lib/puppet/type/sqlserver_features.rb | 1 + lib/puppet/type/sqlserver_instance.rb | 2 + manifests/config.pp | 10 +- manifests/init.pp | 21 ++++ 10 files changed, 204 insertions(+), 68 deletions(-) create mode 100644 files/sqlserver.psm1 create mode 100755 lib/facter/sqlserver_hash.rb create mode 100755 lib/facter/sqlserver_instances_array.rb create mode 100644 manifests/init.pp diff --git a/files/sqlserver.psm1 b/files/sqlserver.psm1 new file mode 100644 index 00000000..58829e84 --- /dev/null +++ b/files/sqlserver.psm1 @@ -0,0 +1,110 @@ + +function Get-RunDiscovery(){ + $k = gi 'HKLM:\\Software\\Microsoft\\Microsoft SQL Server' + $sqlserver = @{} + $shared_code = "" + $ver_info = @{} + @("110","120") | %{ + $version = $k.OpenSubKey($_) + if ( $version -ne $null) { + $version_info = @{} + @("SharedCode","VerSpecificRootDir") | %{ + if ($version.GetValue($_,$null) -ne $null){ + $version_info.Add($_, $version.GetValue($_)) + } + } + if ($version_info.Count -ne 0) { + $ver_info.Add($_,$version_info) + } + } + } + $report_locations = @("C:\\Program Files\\Microsoft SQL Server\\*\\Setup Bootstrap\\Log\\*\\SqlDiscoveryReport.xml", + "C:\\Program Files (x86)\\Microsoft SQL Server\\*\\Setup Bootstrap\\Log\\*\\SqlDiscoveryReport.xml") + $sqlserver.Add('VerSpecific',$ver_info) + $ver_hash = @{'120'='SqlServer2014';'110' = 'SqlServer2012'} + $ver_hash.Keys | %{ + if ($ver_info.ContainsKey($_) -and + $ver_info[$_].ContainsKey("VerSpecificRootDir")) { + $verSpecificRootDir = $sqlserver[$_].VerSpecificRootDir + } + + $sqlversion = $ver_hash[$_] + if(Test-Path "$verSpecificRootDir\\Setup Bootstrap\\$sqlversion\\setup.exe"){ + pushd "$verSpecificRootDir\\Setup Bootstrap\\$sqlversion\\" + Start-Process -FilePath .\\setup.exe -ArgumentList @("/Action=RunDiscovery","/q") -Wait -WindowStyle Hidden + $report_locations += "$verSpecificRootDir\\Setup Bootstrap\\Log\\*\\SqlDiscoveryReport.xml" + popd + } + elseif(Test-Path "C:\\Program Files\\Microsoft SQL Server\\$_\\Setup Bootstrap\\$sqlversion\\setup.exe"){ + pushd "C:\\Program Files\\Microsoft SQL Server\\$_\\Setup Bootstrap\\$sqlversion\\" + Start-Process -FilePath .\\setup.exe -ArgumentList @("/Action=RunDiscovery","/q") -Wait -WindowStyle Hidden + popd + } + elseif(Test-Path "C:\\Program Files (x86)\\Microsoft SQL Server\\$_\\Setup Bootstrap\\$sqlversion\\setup.exe"){ + pushd "C:\\Program Files (x86)\\Microsoft SQL Server\\$_\\Setup Bootstrap\\$sqlversion\\" + Start-Process -FilePath .\\setup.exe -ArgumentList @("/Action=RunDiscovery","/q") -Wait -WindowStyle Hidden + popd + } + } + $instances = @($k.GetValue("InstalledInstances")) + if ($instances -ne $null -and $instances.Count -gt 0) { + $instances | foreach { + $instancedata = @{} + if ($k.GetSubKeyNames().Contains("MSSQL12.$_")){ + $subkey = $k.OpenSubKey("MSSQL12.$_") + }elseif($k.GetSubKeyNames().Contains("MSSQL11.$_")){ + $subkey = $k.OpenSubKey("MSSQL11.$_") + } + @("LoginMode", "DefaultData", "DefaultLog","BackupDirectory") | % { + $value = $subkey.OpenSubKey("MSSQLServer").GetValue($_,$null) + if ($value -ne $null){ + $instancedata[$_] = $value + } + } + @("Version","SQLPath","SQLBinRoot","Language","Edition","SQLGroup","Colation","SQLDataRoot") | % { + $value = $subkey.OpenSubKey("Setup").GetValue($_, $null) + if ($value -ne $null){ + $instancedata[$_] = $value + } + } + $sqlserver.Add($_,$instancedata) + } + $sqlserver.Add("Instances",@($instances)) + }else{ + $instances = @() + } + $file = gci $report_locations -ErrorAction Ignore | sort -Descending | select -First 1 + if($file -ne $null) { + [xml] $xml = cat $file + $json = $xml.ArrayOfDiscoveryInformation.DiscoveryInformation + foreach($instance in ($json | % { $_.Instance } | Get-Unique )){ + $features = @() + $json | %{ + if ($_.Features -eq "None"){ + break + } + if($_.instance -eq $instance){ + $features += $_.feature + } + } + if($instance -eq "" ){ + if ($features -ne $null) { + $sqlserver.Add("Features",@($features)) + } + }else{ + if (!($sqlserver.ContainsKey($instance))){ + $sqlserver.Add($instance,@{}) + } + if ($features -ne $null){ + $sqlserver[$instance].Add("Features",@($features)) + } + } + } + if ($instances -eq $null -or $instances.Count -eq 0){ + $sqlserver.Add("Instances",@(($json | % { $_.Instance } | Get-Unique ))) + } + + } + Write-Host (ConvertTo-Json $sqlserver) +} + diff --git a/lib/facter/sqlserver_hash.rb b/lib/facter/sqlserver_hash.rb new file mode 100755 index 00000000..92300167 --- /dev/null +++ b/lib/facter/sqlserver_hash.rb @@ -0,0 +1,27 @@ +require 'tempfile' + +Facter.add(:sqlserver_hash) do + confine :osfamily => :windows + + setcode do + powershell = if File.exists?("#{ENV['SYSTEMROOT']}\\sysnative\\WindowsPowershell\\v1.0\\powershell.exe") + "#{ENV['SYSTEMROOT']}\\sysnative\\WindowsPowershell\\v1.0\\powershell.exe" + else + 'powershell.exe' + end + ps_args = '-NoProfile -NonInteractive -NoLogo -ExecutionPolicy Bypass' + + discovery = <<-DISCOVERY +Import-Module 'C:\\Program Files\\Microsoft SQL Server\\.puppet\\sqlserver.psm1'; +Get-RunDiscovery + DISCOVERY + discovery_script = Tempfile.new(['puppet-sqlserver', '.ps1']) + discovery_script.write(discovery) + discovery_script.flush + begin + result = Facter::Core::Execution.exec("#{powershell} #{ps_args} -Command - < \"#{discovery_script.path}\"") + JSON.parse(result) unless result.empty? + rescue + end + end +end diff --git a/lib/facter/sqlserver_instances_array.rb b/lib/facter/sqlserver_instances_array.rb new file mode 100755 index 00000000..6a44527e --- /dev/null +++ b/lib/facter/sqlserver_instances_array.rb @@ -0,0 +1,31 @@ +require 'tempfile' + +Facter.add(:sqlserver_instance_array) do + confine :osfamily => :windows + + setcode do + powershell = if File.exists?("#{ENV['SYSTEMROOT']}\\sysnative\\WindowsPowershell\\v1.0\\powershell.exe") + "#{ENV['SYSTEMROOT']}\\sysnative\\WindowsPowershell\\v1.0\\powershell.exe" + elsif File.exists?("#{ENV['SYSTEMROOT']}\\system32\\WindowsPowershell\\v1.0\\powershell.exe") + "#{ENV['SYSTEMROOT']}\\system32\\WindowsPowershell\\v1.0\\powershell.exe" + else + 'powershell.exe' + end + ps_args = '-NoProfile -NonInteractive -NoLogo -ExecutionPolicy Bypass' + + instances = <<-INSTANCES +$k = gi 'HKLM:\\SOFTWARE\\Microsoft\\Microsoft SQL Server' +$values = $k.GetValue('InstalledInstances') +$instances = $values -join ',' +Write-Host $instances + INSTANCES + tempfile = Tempfile.new(['instances', '.ps1']) + tempfile.write(instances) + tempfile.flush + begin + result = Facter::Core::Execution.exec("#{powershell} #{ps_args} -Command - < \"#{tempfile.path}\"") + JSON.parse(result) unless result.empty? + rescue + end + end +end diff --git a/lib/puppet/provider/sqlserver.rb b/lib/puppet/provider/sqlserver.rb index 213079d7..61deaa38 100644 --- a/lib/puppet/provider/sqlserver.rb +++ b/lib/puppet/provider/sqlserver.rb @@ -78,47 +78,6 @@ def not_nil_and_not_empty?(obj) !obj.nil? and !obj.empty? end - def self.run_discovery_script - discovery = <<-DISCOVERY - if(Test-Path 'C:\\Program Files\\Microsoft SQL Server\\120\\Setup Bootstrap\\SQLServer2014\\setup.exe'){ - pushd 'C:\\Program Files\\Microsoft SQL Server\\120\\Setup Bootstrap\\SQLServer2014\\' - Start-Process -FilePath .\\setup.exe -ArgumentList @("/Action=RunDiscovery","/q") -Wait -WindowStyle Hidden - popd -}elseif(Test-Path 'C:\\Program Files\\Microsoft SQL Server\\110\\Setup Bootstrap\\SQLServer2012\\setup.exe'){ - pushd 'C:\\Program Files\\Microsoft SQL Server\\110\\Setup Bootstrap\\SQLServer2012\\' - Start-Process -FilePath .\\setup.exe -ArgumentList @("/Action=RunDiscovery","/q") -Wait -WindowStyle Hidden - popd -} - -$file = gci 'C:\\Program Files\\Microsoft SQL Server\\*\\Setup Bootstrap\\Log\\*\\SqlDiscoveryReport.xml' -ErrorAction Ignore | sort -Descending | select -First 1 -if($file -ne $null) { - [xml] $xml = cat $file - $json = $xml.ArrayOfDiscoveryInformation.DiscoveryInformation - $hash = @{"instances" = @();"TimeStamp"= ("{0:yyyy-MM-dd HH:mm:ss}" -f $file.CreationTime)} - foreach($instance in ($json | % { $_.Instance } | Get-Unique )){ - $features = @() - $json | %{ - if($_.instance -eq $instance){ - $features += $_.feature - } - } - if($instance -eq "" ){ - $hash.Add("Generic Features",$features) - }else{ - $hash["instances"] += $instance - $hash.Add($instance,@{"features"=$features}) - } - } - $file.Directory.Delete($true) - Write-Host (ConvertTo-Json $hash) -}else{ - Write-host ("{}") -} - DISCOVERY - result = powershell([discovery]) - JSON.parse(result) - end - def self.run_install_dot_net install_dot_net = <<-DOTNET Install-WindowsFeature NET-Framework-Core diff --git a/lib/puppet/provider/sqlserver_features/mssql.rb b/lib/puppet/provider/sqlserver_features/mssql.rb index b3d1387a..026a0e53 100644 --- a/lib/puppet/provider/sqlserver_features/mssql.rb +++ b/lib/puppet/provider/sqlserver_features/mssql.rb @@ -5,14 +5,14 @@ def self.instances instances = [] - jsonResult = Puppet::Provider::Sqlserver.run_discovery_script - debug "Parsing json result #{jsonResult}" - if jsonResult.has_key?('Generic Features') + sqlserver_hash = Facter.value(:sqlserver_hash) + debug "Parsing json result #{sqlserver_hash}" + if sqlserver_hash != nil && sqlserver_hash.has_key?('Features') existing_instance = {:name => "Generic Features", :ensure => :present, :features => PuppetX::Sqlserver::ServerHelper.translate_features( - jsonResult['Generic Features']).sort! + sqlserver_hash['Features']).sort! } debug "Parsed features = #{existing_instance[:features]}" diff --git a/lib/puppet/provider/sqlserver_instance/mssql.rb b/lib/puppet/provider/sqlserver_instance/mssql.rb index 58210443..66d53898 100644 --- a/lib/puppet/provider/sqlserver_instance/mssql.rb +++ b/lib/puppet/provider/sqlserver_instance/mssql.rb @@ -8,15 +8,15 @@ def self.instances instances = [] - jsonResult = Puppet::Provider::Sqlserver.run_discovery_script - debug "Parsing json result #{jsonResult}" - if jsonResult.has_key?('instances') - jsonResult['instances'].each do |instance_name| + sqlserver_hash = Facter.value(:sqlserver_hash) + debug "Parsing json result #{sqlserver_hash}" + if sqlserver_hash != nil && sqlserver_hash.has_key?('Instances') + sqlserver_hash['Instances'].each do |instance_name| existing_instance = {:name => instance_name, :ensure => :present, :features => PuppetX::Sqlserver::ServerHelper.translate_features( - jsonResult[instance_name]['features']).sort! + sqlserver_hash[instance_name]['Features']).sort! } instance = new(existing_instance) instances << instance @@ -70,17 +70,6 @@ def create else installNet35 add_features(@resource[:features]) - # cmd_args = build_cmd_args(@resource[:features]) - # begin - # config_file = create_temp_for_install_switch - # cmd_args << "/ConfigurationFile=\"#{config_file.path}\"" unless config_file.nil? - # try_execute(cmd_args) - # ensure - # if config_file - # config_file.close - # config_file.unlink - # end - # end end end diff --git a/lib/puppet/type/sqlserver_features.rb b/lib/puppet/type/sqlserver_features.rb index 508009be..fa46de63 100644 --- a/lib/puppet/type/sqlserver_features.rb +++ b/lib/puppet/type/sqlserver_features.rb @@ -4,6 +4,7 @@ Puppet::Type::newtype(:sqlserver_features) do ensurable + autorequire('class') { 'sqlserver' } newparam(:name, :namevar => true) do #Due to our prefetch and unaware of what name the user will provide we munge the value to meet our expecations. diff --git a/lib/puppet/type/sqlserver_instance.rb b/lib/puppet/type/sqlserver_instance.rb index fc5f0be7..616c6964 100644 --- a/lib/puppet/type/sqlserver_instance.rb +++ b/lib/puppet/type/sqlserver_instance.rb @@ -5,6 +5,8 @@ ensurable + autorequire('class') { 'sqlserver' } + newparam(:name, :namevar => true) do munge do |value| value.upcase diff --git a/manifests/config.pp b/manifests/config.pp index 640782fa..4083d5ae 100644 --- a/manifests/config.pp +++ b/manifests/config.pp @@ -26,15 +26,11 @@ #possible future parameter if we do end up supporting different install directories $install_dir ='C:/Program Files/Microsoft SQL Server' $config_dir = "${install_dir}/.puppet" - $config_file = "${config_dir}/.${instance_name}.cfg" - if !defined(File[$config_dir]){ - file{ $config_dir: - ensure => directory - } - } + $_instance = upcase($instance_name) + $config_file = "${config_dir}/.${_instance}.cfg" + file{ $config_file: content => template('sqlserver/instance_config.erb'), - require => File[$config_dir], } $acl_permissions = [{ identity => 'Administrators', rights => ['full'] } ] diff --git a/manifests/init.pp b/manifests/init.pp new file mode 100644 index 00000000..b9352c2d --- /dev/null +++ b/manifests/init.pp @@ -0,0 +1,21 @@ +## +# +## +class sqlserver { + + $config_dir = 'C:\Program Files\Microsoft SQL Server\.puppet' + ensure_resource('file',['C:\Program Files\Microsoft SQL Server',$config_dir],{ 'ensure' => 'directory', 'recurse' => 'true' }) + + file { "${config_dir}\\sqlserver.psm1": + source => 'puppet:///modules/sqlserver/sqlserver.psm1', + source_permissions => ignore, + } + + $acl_permissions = [{ identity => 'Administrators', rights => ['full'] } ] + acl { "${config_dir}\\sqlserver.psm1": + purge => true, + inherit_parent_permissions => false, + permissions => $acl_permissions, + require => File["${config_dir}\\sqlserver.psm1"], + } +}