diff --git a/DSCResources/MSFT_xSQLAOGroupEnsure/MSFT_xSQLAOGroupEnsure.psm1 b/DSCResources/MSFT_xSQLAOGroupEnsure/MSFT_xSQLAOGroupEnsure.psm1 index 6a693a4da..6a622e594 100644 --- a/DSCResources/MSFT_xSQLAOGroupEnsure/MSFT_xSQLAOGroupEnsure.psm1 +++ b/DSCResources/MSFT_xSQLAOGroupEnsure/MSFT_xSQLAOGroupEnsure.psm1 @@ -26,17 +26,17 @@ function Get-TargetResource [System.String] $SQLInstanceName= "MSSQLSERVER", - [parameter(Mandatory = $true)] + [parameter(Mandatory = $false)] [System.Management.Automation.PSCredential] $SetupCredential ) if(!$SQL) { - $SQL = Connect-SQL -SQLServer $SQLServer -SQLInstanceName $SQLInstanceName + $SQL = Connect-SQL -SQLServer $SQLServer -SQLInstanceName $SQLInstanceName -SetupCredential $SetupCredential } - $vConfigured = Test-TargetResource -Ensure $Ensure -AvailabilityGroupName $AvailabilityGroupName -SQLServer $SQLServer -SQLInstanceName $SQLInstanceName + $vConfigured = Test-TargetResource -Ensure $Ensure -AvailabilityGroupName $AvailabilityGroupName -SQLServer $SQLServer -SQLInstanceName $SQLInstanceName -SetupCredential $SetupCredential $returnValue = @{ Ensure = $vConfigured @@ -95,7 +95,7 @@ function Set-TargetResource [System.String] $SQLInstanceName= "MSSQLSERVER", - [parameter(Mandatory = $true)] + [parameter(Mandatory = $false)] [System.Management.Automation.PSCredential] $SetupCredential ) @@ -136,7 +136,7 @@ function Set-TargetResource #First two nodes will account for Syncronous Automatic Failover, Any additional will be Asyncronous try { - $nodes= Get-ClusterNode -cluster $sql.ClusterName -Verbose:$false | select -ExpandProperty name + $nodes = Get-ClusterNode -cluster $sql.ClusterName -Verbose:$false | select -ExpandProperty name $syncNodes = $nodes | Select-Object -First 2 $asyncNodes = $nodes | Select-Object -Skip 2 $availabilityGroup = New-Object -typename Microsoft.SqlServer.Management.Smo.AvailabilityGroup -ArgumentList $SQL, $AvailabilityGroupName @@ -146,7 +146,7 @@ function Set-TargetResource } Catch { - Throw "Failed to connect to Cluster Nodes from $sql.ClusterName" + Throw "Failed to connect to Cluster Nodes from $($sql.ClusterName)" Exit } @@ -260,7 +260,7 @@ function Set-TargetResource Try { $sql.AvailabilityGroups[$AvailabilityGroupName].Drop() - NNew-VerboseMessage -Message "Dropped $AvailabilityGroupName" + New-VerboseMessage -Message "Dropped $AvailabilityGroupName" } Catch{ Throw "Unable to Drop $AvailabilityGroup on $SQLServer\$SQLInstanceName" @@ -314,14 +314,14 @@ function Test-TargetResource [System.String] $SQLInstanceName= "MSSQLSERVER", - [parameter(Mandatory = $true)] + [parameter(Mandatory = $false)] [System.Management.Automation.PSCredential] $SetupCredential ) if(!$SQL) { - $SQL = Connect-SQL -SQLServer $SQLServer -SQLInstanceName $SQLInstanceName + $SQL = Connect-SQL -SQLServer $SQLServer -SQLInstanceName $SQLInstanceName -SetupCredential $SetupCredential } Switch ($Ensure) diff --git a/Tests/MSFT_xSQLAOGroupEnsure.Tests.ps1 b/Tests/MSFT_xSQLAOGroupEnsure.Tests.ps1 index 5b45b4b19..7d45d9881 100644 --- a/Tests/MSFT_xSQLAOGroupEnsure.Tests.ps1 +++ b/Tests/MSFT_xSQLAOGroupEnsure.Tests.ps1 @@ -1,12 +1,14 @@ -Import-Module "$PSScriptRoot\..\DSCResources\MSFT_xSQLAOGroupEnsure\MSFT_xSQLAOGroupEnsure.psm1" -Force +Import-Module "$PSScriptRoot\..\DSCResources\MSFT_xSQLAOGroupEnsure\MSFT_xSQLAOGroupEnsure.psm1" -Prefix Pester -Force Describe 'Get-TargetResource'{ - Mock -ModuleName xSQLServerHelper -CommandName Connect-SQL -MockWith { - $sql = [PSCustomObject]@{ + Mock -ModuleName MSFT_xSQLAOGroupEnsure -CommandName Connect-SQL -MockWith { + # build a custom object to return which is close to the real SMO object + $smoObj = [PSCustomObject]@{ SQLServer = 'Node01'; SQLInstanceName = 'Prd01'; + ClusterName = 'Clust01'; } - $sql | Add-Member -MemberType NoteProperty -Name AvailabilityGroups -Value @{ + $smoObj | Add-Member -MemberType NoteProperty -Name AvailabilityGroups -Value @{ 'AG01' = @{ AvailabilityGroupListeners = @{ name = 'AgList01'; @@ -15,87 +17,172 @@ Describe 'Get-TargetResource'{ AvailabilityDatabases = @(@{name='AdventureWorks'}); }; }; - $sql.AvailabilityGroups['AG01'] | Add-Member -MemberType NoteProperty -Name Name -Value 'AG01' -Force - $sql.AvailabilityGroups['AG01'] | Add-Member -MemberType ScriptMethod -Name ToString -Value {return 'AG01'} -Force - return $sql + $smoObj.AvailabilityGroups['AG01'] | Add-Member -MemberType NoteProperty -Name Name -Value 'AG01' -Force + $smoObj.AvailabilityGroups['AG01'] | Add-Member -MemberType ScriptMethod -Name ToString -Value {return 'AG01'} -Force + return $smoObj } - Mock -ModuleName xSQLServerHelper -CommandName Grant-ServerPerms -MockWith { - New-VerboseMessage -Message "Granted Permissions to $AuthorizedUser" - } + Context "When the configuration is already set" { + + $password = "dummyPassw0rd" | ConvertTo-SecureString -asPlainText -Force + $username = "dba" + $credential = New-Object System.Management.Automation.PSCredential($username,$password) - Mock -ModuleName MSFT_xSqlAlias -CommandName Get-ItemProperty -MockWith { - Write-Output 'DBMSSOCN,localhost,1433' - } - - $SqlAlias = Get-xSqlAliasTargetResource -Name 'localhost' + $SqlAOGroup = Get-PesterTargetResource -Ensure 'Present' -AvailabilityGroupName 'AG01' -SQLServer 'localhost' -SQLInstanceName 'MSSQLSERVER' -SetupCredential $credential; - It 'Should return hashtable with Key Protocol'{ - $SqlAlias.ContainsKey('Protocol') | Should Be $true - } - - It 'Should return hashtable with Value that matches "TCP"'{ - $SqlAlias.Protocol = 'TCP' - } -} + It 'Should return hashtable with Ensure = $true'{ + $SqlAOGroup.Ensure | Should Be $true + } + } -Describe 'Set-TargetResource'{ + Context "When the configuration is not yet set or has drift" { + + $password = "dummyPassw0rd" | ConvertTo-SecureString -asPlainText -Force + $username = "dba" + $credential = New-Object System.Management.Automation.PSCredential($username,$password) - Mock -ModuleName MSFT_xSqlAlias -CommandName Test-Path -MockWith { - Write-Output $true - } + $SqlAOGroup = Get-PesterTargetResource -Ensure 'Absent' -AvailabilityGroupName 'AG01' -SQLServer 'localhost' -SQLInstanceName 'MSSQLSERVER' -SetupCredential $credential; - Mock -ModuleName MSFT_xSqlAlias -CommandName Get-ItemProperty -MockWith { - Write-Output 'DBMSSOCN,localhost,52002' - } - - Mock -ModuleName MSFT_xSqlAlias -CommandName Set-ItemProperty -MockWith { - Write-Output $true - } - - Mock -ModuleName MSFT_xSqlAlias -CommandName Get-Wmiobject -MockWith { - Write-Output @{ - Class = 'win32_OperatingSystem' - OSArchitecture = '64-bit' + It 'Should return hashtable with Ensure = $false'{ + $SqlAOGroup.Ensure | Should Be $false } - } + } +} - It 'Should not call Set-ItemProperty with value already set' { - Set-xSqlAliasTargetResource -Name 'myServerAlias' -Protocol 'TCP' -ServerName 'localhost' -TCPPort 52002 -Ensure 'Present' - Assert-MockCalled -ModuleName MSFT_xSqlAlias -CommandName Set-ItemProperty -Exactly 0 - } - It 'Call Set-ItemProperty exactly 2 times (1 for 32bit and 1 for 64 bit reg keys)' { - Set-xSqlAliasTargetResource -Name 'myServerAlias' -Protocol 'TCP' -ServerName 'localhost' -TCPPort 1433 -Ensure 'Present' - Assert-MockCalled -ModuleName MSFT_xSqlAlias -CommandName Set-ItemProperty -Exactly 2 - } - -} Describe 'Test-TargetResource'{ - Mock -ModuleName MSFT_xSqlAlias -CommandName Test-Path -MockWith { - Write-Output $true + Mock -ModuleName MSFT_xSQLAOGroupEnsure -CommandName Connect-SQL -MockWith { + # build a custom object to return which is close to the real SMO object + $smoObj = [PSCustomObject]@{ + SQLServer = 'Node01'; + SQLInstanceName = 'Prd01'; + ClusterName = 'Clust01'; + } + $smoObj | Add-Member -MemberType NoteProperty -Name AvailabilityGroups -Value @{ + 'AG01' = @{ + AvailabilityGroupListeners = @{ + name = 'AgList01'; + availabilitygrouplisteneripaddresses = @{IpAddress = '192.168.0.1'; SubnetMask = '255.255.255.0'}; + portnumber = 5022;}; + AvailabilityDatabases = @(@{name='AdventureWorks'}); + }; + }; + $smoObj.AvailabilityGroups['AG01'] | Add-Member -MemberType NoteProperty -Name Name -Value 'AG01' -Force + $smoObj.AvailabilityGroups['AG01'] | Add-Member -MemberType ScriptMethod -Name ToString -Value {return 'AG01'} -Force + return $smoObj } - Mock -ModuleName MSFT_xSqlAlias -CommandName Get-ItemProperty -MockWith { - Write-Output @{ - myServerAlias = 'DBMSSOCN,localhost,1433' + Context "When the configuration is valid" { + + $password = "dummyPassw0rd" | ConvertTo-SecureString -asPlainText -Force + $username = "dba" + $credential = New-Object System.Management.Automation.PSCredential($username,$password) + + $SqlAOGroupTest = Test-PesterTargetResource -Ensure 'Present' -AvailabilityGroupName 'AG01' -SQLServer 'localhost' -SQLInstanceName 'MSSQLSERVER' -SetupCredential $credential; + + It 'Should return $true'{ + $SqlAOGroupTest | Should Be $true } - } + } + + Context "When the configuration has drifted" { + + $password = "dummyPassw0rd" | ConvertTo-SecureString -asPlainText -Force + $username = "dba" + $credential = New-Object System.Management.Automation.PSCredential($username,$password) - Mock -ModuleName MSFT_xSqlAlias -CommandName Get-Wmiobject -MockWith { - Write-Output @{ - Class = 'win32_OperatingSystem' - OSArchitecture = '64-bit' + $SqlAOGroupTest = Test-PesterTargetResource -Ensure 'Absent' -AvailabilityGroupName 'AG01' -SQLServer 'localhost' -SQLInstanceName 'MSSQLSERVER' -SetupCredential $credential; + + It 'Should return $false'{ + $SqlAOGroupTest | Should Be $false } - } + } +} - It 'Should return true when Test is passed as Alias thats already set'{ - Test-xSqlAliasTargetResource -Name 'myServerAlias' -Protocol 'TCP' -ServerName localhost -TCPPort 1433 -Ensure 'Present' | Should Be $true - } - It 'Should return false when Test is passed as Alias that is not set'{ - Test-xSqlAliasTargetResource -Name 'myServerAlias' -Protocol 'TCP' -ServerName localhost -TCPPort 52002 -Ensure 'Present' | Should Be $false + +Describe 'Set-TargetResource'{ + + # create this first as we need to override the new-object cmdlet later + $password = "dummyPassw0rd" | ConvertTo-SecureString -asPlainText -Force + $username = "dba"; + $credential = New-Object System.Management.Automation.PSCredential($username, $password) + + Mock -ModuleName MSFT_xSQLAOGroupEnsure -CommandName Connect-SQL -MockWith { + # build a custom object to return which is close to the real SMO object + $smoObj = [PSCustomObject]@{ + SQLServer = 'Node01'; + SQLInstanceName = 'Prd01'; + ClusterName = 'Clust01'; + } + $smoObj | Add-Member -MemberType NoteProperty -Name AvailabilityGroups -Value @{ + 'AG01' = @{ + AvailabilityGroupListeners = @{ + name = 'AgList01'; + availabilitygrouplisteneripaddresses = @{IpAddress = '192.168.0.1'; SubnetMask = '255.255.255.0'}; + portnumber = 5022;}; + AvailabilityDatabases = @(@{name='AdventureWorks'}); + }; + }; + $smoObj.AvailabilityGroups['AG01'] | Add-Member -MemberType NoteProperty -Name Name -Value 'AG01' -Force + $smoObj.AvailabilityGroups['AG01'] | Add-Member -MemberType ScriptMethod -Name ToString -Value {return 'AG01'} -Force + return $smoObj + } + Mock -ModuleName MSFT_xSQLAOGroupEnsure -CommandName Grant-ServerPerms -MockWith { + New-VerboseMessage -Message "Granted Permissions to $AuthorizedUser" + } + Mock -ModuleName MSFT_xSQLAOGroupEnsure -CommandName New-ListenerADObject -MockWith { + New-VerboseMessage -Message "Created new Listener Object" + } + Mock -ModuleName MSFT_xSQLAOGroupEnsure -CommandName Get-ClusterNode -MockWith { + $clusterNode = @([PSCustomObject]@{ + Name = 'Node01'; + }; + , [PSCustomObject]@{ + Name = 'Node02'; + }; + , [PSCustomObject]@{ + Name = 'Node03'; + }; + , [PSCustomObject]@{ + Name = 'Node04'; + }; + ) + return $clusterNode; + } + Mock -ModuleName MSFT_xSQLAOGroupEnsure -CommandName New-Object -MockWith { + $object = [PSCustomObject]@{ + Name = $args[0]; + } + return $object; + } + Mock Get-Module -MockWith { + return 'Module Name'; } + + + Context "Set the configuration" { + + # setup the params for the function using splatting method + $Params = @{ + Ensure = 'Present'; + AvailabilityGroupName = 'AG01'; + AvailabilityGroupNameListener = 'AgList01'; + AvailabilityGroupNameIP = '192.168.0.1'; + AvailabilityGroupSubMask = '255.255.255.0'; + AvailabilityGroupPort = 1433; + ReadableSecondary = 'ReadOnly'; + AutoBackupPrefernce = 'Primary'; + SQLServer = 'localhost'; + SQLInstanceName = 'MSSQLSERVER'; + SetupCredential = $credential; + } + + $SqlAOGroup = Set-PesterTargetResource @Params; + + #this shouldn't have generated any errors which they are caught by pester without further checks + } + } diff --git a/Tests/MSFT_xSQLAOGroupEnsure.Tests_buildingblock.ps1 b/Tests/MSFT_xSQLAOGroupEnsure.Tests_buildingblock.ps1 deleted file mode 100644 index 8400701ab..000000000 --- a/Tests/MSFT_xSQLAOGroupEnsure.Tests_buildingblock.ps1 +++ /dev/null @@ -1,24 +0,0 @@ -$sql = [PSCustomObject]@{ - SQLServer = 'Node01'; - SQLInstanceName = 'Prd01'; - } -$sql | Add-Member -MemberType NoteProperty -Name AvailabilityGroups -Value @{ - 'AG01' = @{ - AvailabilityGroupListeners = @{ - name = 'AgList01'; - availabilitygrouplisteneripaddresses = @{IpAddress = '192.168.0.1'; SubnetMask = '255.255.255.0'}; - portnumber = 5022;}; - AvailabilityDatabases = @(@{name='AdventureWorks'}); - }; - }; -$sql.AvailabilityGroups['AG01'] | Add-Member -MemberType NoteProperty -Name Name -Value 'AG01' -Force -$sql.AvailabilityGroups['AG01'] | Add-Member -MemberType ScriptMethod -Name ToString -Value {return 'AG01'} -Force - - - $AvailabilityGroupName = 'AG01' - AvailabilityGroupName = $sql.AvailabilityGroups[$AvailabilityGroupName] - AvailabilityGroupNameListener = $sql.AvailabilityGroups[$AvailabilityGroupName].AvailabilityGroupListeners.name - AvailabilityGroupNameIP = $sql.AvailabilityGroups[$AvailabilityGroupName].AvailabilityGroupListeners.availabilitygrouplisteneripaddresses.IPAddress - AvailabilityGroupSubMask = $sql.AvailabilityGroups[$AvailabilityGroupName].AvailabilityGroupListeners.availabilitygrouplisteneripaddresses.SubnetMask - AvailabilityGroupPort = $sql.AvailabilityGroups[$AvailabilityGroupName].AvailabilityGroupListeners.portnumber - AvailabilityGroupNameDatabase = $sql.AvailabilityGroups[$AvailabilityGroupName].AvailabilityDatabases.name \ No newline at end of file