Skip to content

Commit

Permalink
xSQLServerAlwaysOnAvailabilityGroupReplica: Make Cluster Aware (#892)
Browse files Browse the repository at this point in the history
- Changes to xSQLServerAlwaysOnAvailabilityGroupReplica
  - 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 #870).
  • Loading branch information
randomnote1 authored and johlju committed Oct 25, 2017
1 parent a712236 commit de5c168
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 5 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@
- 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 #868](https://github.com/PowerShell/xSQLServer/issues/868)).
- Changes to xSQLServerAlwaysOnAvailabilityGroupReplica
- 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 #870](https://github.com/PowerShell/xSQLServer/issues/870)).
- 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)).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ function Get-TargetResource
# Connect to the instance
$serverObject = Connect-SQL -SQLServer $SQLServer -SQLInstanceName $SQLInstanceName

# Is this node actively hosting the SQL instance?
$isActiveNode = Test-ActiveNode -ServerObject $serverObject

# Get the endpoint properties
$endpoint = $serverObject.Endpoints | Where-Object { $_.EndpointType -eq 'DatabaseMirroring' }
if ( $endpoint )
Expand All @@ -62,6 +65,7 @@ function Get-TargetResource
ConnectionModeInSecondaryRole = ''
FailoverMode = ''
EndpointUrl = ''
IsActiveNode = $isActiveNode
ReadOnlyRoutingConnectionUrl = ''
ReadOnlyRoutingList = @()
SQLServer = $SQLServer
Expand Down Expand Up @@ -148,6 +152,10 @@ function Get-TargetResource
.PARAMETER ReadOnlyRoutingList
Specifies an ordered list of replica server names that represent the probe sequence for connection director to use when redirecting read-only connections through this availability replica. This parameter applies if the availability replica is the current primary replica of the availability group.
.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
{
Expand Down Expand Up @@ -218,7 +226,11 @@ function Set-TargetResource

[Parameter()]
[String[]]
$ReadOnlyRoutingList
$ReadOnlyRoutingList,

[Parameter()]
[Boolean]
$ProcessOnlyOnActiveNode
)

Import-SQLPSModule
Expand Down Expand Up @@ -496,6 +508,9 @@ function Set-TargetResource
.PARAMETER ReadOnlyRoutingList
Specifies an ordered list of replica server names that represent the probe sequence for connection director to use when redirecting read-only connections through this availability replica. This parameter applies if the availability replica is the current primary replica of the availability group.
.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
{
Expand Down Expand Up @@ -567,7 +582,11 @@ function Test-TargetResource

[Parameter()]
[String[]]
$ReadOnlyRoutingList
$ReadOnlyRoutingList,

[Parameter()]
[Boolean]
$ProcessOnlyOnActiveNode
)

$getTargetResourceParameters = @{
Expand All @@ -582,6 +601,17 @@ function Test-TargetResource

$getTargetResourceResult = Get-TargetResource @getTargetResourceParameters

<#
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 $result
}

switch ($Ensure)
{
'Absent'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ class MSFT_xSQLServerAlwaysOnAvailabilityGroupReplica : OMI_BaseResource
[Write, Description("Specifies the failover mode. Default is 'Manual'."), ValueMap{"Automatic","Manual"}, Values{"Automatic","Manual"}] String FailoverMode;
[Write, Description("Specifies the fully-qualified domain name (FQDN) and port to use when routing to the replica for read only connections.")] String ReadOnlyRoutingConnectionUrl;
[Write, Description("Specifies an ordered list of replica server names that represent the probe sequence for connection director to use when redirecting read-only connections through this availability replica. This parameter applies if the availability replica is the current primary replica of the availability group.")] String ReadOnlyRoutingList[];
[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("Output the network port the endpoint is listening on. Used by Get-TargetResource.")] Uint16 EndpointPort;
[Read, Description("Output the endpoint URL of the Availability Group Replica. Used by Get-TargetResource.")] String EndpointUrl;
[Read, Description("Output the NetName property from the SQL Server object. Used by Get-TargetResource.")] String SqlServerNetName;
[Read, Description("Determines if the current node is actively hosting the SQL Server instance.")] Boolean IsActiveNode;
};
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
<#
.EXAMPLE
This example shows how to ensure that the Availability Group Replica 'SQL2' exists in the Availability Group 'TestAG'.
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.
#>

$ConfigurationData = @{
AllNodes = @(
@{
NodeName = '*'
SQLInstanceName = 'MSSQLSERVER'
AvailabilityGroupName = 'TestAG'
NodeName = '*'
SQLInstanceName = 'MSSQLSERVER'
AvailabilityGroupName = 'TestAG'
ProcessOnlyOnActiveNode = $true

},

@{
Expand Down Expand Up @@ -94,6 +101,7 @@ Configuration Example
SQLInstanceName = $Node.SQLInstanceName
PrimaryReplicaSQLServer = ( $AllNodes | Where-Object { $_.Role -eq 'PrimaryReplica' } ).NodeName
PrimaryReplicaSQLInstanceName = ( $AllNodes | Where-Object { $_.Role -eq 'PrimaryReplica' } ).SQLInstanceName
ProcessOnlyOnActiveNode = $Node.ProcessOnlyOnActiveNode
}
}
}
Expand Down
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,9 @@ Always On Availability Group Replica.
when redirecting read-only connections through this availability replica. This
parameter applies if the availability replica is the current primary replica of
the availability group.
* **`[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

Expand All @@ -373,6 +376,8 @@ Always On Availability Group Replica.
Availability Group Replica. Used by Get-TargetResource.
* **`[String]` SQLServerNetName** _(Read)_: Output the NetName property from the
SQL Server object.
* **`[Boolean]` IsActiveNode** _(Read)_: Determines if the current node is
actively hosting the SQL Server instance.

#### Examples

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ try
$mockFailoverMode = 'Manual'
$mockReadOnlyRoutingConnectionUrl = "TCP://$($mockSqlServer).domain.com:1433"
$mockReadOnlyRoutingList = @($mockSqlServer)
$mockProcessOnlyOnActiveNode = $false

#endregion

Expand Down Expand Up @@ -1288,9 +1289,13 @@ try
FailoverMode = $mockFailoverMode
ReadOnlyRoutingConnectionUrl = $mockReadOnlyRoutingConnectionUrl
ReadOnlyRoutingList = $mockReadOnlyRoutingList
ProcessOnlyOnActiveNode = $mockProcessOnlyOnActiveNode
}

Mock -CommandName Connect-SQL -MockWith $mockConnectSqlServer1 -Verifiable
Mock -CommandName Test-ActiveNode -MockWith {
return -not $mockProcessOnlyOnActiveNode
} -Verifiable
}

Context 'When the desired state is absent' {
Expand Down Expand Up @@ -1338,13 +1343,15 @@ try
Test-TargetResource @testTargetResourceParameters | Should -Be $false

Assert-MockCalled -CommandName Connect-SQL -Scope It -Times 1 -Exactly
Assert-MockCalled -CommandName Test-ActiveNode -Scope It -Times 1 -Exactly
}

It 'Should return $true when the Availability Replica is present' {

Test-TargetResource @testTargetResourceParameters | Should -Be $true

Assert-MockCalled -CommandName Connect-SQL -Scope It -Times 1 -Exactly
Assert-MockCalled -CommandName Test-ActiveNode -Scope It -Times 1 -Exactly
}

foreach ( $propertyToCheck in $propertiesToCheck.GetEnumerator() )
Expand All @@ -1355,6 +1362,7 @@ try
Test-TargetResource @testTargetResourceParameters | Should -Be $false

Assert-MockCalled -CommandName Connect-SQL -Scope It -Times 1 -Exactly
Assert-MockCalled -CommandName Test-ActiveNode -Scope It -Times 1 -Exactly
}
}

Expand All @@ -1365,6 +1373,7 @@ try
Test-TargetResource @testTargetResourceParameters | Should -Be $false

Assert-MockCalled -CommandName Connect-SQL -Scope It -Times 1 -Exactly
Assert-MockCalled -CommandName Test-ActiveNode -Scope It -Times 1 -Exactly
}

It 'Should return $true when the Availability Replica is present and the Endpoint Hostname is not specified' {
Expand All @@ -1374,6 +1383,7 @@ try
Test-TargetResource @testTargetResourceParameters | Should -Be $true

Assert-MockCalled -CommandName Connect-SQL -Scope It -Times 1 -Exactly
Assert-MockCalled -CommandName Test-ActiveNode -Scope It -Times 1 -Exactly
}

It 'Should return $false when the Availability Replica is present and the Endpoint Hostname is not in the desired state' {
Expand All @@ -1383,6 +1393,7 @@ try
Test-TargetResource @testTargetResourceParameters | Should -Be $false

Assert-MockCalled -CommandName Connect-SQL -Scope It -Times 1 -Exactly
Assert-MockCalled -CommandName Test-ActiveNode -Scope It -Times 1 -Exactly
}

It 'Should return $false when the Availability Replica is present and the Endpoint Protocol is not in the desired state' {
Expand All @@ -1392,6 +1403,7 @@ try
Test-TargetResource @testTargetResourceParameters | Should -Be $false

Assert-MockCalled -CommandName Connect-SQL -Scope It -Times 1 -Exactly
Assert-MockCalled -CommandName Test-ActiveNode -Scope It -Times 1 -Exactly
}

It 'Should return $false when the Availability Replica is present and the Endpoint Port is not in the desired state' {
Expand All @@ -1401,6 +1413,20 @@ try
Test-TargetResource @testTargetResourceParameters | Should -Be $false

Assert-MockCalled -CommandName Connect-SQL -Scope It -Times 1 -Exactly
Assert-MockCalled -CommandName Test-ActiveNode -Scope It -Times 1 -Exactly

$mockAlternateEndpointPort = $false
}

It 'Should return $true when ProcessOnlyOnActiveNode is "$true" and the current node is not actively hosting the instance' {
$mockProcessOnlyOnActiveNode = $true

$testTargetResourceParameters.ProcessOnlyOnActiveNode = $mockProcessOnlyOnActiveNode

Test-TargetResource @testTargetResourceParameters | Should -Be $true

Assert-MockCalled -CommandName Connect-SQL -Scope It -Times 1 -Exactly
Assert-MockCalled -CommandName Test-ActiveNode -Scope It -Times 1 -Exactly
}
}
}
Expand Down

0 comments on commit de5c168

Please sign in to comment.