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"], + } +}