diff --git a/CHANGELOG.md b/CHANGELOG.md index ff81c2f8f..d1920ad14 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,10 @@ - Added the CommonTestHelper.psm1 to store common testing functions. - Added the Import-SQLModuleStub function to ensure the correct version of the module stubs are loaded ([issue #784](https://github.com/PowerShell/xSQLServer/issues/784)). +- Changes to xSQLServerMemory + - Made the resource cluster aware. When ProcessOnlyOnActiveNode is specified, + the resource will only determine if a change is needed if the target node + is the active host of the SQL Server instance ([issue #867](https://github.com/PowerShell/xSQLServer/issues/867)). - Changes to xSQLServerNetwork - BREAKING CHANGE: Renamed parameter TcpDynamicPorts to TcpDynamicPort and changed type to Boolean ([issue #534](https://github.com/PowerShell/xSQLServer/issues/534)). diff --git a/DSCResources/MSFT_xSQLServerMemory/MSFT_xSQLServerMemory.psm1 b/DSCResources/MSFT_xSQLServerMemory/MSFT_xSQLServerMemory.psm1 index 615447175..db6ac74b7 100644 --- a/DSCResources/MSFT_xSQLServerMemory/MSFT_xSQLServerMemory.psm1 +++ b/DSCResources/MSFT_xSQLServerMemory/MSFT_xSQLServerMemory.psm1 @@ -2,13 +2,13 @@ Import-Module -Name (Join-Path -Path (Split-Path (Split-Path $PSScriptRoot -Pare <# .SYNOPSIS - This function gets the value of the min and max memory server configuration option. + This function gets the value of the min and max memory server configuration option. .PARAMETER SQLServer - The host name of the SQL Server to be configured. + The host name of the SQL Server to be configured. .PARAMETER SQLInstanceName - The name of the SQL instance to be configured. + The name of the SQL instance to be configured. #> function Get-TargetResource @@ -35,6 +35,9 @@ function Get-TargetResource Write-Verbose -Message 'Getting the value for minimum and maximum SQL server memory.' $minMemory = $sqlServerObject.Configuration.MinServerMemory.ConfigValue $maxMemory = $sqlServerObject.Configuration.MaxServerMemory.ConfigValue + + # Is this node actively hosting the SQL instance? + $isActiveNode = Test-ActiveNode -ServerObject $sqlServerObject } $returnValue = @{ @@ -42,6 +45,7 @@ function Get-TargetResource SQLServer = $SQLServer MinMemory = $minMemory MaxMemory = $maxMemory + IsActiveNode = $isActiveNode } $returnValue @@ -49,27 +53,31 @@ function Get-TargetResource <# .SYNOPSIS - This function sets the value for the min and max memory server configuration option. + This function sets the value for the min and max memory server configuration option. .PARAMETER SQLServer - The host name of the SQL Server to be configured. + The host name of the SQL Server to be configured. .PARAMETER SQLInstanceName - The name of the SQL instance to be configured. + The name of the SQL instance to be configured. .PARAMETER Ensure - When set to 'Present' then min and max memory will be set to either the value in parameter MinMemory and MaxMemory or dynamically configured when parameter DynamicAlloc is set to $true. - When set to 'Absent' min and max memory will be set to default values. + When set to 'Present' then min and max memory will be set to either the value in parameter MinMemory and MaxMemory or dynamically configured when parameter DynamicAlloc is set to $true. + When set to 'Absent' min and max memory will be set to default values. .PARAMETER DynamicAlloc - If set to $true then max memory will be dynamically configured. - When this is set parameter is set to $true, the parameter MaxMemory must be set to $null or not be configured. + If set to $true then max memory will be dynamically configured. + When this is set parameter is set to $true, the parameter MaxMemory must be set to $null or not be configured. .PARAMETER MinMemory - This is the minimum amount of memory, in MB, in the buffer pool used by the instance of SQL Server. + This is the minimum amount of memory, in MB, in the buffer pool used by the instance of SQL Server. .PARAMETER MaxMemory - This is the maximum amount of memory, in MB, in the buffer pool used by the instance of SQL Server. + This is the maximum amount of memory, in MB, in the buffer pool used by the instance of SQL Server. + + .PARAMETER ProcessOnlyOnActiveNode + Specifies that the resource will only determine if a change is needed if the target node is the active host of the SQL Server instance. + Not used in Set-TargetResource. #> function Set-TargetResource { @@ -101,7 +109,11 @@ function Set-TargetResource [Parameter()] [System.Int32] - $MaxMemory + $MaxMemory, + + [Parameter()] + [Boolean] + $ProcessOnlyOnActiveNode ) $sqlServerObject = Connect-SQL -SQLServer $SQLServer -SQLInstanceName $SQLInstanceName @@ -170,27 +182,30 @@ function Set-TargetResource <# .SYNOPSIS - This function tests the value of the min and max memory server configuration option. + This function tests the value of the min and max memory server configuration option. .PARAMETER SQLServer - The host name of the SQL Server to be configured. + The host name of the SQL Server to be configured. .PARAMETER SQLInstanceName - The name of the SQL instance to be configured. + The name of the SQL instance to be configured. .PARAMETER Ensure - When set to 'Present' then min and max memory will be set to either the value in parameter MinMemory and MaxMemory or dynamically configured when parameter DynamicAlloc is set to $true. - When set to 'Absent' min and max memory will be set to default values. + When set to 'Present' then min and max memory will be set to either the value in parameter MinMemory and MaxMemory or dynamically configured when parameter DynamicAlloc is set to $true. + When set to 'Absent' min and max memory will be set to default values. .PARAMETER DynamicAlloc - If set to $true then max memory will be dynamically configured. - When this is set parameter is set to $true, the parameter MaxMemory must be set to $null or not be configured. + If set to $true then max memory will be dynamically configured. + When this is set parameter is set to $true, the parameter MaxMemory must be set to $null or not be configured. .PARAMETER MinMemory - This is the minimum amount of memory, in MB, in the buffer pool used by the instance of SQL Server. + This is the minimum amount of memory, in MB, in the buffer pool used by the instance of SQL Server. .PARAMETER MaxMemory - This is the maximum amount of memory, in MB, in the buffer pool used by the instance of SQL Server. + This is the maximum amount of memory, in MB, in the buffer pool used by the instance of SQL Server. + + .PARAMETER ProcessOnlyOnActiveNode + Specifies that the resource will only determine if a change is needed if the target node is the active host of the SQL Server instance. #> function Test-TargetResource { @@ -223,7 +238,11 @@ function Test-TargetResource [Parameter()] [System.Int32] - $MaxMemory + $MaxMemory, + + [Parameter()] + [Boolean] + $ProcessOnlyOnActiveNode ) Write-Verbose -Message 'Testing the values of the minimum and maximum memory server configuration option set to be used by the instance.' @@ -239,6 +258,17 @@ function Test-TargetResource $currentMaxMemory = $getTargetResourceResult.MaxMemory $isServerMemoryInDesiredState = $true + <# + If this is supposed to process only the active node, and this is not the + active node, don't bother evaluating the test. + #> + if ( $ProcessOnlyOnActiveNode -and -not $getTargetResourceResult.IsActiveNode ) + { + # Use localization if the resource has been converted + New-VerboseMessage -Message ( 'The node "{0}" is not actively hosting the instance "{1}". Exiting the test.' -f $env:COMPUTERNAME,$SQLInstanceName ) + return $isServerMemoryInDesiredState + } + switch ($Ensure) { 'Absent' diff --git a/DSCResources/MSFT_xSQLServerMemory/MSFT_xSQLServerMemory.schema.mof b/DSCResources/MSFT_xSQLServerMemory/MSFT_xSQLServerMemory.schema.mof index ef3ca5c82..4f6bbb202 100644 --- a/DSCResources/MSFT_xSQLServerMemory/MSFT_xSQLServerMemory.schema.mof +++ b/DSCResources/MSFT_xSQLServerMemory/MSFT_xSQLServerMemory.schema.mof @@ -7,4 +7,6 @@ class MSFT_xSQLServerMemory : OMI_BaseResource [Write, Description("If set to $true then max memory will be dynamically configured. When this is set parameter is set to $true, the parameter MaxMemory must be set to $null or not be configured. Default value is $false.")] Boolean DynamicAlloc; [Write, Description("Minimum amount of memory, in MB, in the buffer pool used by the instance of SQL Server.")] Sint32 MinMemory; [Write, Description("Maximum amount of memory, in MB, in the buffer pool used by the instance of SQL Server.")] Sint32 MaxMemory; + [Write, Description("Specifies that the resource will only determine if a change is needed if the target node is the active host of the SQL Server instance.")] Boolean ProcessOnlyOnActiveNode; + [Read, Description("Determines if the current node is actively hosting the SQL Server instance.")] Boolean IsActiveNode; }; diff --git a/Examples/Resources/xSQLServerMemory/2-SetMaxMemoryToAuto.ps1 b/Examples/Resources/xSQLServerMemory/2-SetMaxMemoryToAuto.ps1 index 3590c382a..a13999410 100644 --- a/Examples/Resources/xSQLServerMemory/2-SetMaxMemoryToAuto.ps1 +++ b/Examples/Resources/xSQLServerMemory/2-SetMaxMemoryToAuto.ps1 @@ -2,6 +2,11 @@ .EXAMPLE This example shows how to set the maximum memory configuration option with the automatic configuration. + + In the event this is applied to a Failover Cluster Instance (FCI), the + ProcessOnlyOnActiveNode property will tell the Test-TargetResource function + to evaluate if any changes are needed if the node is actively hosting the + SQL Server instance. #> Configuration Example { @@ -19,11 +24,12 @@ Configuration Example { xSQLServerMemory Set_SQLServerMaxMemory_ToAuto { - Ensure = 'Present' - DynamicAlloc = $true - SQLServer = 'SQLServer' - SQLInstanceName = 'DSC' - PsDscRunAsCredential = $SysAdminAccount + Ensure = 'Present' + DynamicAlloc = $true + SQLServer = 'SQLServer' + SQLInstanceName = 'DSC' + PsDscRunAsCredential = $SysAdminAccount + ProcessOnlyOnActiveNode = $true } } } diff --git a/README.md b/README.md index 6a90acb6c..c8010639d 100644 --- a/README.md +++ b/README.md @@ -1002,6 +1002,14 @@ SQL Max Memory = TotalPhysicalMemory - (NumOfSQLThreads\*ThreadStackSize) - pool used by the instance of SQL Server. * **`[Sint32]` MaxMemory** _(Write)_: Maximum amount of memory, in MB, in the buffer pool used by the instance of SQL Server. +* **`[Boolean]` ProcessOnlyOnActiveNode** _(Write)_: Specifies that the resource + will only determine if a change is needed if the target node is the active + host of the SQL Server instance. + +#### Read-Only Properties from Get-TargetResource + +* **`[Boolean]` IsActiveNode** _(Read)_: Determines if the current node is + actively hosting the SQL Server instance. #### Examples diff --git a/Tests/Unit/MSFT_xSQLServerMemory.Tests.ps1 b/Tests/Unit/MSFT_xSQLServerMemory.Tests.ps1 index 850a77e7b..e54c72156 100644 --- a/Tests/Unit/MSFT_xSQLServerMemory.Tests.ps1 +++ b/Tests/Unit/MSFT_xSQLServerMemory.Tests.ps1 @@ -13,6 +13,9 @@ if ( (-not (Test-Path -Path (Join-Path -Path $script:moduleRoot -ChildPath 'DSCR Import-Module (Join-Path -Path $script:moduleRoot -ChildPath 'DSCResource.Tests\TestHelper.psm1') -Force +# Loading mocked classes +Add-Type -Path ( Join-Path -Path ( Join-Path -Path $PSScriptRoot -ChildPath Stubs ) -ChildPath SMO.cs ) + $TestEnvironment = Initialize-TestEnvironment ` -DSCModuleName $script:DSCModuleName ` -DSCResourceName $script:DSCResourceName ` @@ -40,6 +43,7 @@ try $mockPhysicalMemoryCapacity = 8589934592 $mockExpectedMinMemoryForAlterMethod = 0 $mockExpectedMaxMemoryForAlterMethod = 2147483647 + $mockTestActiveNode = $true # Default parameters that are used for the It-blocks $mockDefaultParameters = @{ @@ -52,9 +56,10 @@ try $mockConnectSQL = { return @( ( - New-Object Object | - Add-Member -MemberType NoteProperty -Name InstanceName -Value $mockSQLServerInstanceName -PassThru | - Add-Member -MemberType NoteProperty -Name ComputerNamePhysicalNetBIOS -Value $mockSQLServerName -PassThru | + # New-Object Object | + New-Object -TypeName Microsoft.SqlServer.Management.Smo.Server | + Add-Member -MemberType NoteProperty -Name InstanceName -Value $mockSQLServerInstanceName -PassThru -Force | + Add-Member -MemberType NoteProperty -Name ComputerNamePhysicalNetBIOS -Value $mockSQLServerName -PassThru -Force | Add-Member -MemberType ScriptProperty -Name Configuration -Value { return @( ( New-Object Object | Add-Member -MemberType ScriptProperty -Name MinServerMemory -Value { @@ -74,7 +79,7 @@ try ) ) } -PassThru -Force ) ) - } -PassThru | + } -PassThru -Force | Add-Member -MemberType ScriptMethod -Name Alter -Value { if ( $this.Configuration.MinServerMemory.ConfigValue -ne $mockExpectedMinMemoryForAlterMethod ) { @@ -93,6 +98,7 @@ try Describe "MSFT_xSQLServerMemory\Get-TargetResource" -Tag 'Get'{ Mock -CommandName Connect-SQL -MockWith $mockConnectSQL -Verifiable + Mock -CommandName Test-ActiveNode -MockWith { return $mockTestActiveNode } -Verifiable Context 'When the system is either in the desired state or not in the desired state' { $testParameters = $mockDefaultParameters @@ -115,6 +121,10 @@ try It 'Should call the mock function Connect-SQL' { Assert-MockCalled Connect-SQL -Exactly -Times 1 -Scope Context } + + It 'Should call the mock function Test-ActiveNode' { + Assert-MockCalled Test-ActiveNode -Exactly -Times 1 -Scope Context + } } Assert-VerifiableMock @@ -161,6 +171,8 @@ try $mockGetCimInstanceOS } -ParameterFilter { $ClassName -eq 'Win32_operatingsystem' } -Verifiable + Mock -CommandName Test-ActiveNode -MockWith { return $mockTestActiveNode } -Verifiable + Context 'When the system is not in the desired state and DynamicAlloc is set to false' { $testParameters = $mockDefaultParameters $testParameters += @{ @@ -305,6 +317,50 @@ try } } + Context 'When the system is not in the desired state, DynamicAlloc is set to true and ProcessOnlyOnActiveNode is set to true' { + AfterAll { + $mockTestActiveNode = $true + } + + BeforeAll { + $testParameters = $mockDefaultParameters + $testParameters += @{ + Ensure = 'Present' + DynamicAlloc = $true + ProcessOnlyOnActiveNode = $true + } + + $mockTestActiveNode = $false + } + + It 'Should return the state as true' { + $result = Test-TargetResource @testParameters + $result | Should -Be $true + } + + It 'Should call the mock function Connect-SQL' { + Assert-MockCalled Connect-SQL -Exactly -Times 1 -Scope Context + } + + It 'Should not call the mock function Get-CimInstance with ClassName equal to Win32_PhysicalMemory' { + Assert-MockCalled Get-CimInstance -Exactly -Times 0 -ParameterFilter { + $ClassName -eq 'Win32_PhysicalMemory' + } -Scope Context + } + + It 'Should not call the mock function Get-CimInstance with ClassName equal to Win32_Processor' { + Assert-MockCalled Get-CimInstance -Exactly -Times 0 -ParameterFilter { + $ClassName -eq 'Win32_Processor' + } -Scope Context + } + + It 'Should not call the mock function Get-CimInstance with ClassName equal to Win32_operatingsystem' { + Assert-MockCalled Get-CimInstance -Exactly -Times 0 -ParameterFilter { + $ClassName -eq 'Win32_operatingsystem' + } -Scope Context + } + } + $mockMinServerMemory = 0 $mockMaxServerMemory = 12083