From 4c0dcc6428cf5f4bb2ed4d649013cde949e6d885 Mon Sep 17 00:00:00 2001 From: Johan Ljunggren Date: Wed, 13 May 2020 20:03:35 +0200 Subject: [PATCH] BREAKING CHANGE: SqlServerEndpoint: Added the property State (#1535) - SqlServerEndpointState - This resource is now deprecated. The functionality is covered by a property in the resource _SqlServerEndpoint_ (issue #968). - SqlServerEndpoint - BREAKING CHANGE: A new required property `EndpointType` was added to support different types of endpoints in the future. For now the only endpoint type that is supported is the database mirror endpoint type (`DatabaseMirroring`). - Added the property `State` to be able to specify if the endpoint should be running, stopped, or disabled. _This property was moved from the now_ _deprecated DSC resource `SqlServerEndpointState`_. - BREAKING CHANGE: Now the properties are only enforced if they are specified in the configuration. - CommonTestHelper - The test helper function `New-SQLSelfSignedCertificate` was changed to install the dependent module `PSPKI` through `RequiredModules.psd1`. --- CHANGELOG.md | 22 +- README.md | 59 +-- RequiredModules.psd1 | 1 + azure-pipelines.yml | 4 +- build.yaml | 3 + codecov.yml | 1 + .../DSC_SqlServerEndpoint.psm1 | 305 +++++++++++---- .../DSC_SqlServerEndpoint.schema.mof | 8 +- .../en-US/DSC_SqlServerEndpoint.strings.psd1 | 3 +- .../MSFT_SqlServerEndpointState.psm1} | 8 + .../MSFT_SqlServerEndpointState.schema.mof} | 2 +- .../MSFT_SqlServerEndpointState.strings.psd1} | 2 +- source/Examples/README.md | 1 - .../SqlAG/1-CreateAvailabilityGroup.ps1 | 1 + .../3-CreateAvailabilityGroupDetailed.ps1 | 1 + .../1-CreateAvailabilityGroupReplica.ps1 | 1 + .../1-CreateEndpointWithDefaultValues.ps1 | 2 + ...EndpointWithSpecificPortIPAddressOwner.ps1 | 2 + .../SqlServerEndpoint/3-RemoveEndpoint.ps1 | 2 + .../1-MakeSureEndpointIsStarted.ps1 | 61 --- .../2-MakeSureEndpointIsStopped.ps1 | 30 -- ...C_SqlServerEndpoint.Integration.Tests.ps1} | 3 + ...g.ps1 => DSC_SqlServerEndpoint.config.ps1} | 3 + tests/TestHelpers/CommonTestHelper.psm1 | 1 - tests/Unit/DSC_SqlServerEndpoint.Tests.ps1 | 129 ++++++- .../Unit/DSC_SqlServerEndpointState.Tests.ps1 | 354 ------------------ 26 files changed, 432 insertions(+), 577 deletions(-) rename source/DSCResources/{DSC_SqlServerEndpointState/DSC_SqlServerEndpointState.psm1 => MSFT_SqlServerEndpointState/MSFT_SqlServerEndpointState.psm1} (97%) rename source/DSCResources/{DSC_SqlServerEndpointState/DSC_SqlServerEndpointState.schema.mof => MSFT_SqlServerEndpointState/MSFT_SqlServerEndpointState.schema.mof} (91%) rename source/DSCResources/{DSC_SqlServerEndpointState/en-US/DSC_SqlServerEndpointState.strings.psd1 => MSFT_SqlServerEndpointState/en-US/MSFT_SqlServerEndpointState.strings.psd1} (86%) delete mode 100644 source/Examples/Resources/SqlServerEndpointState/1-MakeSureEndpointIsStarted.ps1 delete mode 100644 source/Examples/Resources/SqlServerEndpointState/2-MakeSureEndpointIsStopped.ps1 rename tests/Integration/{DSC_SqlServerEndPoint.Integration.Tests.ps1 => DSC_SqlServerEndpoint.Integration.Tests.ps1} (95%) rename tests/Integration/{DSC_SqlServerEndPoint.config.ps1 => DSC_SqlServerEndpoint.config.ps1} (93%) delete mode 100644 tests/Unit/DSC_SqlServerEndpointState.Tests.ps1 diff --git a/CHANGELOG.md b/CHANGELOG.md index e36904d76..14572c02b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,15 +21,18 @@ The documentation, examples, unit test, and integration tests have been removed for these deprecated resources. These resources will be removed in a future release. -- SqlServerNetwork - - This resource is now deprecated. The functionality is now covered by - the resources _SqlServerProtocol_ and _SqlServerProtocolTcpIp_. - SqlDatabaseOwner - This resource is now deprecated. The functionality is now covered by a property in the resource _SqlDatabase_ ([issue #966](https://github.com/dsccommunity/SqlServerDsc/issues/966)). - SqlDatabaseRecoveryModel - This resource is now deprecated. The functionality is now covered by a property in the resource _SqlDatabase_ ([issue #967](https://github.com/dsccommunity/SqlServerDsc/issues/967)). +- SqlServerEndpointState + - This resource is now deprecated. The functionality is covered by a + property in the resource _SqlServerEndpoint_ ([issue #968](https://github.com/dsccommunity/SqlServerDsc/issues/968)). +- SqlServerNetwork + - This resource is now deprecated. The functionality is now covered by + the resources _SqlServerProtocol_ and _SqlServerProtocolTcpIp_. ### Added @@ -38,6 +41,14 @@ in a future release. - Added new resource SqlServerProtocolTcpIp ([issue #1378](https://github.com/dsccommunity/SqlServerDsc/issues/1378)). - Fixing a problem with the latest ModuleBuild 1.7.0 that breaks the CI pipeline. +- SqlServerEndpoint + - BREAKING CHANGE: A new required property `EndpointType` was added to + support different types of endpoints in the future. For now the only + endpoint type that is supported is the database mirror endpoint type + (`DatabaseMirroring`). + - Added the property `State` to be able to specify if the endpoint should + be running, stopped, or disabled. _This property was moved from the now_ + _deprecated DSC resource `SqlServerEndpointState`_. - SqlSetup - A read only property `IsClustered` was added that can be used to determine if the instance is clustered. @@ -72,6 +83,9 @@ in a future release. - SqlServerDsc.Common - The helper function `Invoke-InstallationMediaCopy` was changed to handle a breaking change in PowerShell 7 ([issue #1530](https://github.com/dsccommunity/SqlServerDsc/issues/1530)). +- CommonTestHelper + - The test helper function `New-SQLSelfSignedCertificate` was changed + to install the dependent module `PSPKI` through `RequiredModules.psd1`. - SqlAlwaysOnService - BREAKING CHANGE: The parameter `ServerName` is now non-mandatory and defaults to `$env:COMPUTERNAME` ([issue #319](https://github.com/dsccommunity/SqlServerDsc/issues/319)). @@ -118,6 +132,8 @@ in a future release. - SqlServerDatabaseMail - Normalize parameter descriptive text for default values. - SqlServerEndpoint + - BREAKING CHANGE: Now the properties are only enforced if they are + specified in the configuration. - Normalize parameter descriptive text for default values. - SqlServerEndpointPermission - BREAKING CHANGE: The parameter `ServerName` is now non-mandatory and diff --git a/README.md b/README.md index baf4fb21b..2dd9578d4 100644 --- a/README.md +++ b/README.md @@ -71,8 +71,9 @@ The documentation, examples, unit test, and integration tests have been removed for these deprecated resources. These resources will be removed in a future release. -* SqlDatabaseOwner _(replaced by a property in [**SqlDatabase**](#sqldatabase)_. -* SqlDatabaseRecoveryModel _(replaced by a property in [**SqlDatabase**](#sqldatabase)_. +* SqlDatabaseOwner _(replaced by a property in [**SqlDatabase**](#sqldatabase))_. +* SqlDatabaseRecoveryModel _(replaced by a property in [**SqlDatabase**](#sqldatabase))_. +* SqlServerEndpointState _(replaced by [**SqlServerEndpoint**](#sqlserverendpoint))_. * SqlServerNetwork _(replaced by [**SqlServerProtocol**](#sqlserverprotocol) and_ _[**SqlServerProtocolTcpIp**](#sqlserverprotocoltcpip))_. @@ -119,7 +120,6 @@ in a future release. is present or absent. * [**SqlServerEndpointPermission**](#sqlserverendpointpermission) Grant or revoke permission on the endpoint. -* [**SqlServerEndpointState**](#sqlserverendpointstate) Change state of the endpoint. * [**SqlServerLogin**](#sqlserverlogin) resource to manage SQL logins. * [**SqlServerMaxDop**](#sqlservermaxdop) resource to manage MaxDegree of Parallelism for SQL Server. @@ -1248,10 +1248,10 @@ All issues are not listed here, see [here for all open issues](https://github.co This resource is used to create an endpoint. Currently it only supports creating a database mirror endpoint which can be used by, for example, AlwaysOn. ->Note: The endpoint will be started after creation, but will not be enforced. Please -use [**SqlServerEndpointState**](#sqlserverendpointstate) to make sure the endpoint -remains in started state. To set connect permission to the endpoint, please use -the resource [**SqlServerEndpointPermission**](#sqlserverendpointpermission). +>Note: The endpoint will be started after creation, but will not be enforced +>unless the the parameter `State` is specified. +>To set connect permission to the endpoint, please use +>the resource [**SqlServerEndpointPermission**](#sqlserverendpointpermission). #### Requirements @@ -1266,17 +1266,26 @@ the resource [**SqlServerEndpointPermission**](#sqlserverendpointpermission). #### Parameters * **`[String]` EndpointName** _(Key)_: The name of the endpoint. +* **`[String]` InstanceName** _(Key)_: The name of the SQL instance to be configured. +* **`[String]` EndpointType** _(Required)_: Specifies the type of endpoint. Currently + the only type that is supported is the Database Mirror type. { *DatabaseMirroring* }. * **`[String]` Ensure** _(Write)_: If the endpoint should be present or absent. Default values is 'Present'. { *Present* | Absent }. * **`[Uint16]` Port** _(Write)_: The network port the endpoint is listening on. - Default value is 5022. + Default value is 5022, but default value is only used during endpoint creation, + it is not enforce. * **`[String]` ServerName** _(Write)_: The host name of the SQL Server to be configured. Default value is $env:COMPUTERNAME. -* **`[String]` InstanceName** _(Key)_: The name of the SQL instance to be configured. * **`[String]` IpAddress** _(Write)_: The network IP address the endpoint is listening on. Default value is '0.0.0.0' which means listen on any valid IP address. + The default value is only used during endpoint creation, it is not enforce. * **`[String]` Owner** _(Write)_: The owner of the endpoint. Default is the login used for the creation. +* **`[String]` State** _(Write)_: Specifies the state of the endpoint. Valid + states are Started, Stopped, or Disabled. When an endpoint is created and + the state is not specified then the endpoint will be started after it is + created. The state will not be enforced unless the parameter is specified. + { Started | Stopped | Disabled }. #### Examples @@ -1320,38 +1329,6 @@ This resource is used to give connect permission to an endpoint for a user (logi All issues are not listed here, see [here for all open issues](https://github.com/dsccommunity/SqlServerDsc/issues?q=is%3Aissue+is%3Aopen+in%3Atitle+SqlServerEndpointPermission). -### SqlServerEndpointState - -This resource is used to set the state of an endpoint. - ->Note: Currently this resource can only be used with Database Mirror endpoints. - -#### Requirements - -* Target machine must be running Windows Server 2012 or later. -* Target machine must be running SQL Server Database Engine 2012 or later. -* Target machine must have access to the SQLPS PowerShell module or the SqlServer - PowerShell module. - -#### Parameters - -* **`[String]` InstanceName** _(Key)_: The name of the SQL instance to be configured. -* **`[String]` ServerName** _(Write)_: The host name of the SQL Server to be configured. - Default value is $env:COMPUTERNAME. -* **`[String]` Name** _(Key)_: The name of the endpoint. -* **`[String]` State** _(Write)_: The state of the endpoint. Valid states are Started, - Stopped or Disabled. Default value is 'Started'. - { *Started* | Stopped | Disabled }. - -#### Examples - -* [Make sure that an endpoint is started](/source/Examples/Resources/SqlServerEndpointState/1-MakeSureEndpointIsStarted.ps1) -* [Make sure that an endpoint is stopped](/source/Examples/Resources/SqlServerEndpointState/2-MakeSureEndpointIsStopped.ps1) - -#### Known issues - -All issues are not listed here, see [here for all open issues](https://github.com/dsccommunity/SqlServerDsc/issues?q=is%3Aissue+is%3Aopen+in%3Atitle+SqlServerEndpointState). - ### SqlServerLogin No description. diff --git a/RequiredModules.psd1 b/RequiredModules.psd1 index d1ea4c64c..6abf5b2a5 100644 --- a/RequiredModules.psd1 +++ b/RequiredModules.psd1 @@ -23,6 +23,7 @@ # Dependency for integration tests LoopbackAdapter = 'latest' + PSPKI = 'latest' # Prerequisites modules needed for examples or integration tests PSDscResources = '2.12.0.0' diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 6e62822db..b84f62a13 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -145,7 +145,7 @@ stages: 'tests/Integration/DSC_SqlAgentAlert.Integration.Tests.ps1' 'tests/Integration/DSC_SqlServerNetwork.Integration.Tests.ps1' 'tests/Integration/DSC_SqlServerLogin.Integration.Tests.ps1' - 'tests/Integration/DSC_SqlServerEndPoint.Integration.Tests.ps1' + 'tests/Integration/DSC_SqlServerEndpoint.Integration.Tests.ps1' 'tests/Integration/DSC_SqlServerDatabaseMail.Integration.Tests.ps1' 'tests/Integration/DSC_SqlRSSetup.Integration.Tests.ps1' 'tests/Integration/DSC_SqlDatabaseDefaultLocation.Integration.Tests.ps1' @@ -211,7 +211,7 @@ stages: # Group 2 'tests/Integration/DSC_SqlAgentAlert.Integration.Tests.ps1' 'tests/Integration/DSC_SqlServerLogin.Integration.Tests.ps1' - 'tests/Integration/DSC_SqlServerEndPoint.Integration.Tests.ps1' + 'tests/Integration/DSC_SqlServerEndpoint.Integration.Tests.ps1' 'tests/Integration/DSC_SqlServerDatabaseMail.Integration.Tests.ps1' 'tests/Integration/DSC_SqlRSSetup.Integration.Tests.ps1' 'tests/Integration/DSC_SqlDatabaseDefaultLocation.Integration.Tests.ps1' diff --git a/build.yaml b/build.yaml index 28b7c3291..e4fcafedd 100644 --- a/build.yaml +++ b/build.yaml @@ -63,6 +63,7 @@ Pester: - source/DSCResources/MSFT_SqlServerNetwork - source/DSCResources/MSFT_SqlDatabaseOwner - source/DSCResources/MSFT_SqlDatabaseRecoveryModel + - source/DSCResources/MSFT_SqlServerEndpointState Script: - tests/Unit ExcludeTag: @@ -81,12 +82,14 @@ DscTest: - source/DSCResources/MSFT_SqlServerNetwork - source/DSCResources/MSFT_SqlDatabaseOwner - source/DSCResources/MSFT_SqlDatabaseRecoveryModel + - source/DSCResources/MSFT_SqlServerEndpointState ExcludeModuleFile: - Modules/DscResource.Common # Deprecated resources - DSCResources/MSFT_SqlServerNetwork - DSCResources/MSFT_SqlDatabaseOwner - DSCResources/MSFT_SqlDatabaseRecoveryModel + - DSCResources/MSFT_SqlServerEndpointState Resolve-Dependency: Gallery: 'PSGallery' diff --git a/codecov.yml b/codecov.yml index e8f3830b9..f7a355312 100644 --- a/codecov.yml +++ b/codecov.yml @@ -32,3 +32,4 @@ ignore: - 'source/DSCResources/MSFT_SqlServerNetwork' - 'source/DSCResources/MSFT_SqlDatabaseOwner' - 'source/DSCResources/MSFT_SqlDatabaseRecoveryModel' + - 'source/DSCResources/MSFT_SqlServerEndpointState' diff --git a/source/DSCResources/DSC_SqlServerEndpoint/DSC_SqlServerEndpoint.psm1 b/source/DSCResources/DSC_SqlServerEndpoint/DSC_SqlServerEndpoint.psm1 index 09b81d379..d6967240c 100644 --- a/source/DSCResources/DSC_SqlServerEndpoint/DSC_SqlServerEndpoint.psm1 +++ b/source/DSCResources/DSC_SqlServerEndpoint/DSC_SqlServerEndpoint.psm1 @@ -13,11 +13,23 @@ $script:localizedData = Get-LocalizedData -DefaultUICulture 'en-US' .PARAMETER EndpointName The name of the endpoint. + .PARAMETER EndpointType + Specifies the type of endpoint. Currently the only type that is supported + is the Database Mirror type. + .PARAMETER ServerName The host name of the SQL Server to be configured. Default value is $env:COMPUTERNAME. .PARAMETER InstanceName The name of the SQL instance to be configured. + + .NOTES + Get-TargetResource throws an error when the endpoint does not match the + endpoint type. This is because the endpoint cannot be changed once + the endpoint have been created and manual intervention is needed. + Also Set-TargetResource and Test-TargetResource depends on that the + Get-TargetResource does this check so we don't need to have the same + check in those functions as well. #> function Get-TargetResource { @@ -29,6 +41,11 @@ function Get-TargetResource [System.String] $EndpointName, + [Parameter(Mandatory = $true)] + [ValidateSet('DatabaseMirroring')] + [System.String] + $EndpointType, + [Parameter()] [ValidateNotNullOrEmpty()] [System.String] @@ -46,14 +63,17 @@ function Get-TargetResource $getTargetResourceReturnValues = @{ ServerName = $ServerName InstanceName = $InstanceName + EndpointType = $EndpointType Ensure = 'Absent' EndpointName = '' Port = '' IpAddress = '' Owner = '' + State = $null } $sqlServerObject = Connect-SQL -ServerName $ServerName -InstanceName $InstanceName + if ($sqlServerObject) { Write-Verbose -Message ( @@ -63,9 +83,9 @@ function Get-TargetResource $endpointObject = $sqlServerObject.Endpoints[$EndpointName] if ($endpointObject.Name -eq $EndpointName) { - if ($sqlServerObject.Endpoints[$EndPointName].EndpointType -ne 'DatabaseMirroring') + if ($endpointObject.EndpointType -ne $EndpointType) { - $errorMessage = $script:localizedData.EndpointFoundButWrongType -f $EndpointName + $errorMessage = $script:localizedData.EndpointFoundButWrongType -f $EndpointName, $endpointObject.EndpointType, $EndpointType New-InvalidOperationException -Message $errorMessage } @@ -74,14 +94,7 @@ function Get-TargetResource $getTargetResourceReturnValues.Port = $endpointObject.Protocol.Tcp.ListenerPort $getTargetResourceReturnValues.IpAddress = $endpointObject.Protocol.Tcp.ListenerIPAddress $getTargetResourceReturnValues.Owner = $endpointObject.Owner - } - else - { - $getTargetResourceReturnValues.Ensure = 'Absent' - $getTargetResourceReturnValues.EndpointName = '' - $getTargetResourceReturnValues.Port = '' - $getTargetResourceReturnValues.IpAddress = '' - $getTargetResourceReturnValues.Owner = '' + $getTargetResourceReturnValues.State = $endpointObject.EndpointState } } else @@ -100,11 +113,16 @@ function Get-TargetResource .PARAMETER EndpointName The name of the endpoint. + .PARAMETER EndpointType + Specifies the type of endpoint. Currently the only type that is supported + is the Database Mirror type. + .PARAMETER Ensure If the endpoint should be present or absent. Default values is 'Present'. .PARAMETER Port - The network port the endpoint is listening on. Default value is 5022. + The network port the endpoint is listening on. Default value is 5022, but + default value is only used during endpoint creation, it is not enforce. .PARAMETER ServerName The host name of the SQL Server to be configured. Default value is $env:COMPUTERNAME. @@ -114,10 +132,17 @@ function Get-TargetResource .PARAMETER IpAddress The network IP address the endpoint is listening on. Default value is '0.0.0.0' - which means listen on any valid IP address. + which means listen on any valid IP address. The default value is only used + during endpoint creation, it is not enforce. .PARAMETER Owner The owner of the endpoint. Default is the login used for the creation. + + .PARAMETER State + Specifies the state of the endpoint. Valid states are Started, Stopped, or + Disabled. When an endpoint is created and the state is not specified then + the endpoint will be started after it is created. The state will not be + enforced unless the parameter is specified. #> function Set-TargetResource { @@ -128,6 +153,11 @@ function Set-TargetResource [System.String] $EndpointName, + [Parameter(Mandatory = $true)] + [ValidateSet('DatabaseMirroring')] + [System.String] + $EndpointType, + [Parameter()] [ValidateSet('Present', 'Absent')] [System.String] @@ -152,86 +182,168 @@ function Set-TargetResource [Parameter()] [System.String] - $Owner + $Owner, + + [Parameter()] + [ValidateSet('Started', 'Stopped', 'Disabled')] + [System.String] + $State ) - $getTargetResourceResult = Get-TargetResource -EndpointName $EndpointName -ServerName $ServerName -InstanceName $InstanceName + $getTargetResourceParameters = @{ + EndpointName = $EndpointName + EndpointType = $EndpointType + ServerName = $ServerName + InstanceName = $InstanceName + } + + $getTargetResourceResult = Get-TargetResource @getTargetResourceParameters $sqlServerObject = Connect-SQL -ServerName $ServerName -InstanceName $InstanceName + if ($sqlServerObject) { - if ($Ensure -eq 'Present' -and $getTargetResourceResult.Ensure -eq 'Absent') + if ($Ensure -eq 'Present') { - Write-Verbose -Message ( - $script:localizedData.CreateEndpoint -f $EndpointName, $InstanceName - ) - - $endpointObject = New-Object -TypeName Microsoft.SqlServer.Management.Smo.Endpoint -ArgumentList $sqlServerObject, $EndpointName - $endpointObject.EndpointType = [Microsoft.SqlServer.Management.Smo.EndpointType]::DatabaseMirroring - $endpointObject.ProtocolType = [Microsoft.SqlServer.Management.Smo.ProtocolType]::Tcp - $endpointObject.Protocol.Tcp.ListenerPort = $Port - $endpointObject.Protocol.Tcp.ListenerIPAddress = $IpAddress - - if ($PSBoundParameters.ContainsKey('Owner')) + if ($getTargetResourceResult.Ensure -eq 'Absent') { - $endpointObject.Owner = $Owner - } - - $endpointObject.Payload.DatabaseMirroring.ServerMirroringRole = [Microsoft.SqlServer.Management.Smo.ServerMirroringRole]::All - $endpointObject.Payload.DatabaseMirroring.EndpointEncryption = [Microsoft.SqlServer.Management.Smo.EndpointEncryption]::Required - $endpointObject.Payload.DatabaseMirroring.EndpointEncryptionAlgorithm = [Microsoft.SqlServer.Management.Smo.EndpointEncryptionAlgorithm]::Aes - $endpointObject.Create() - $endpointObject.Start() - } - elseif ($Ensure -eq 'Present' -and $getTargetResourceResult.Ensure -eq 'Present') - { - Write-Verbose -Message ( - $script:localizedData.SetEndpoint -f $EndpointName, $InstanceName - ) + Write-Verbose -Message ( + $script:localizedData.CreateEndpoint -f $EndpointName, $InstanceName + ) - # The endpoint already exist, verifying supported endpoint properties so they are in desired state. - $endpointObject = $sqlServerObject.Endpoints[$EndpointName] - if ($endpointObject) - { - if ($endpointObject.Protocol.Tcp.ListenerIPAddress -ne $IpAddress) + switch ($EndpointType) { - Write-Verbose -Message ( - $script:localizedData.UpdatingEndpointIPAddress -f $IpAddress - ) - - $endpointObject.Protocol.Tcp.ListenerIPAddress = $IpAddress - $endpointObject.Alter() + 'DatabaseMirroring' + { + $endpointObject = New-Object -TypeName 'Microsoft.SqlServer.Management.Smo.Endpoint' -ArgumentList @($sqlServerObject, $EndpointName) + $endpointObject.EndpointType = [Microsoft.SqlServer.Management.Smo.EndpointType]::DatabaseMirroring + $endpointObject.ProtocolType = [Microsoft.SqlServer.Management.Smo.ProtocolType]::Tcp + $endpointObject.Protocol.Tcp.ListenerPort = $Port + $endpointObject.Protocol.Tcp.ListenerIPAddress = $IpAddress + + if ($PSBoundParameters.ContainsKey('Owner')) + { + $endpointObject.Owner = $Owner + } + + $endpointObject.Payload.DatabaseMirroring.ServerMirroringRole = [Microsoft.SqlServer.Management.Smo.ServerMirroringRole]::All + $endpointObject.Payload.DatabaseMirroring.EndpointEncryption = [Microsoft.SqlServer.Management.Smo.EndpointEncryption]::Required + $endpointObject.Payload.DatabaseMirroring.EndpointEncryptionAlgorithm = [Microsoft.SqlServer.Management.Smo.EndpointEncryptionAlgorithm]::Aes + $endpointObject.Create() + + <# + If endpoint state is not specified, then default to + starting the endpoint. If state is specified then + it will be handled later. + #> + if (-not ($PSBoundParameters.ContainsKey('State'))) + { + $endpointObject.Start() + } + } } + } + else + { + Write-Verbose -Message ( + $script:localizedData.SetEndpoint -f $EndpointName, $InstanceName + ) - if ($endpointObject.Protocol.Tcp.ListenerPort -ne $Port) + $endpointObject = $sqlServerObject.Endpoints[$EndpointName] + + if (-not $endpointObject) { - Write-Verbose -Message ( - $script:localizedData.UpdatingEndpointPort -f $Port - ) + $errorMessage = $script:localizedData.EndpointNotFound -f $EndpointName - $endpointObject.Protocol.Tcp.ListenerPort = $Port - $endpointObject.Alter() + New-ObjectNotFoundException -Message $errorMessage } + } + + <# + The endpoint exist or was just created. Verifying supported + properties so they are in desired state. + #> - if ($endpointObject.Owner -ne $Owner) + # Properties regardless of endpoint type. + if ($PSBoundParameters.ContainsKey('State')) + { + if ($endpointObject.EndpointState -ne $State) { Write-Verbose -Message ( - $script:localizedData.UpdatingEndpointOwner -f $Owner + $script:localizedData.ChangingEndpointState -f $State ) - $endpointObject.Owner = $Owner - $endpointObject.Alter() + switch ($State) + { + 'Started' + { + $endpointObject.Start() + } + + 'Stopped' + { + $endpointObject.Stop() + } + + 'Disabled' + { + $endpointObject.Disable() + } + } } } - else + + # Individual endpoint type properties. + switch ($EndpointType) { - $errorMessage = $script:localizedData.EndpointNotFound -f $EndpointName - New-ObjectNotFoundException -Message $errorMessage + 'DatabaseMirroring' + { + if ($PSBoundParameters.ContainsKey('IpAddress')) + { + if ($endpointObject.Protocol.Tcp.ListenerIPAddress -ne $IpAddress) + { + Write-Verbose -Message ( + $script:localizedData.UpdatingEndpointIPAddress -f $IpAddress + ) + + $endpointObject.Protocol.Tcp.ListenerIPAddress = $IpAddress + $endpointObject.Alter() + } + } + + if ($PSBoundParameters.ContainsKey('Port')) + { + if ($endpointObject.Protocol.Tcp.ListenerPort -ne $Port) + { + Write-Verbose -Message ( + $script:localizedData.UpdatingEndpointPort -f $Port + ) + + $endpointObject.Protocol.Tcp.ListenerPort = $Port + $endpointObject.Alter() + } + } + + if ($PSBoundParameters.ContainsKey('Owner')) + { + if ($endpointObject.Owner -ne $Owner) + { + Write-Verbose -Message ( + $script:localizedData.UpdatingEndpointOwner -f $Owner + ) + + $endpointObject.Owner = $Owner + $endpointObject.Alter() + } + } + } } } - elseif ($Ensure -eq 'Absent' -and $getTargetResourceResult.Ensure -eq 'Present') + + if ($Ensure -eq 'Absent' -and $getTargetResourceResult.Ensure -eq 'Present') { $endpointObject = $sqlServerObject.Endpoints[$EndpointName] + if ($endpointObject) { Write-Verbose -Message ( @@ -243,6 +355,7 @@ function Set-TargetResource else { $errorMessage = $script:localizedData.EndpointNotFound -f $EndpointName + New-ObjectNotFoundException -Message $errorMessage } } @@ -250,6 +363,7 @@ function Set-TargetResource else { $errorMessage = $script:localizedData.NotConnectedToInstance -f $ServerName, $InstanceName + New-InvalidOperationException -Message $errorMessage } } @@ -261,11 +375,16 @@ function Set-TargetResource .PARAMETER EndpointName The name of the endpoint. + .PARAMETER EndpointType + Specifies the type of endpoint. Currently the only type that is supported + is the Database Mirror type. + .PARAMETER Ensure If the endpoint should be present or absent. Default values is 'Present'. .PARAMETER Port - The network port the endpoint is listening on. Default value is 5022. + The network port the endpoint is listening on. Default value is 5022, but + default value is only used during endpoint creation, it is not enforce. .PARAMETER ServerName The host name of the SQL Server to be configured. Default value is $env:COMPUTERNAME. @@ -275,10 +394,17 @@ function Set-TargetResource .PARAMETER IpAddress The network IP address the endpoint is listening on. Default value is '0.0.0.0' - which means listen on any valid IP address. + which means listen on any valid IP address. The default value is only used + during endpoint creation, it is not enforce. .PARAMETER Owner The owner of the endpoint. Default is the login used for the creation. + + .PARAMETER State + Specifies the state of the endpoint. Valid states are Started, Stopped, or + Disabled. When an endpoint is created and the state is not specified then + the endpoint will be started after it is created. The state will not be + enforced unless the parameter is specified. #> function Test-TargetResource { @@ -290,6 +416,11 @@ function Test-TargetResource [System.String] $EndpointName, + [Parameter(Mandatory = $true)] + [ValidateSet('DatabaseMirroring')] + [System.String] + $EndpointType, + [Parameter()] [ValidateSet('Present', 'Absent')] [System.String] @@ -314,18 +445,48 @@ function Test-TargetResource [Parameter()] [System.String] - $Owner + $Owner, + + [Parameter()] + [ValidateSet('Started', 'Stopped', 'Disabled')] + [System.String] + $State ) Write-Verbose -Message ( $script:localizedData.TestingConfiguration -f $EndpointName, $InstanceName ) - $getTargetResourceResult = Get-TargetResource -EndpointName $EndpointName -ServerName $ServerName -InstanceName $InstanceName + $getTargetResourceParameters = @{ + EndpointName = $EndpointName + EndpointType = $EndpointType + ServerName = $ServerName + InstanceName = $InstanceName + } + + $getTargetResourceResult = Get-TargetResource @getTargetResourceParameters + if ($getTargetResourceResult.Ensure -eq $Ensure) { $result = $true + if ($PSBoundParameters.ContainsKey('Owner')) + { + if ($getTargetResourceResult.Owner -ne $Owner) + { + $result = $false + } + } + + + if ($PSBoundParameters.ContainsKey('State')) + { + if ($getTargetResourceResult.State -ne $State) + { + $result = $false + } + } + if ($getTargetResourceResult.Ensure -eq 'Present' ` -and ( $getTargetResourceResult.Port -ne $Port ` @@ -335,12 +496,6 @@ function Test-TargetResource { $result = $false } - elseif ($getTargetResourceResult.Ensure -eq 'Present' -and $Owner ` - -and $getTargetResourceResult.Owner -ne $Owner - ) - { - $result = $false - } } else { diff --git a/source/DSCResources/DSC_SqlServerEndpoint/DSC_SqlServerEndpoint.schema.mof b/source/DSCResources/DSC_SqlServerEndpoint/DSC_SqlServerEndpoint.schema.mof index 13ff6d80a..8a247ba04 100644 --- a/source/DSCResources/DSC_SqlServerEndpoint/DSC_SqlServerEndpoint.schema.mof +++ b/source/DSCResources/DSC_SqlServerEndpoint/DSC_SqlServerEndpoint.schema.mof @@ -2,10 +2,12 @@ class DSC_SqlServerEndpoint : OMI_BaseResource { [Key, Description("The name of the endpoint.")] String EndpointName; + [Key, Description("The name of the SQL instance to be configured.")] String InstanceName; + [Required, Description("Specifies the type of endpoint. Currently the only type that is supported is the Database Mirror type."), ValueMap{"DatabaseMirroring"}, Values{"DatabaseMirroring"}] String EndpointType; [Write, Description("If the endpoint should be present or absent. Default values is 'Present'."), ValueMap{"Present","Absent"}, Values{"Present","Absent"}] String Ensure; - [Write, Description("The network port the endpoint is listening on. Default value is 5022.")] Uint16 Port; + [Write, Description("The network port the endpoint is listening on. Default value is 5022, but default value is only used during endpoint creation, it is not enforce.")] Uint16 Port; [Write, Description("The host name of the SQL Server to be configured. Default value is $env:COMPUTERNAME.")] String ServerName; - [Key, Description("The name of the SQL instance to be configured.")] String InstanceName; - [Write, Description("The network IP address the endpoint is listening on. Default the endpoint will listen on any valid IP address.")] String IpAddress; + [Write, Description("The network IP address the endpoint is listening on. Default the endpoint will listen on any valid IP address. The default value is only used during endpoint creation, it is not enforce.")] String IpAddress; [Write, Description("The owner of the endpoint. Default is the login used for the creation.")] String Owner; + [Write, Description("Specifies the state of the endpoint. Valid states are Started, Stopped, or Disabled. When an endpoint is created and the state is not specified then the endpoint will be started after it is created. The state will not be enforced unless the parameter is specified."), ValueMap{"Started","Stopped","Disabled"}, Values{"Started","Stopped","Disabled"}] String State; }; diff --git a/source/DSCResources/DSC_SqlServerEndpoint/en-US/DSC_SqlServerEndpoint.strings.psd1 b/source/DSCResources/DSC_SqlServerEndpoint/en-US/DSC_SqlServerEndpoint.strings.psd1 index fc20c5c6f..3452dce61 100644 --- a/source/DSCResources/DSC_SqlServerEndpoint/en-US/DSC_SqlServerEndpoint.strings.psd1 +++ b/source/DSCResources/DSC_SqlServerEndpoint/en-US/DSC_SqlServerEndpoint.strings.psd1 @@ -1,6 +1,6 @@ ConvertFrom-StringData @' GetEndpoint = Getting the current values of the endpoint with the name '{0}' for the instance '{1}'. - EndpointFoundButWrongType = Endpoint '{0}' does exist, but it is not of type 'DatabaseMirroring'. + EndpointFoundButWrongType = The endpoint '{0}' is of type '{1}', but expected it to be of type '{2}'. ConnectedToInstance = Connect to the instance '{0}\\{1}'. NotConnectedToInstance = Was unable to connect to the instance '{0}\\{1}'. SetEndpoint = Changing the values of the endpoint with the name '{0}' for the instance '{1}'. @@ -8,6 +8,7 @@ ConvertFrom-StringData @' UpdatingEndpointIPAddress = Updating the endpoint IP address to '{0}'. UpdatingEndpointPort = Updating the endpoint port to '{0}'. UpdatingEndpointOwner = Updating the endpoint owner to '{0}'. + ChangingEndpointState = Changing the endpoint state to '{0}'. EndpointNotFound = The endpoint with the name '{0}' does not exist. DropEndpoint = Removing the endpoint '{0}' on the instance '{1}'. TestingConfiguration = Determines if the endpoint with the name '{0}' for the instance '{1}' is in desired state. diff --git a/source/DSCResources/DSC_SqlServerEndpointState/DSC_SqlServerEndpointState.psm1 b/source/DSCResources/MSFT_SqlServerEndpointState/MSFT_SqlServerEndpointState.psm1 similarity index 97% rename from source/DSCResources/DSC_SqlServerEndpointState/DSC_SqlServerEndpointState.psm1 rename to source/DSCResources/MSFT_SqlServerEndpointState/MSFT_SqlServerEndpointState.psm1 index 59a1a27f1..71d878a7d 100644 --- a/source/DSCResources/DSC_SqlServerEndpointState/DSC_SqlServerEndpointState.psm1 +++ b/source/DSCResources/MSFT_SqlServerEndpointState/MSFT_SqlServerEndpointState.psm1 @@ -1,3 +1,11 @@ +<# + DEPRECATION NOTICE: + + THIS RESOURCE IS DEPRECATED! + + Changes to this resource will no longer be merged. Instead please use the + resources SqlServerEndpoint. +#> $script:sqlServerDscHelperModulePath = Join-Path -Path $PSScriptRoot -ChildPath '..\..\Modules\SqlServerDsc.Common' $script:resourceHelperModulePath = Join-Path -Path $PSScriptRoot -ChildPath '..\..\Modules\DscResource.Common' diff --git a/source/DSCResources/DSC_SqlServerEndpointState/DSC_SqlServerEndpointState.schema.mof b/source/DSCResources/MSFT_SqlServerEndpointState/MSFT_SqlServerEndpointState.schema.mof similarity index 91% rename from source/DSCResources/DSC_SqlServerEndpointState/DSC_SqlServerEndpointState.schema.mof rename to source/DSCResources/MSFT_SqlServerEndpointState/MSFT_SqlServerEndpointState.schema.mof index 47ddbb077..61062db7b 100644 --- a/source/DSCResources/DSC_SqlServerEndpointState/DSC_SqlServerEndpointState.schema.mof +++ b/source/DSCResources/MSFT_SqlServerEndpointState/MSFT_SqlServerEndpointState.schema.mof @@ -1,5 +1,5 @@ [ClassVersion("1.0.0.0"), FriendlyName("SqlServerEndpointState")] -class DSC_SqlServerEndpointState : OMI_BaseResource +class MSFT_SqlServerEndpointState : OMI_BaseResource { [Key, Description("The name of the SQL instance to be configured.")] String InstanceName; [Write, Description("The host name of the SQL Server to be configured. Default value is $env:COMPUTERNAME.")] String ServerName; diff --git a/source/DSCResources/DSC_SqlServerEndpointState/en-US/DSC_SqlServerEndpointState.strings.psd1 b/source/DSCResources/MSFT_SqlServerEndpointState/en-US/MSFT_SqlServerEndpointState.strings.psd1 similarity index 86% rename from source/DSCResources/DSC_SqlServerEndpointState/en-US/DSC_SqlServerEndpointState.strings.psd1 rename to source/DSCResources/MSFT_SqlServerEndpointState/en-US/MSFT_SqlServerEndpointState.strings.psd1 index 2962cc004..719c4c153 100644 --- a/source/DSCResources/DSC_SqlServerEndpointState/en-US/DSC_SqlServerEndpointState.strings.psd1 +++ b/source/DSCResources/MSFT_SqlServerEndpointState/en-US/MSFT_SqlServerEndpointState.strings.psd1 @@ -1,5 +1,5 @@ ConvertFrom-StringData @' - GetEndpointState = Getting state of the endpoint with the name '{0}' for the instance '{1}'. + GetEndpointState = THIS RESOURCE IS DEPRECATED! Getting state of the endpoint with the name '{0}' for the instance '{1}'. EndpointNotFound = The endpoint with the name '{0}' does not exist. EndpointErrorVerifyExist = Unexpected result when trying to verify existence of the endpoint with the name '{0}'. UnexpectedErrorFromGet = Got unexpected result from Get-TargetResource. No change is made. diff --git a/source/Examples/README.md b/source/Examples/README.md index 55ce2b82c..01d621f04 100644 --- a/source/Examples/README.md +++ b/source/Examples/README.md @@ -28,7 +28,6 @@ These are the links to the examples for each individual resource. - [SqlServerDatabaseMail](Resources/SqlServerDatabaseMail) - [SqlServerEndpoint](Resources/SqlServerEndpoint) - [SqlServerEndpointPermission](Resources/SqlServerEndpointPermission) -- [SqlServerEndpointState](Resources/SqlServerEndpointState) - [SqlServerLogin](Resources/SqlServerLogin) - [SqlServerMaxDop](Resources/SqlServerMaxDop) - [SqlServerMemory](Resources/SqlServerMemory) diff --git a/source/Examples/Resources/SqlAG/1-CreateAvailabilityGroup.ps1 b/source/Examples/Resources/SqlAG/1-CreateAvailabilityGroup.ps1 index 57164eaca..54809d512 100644 --- a/source/Examples/Resources/SqlAG/1-CreateAvailabilityGroup.ps1 +++ b/source/Examples/Resources/SqlAG/1-CreateAvailabilityGroup.ps1 @@ -45,6 +45,7 @@ Configuration Example SqlServerEndpoint 'HADREndpoint' { EndPointName = 'HADR' + EndpointType = 'DatabaseMirroring' Ensure = 'Present' Port = 5022 ServerName = $Node.NodeName diff --git a/source/Examples/Resources/SqlAG/3-CreateAvailabilityGroupDetailed.ps1 b/source/Examples/Resources/SqlAG/3-CreateAvailabilityGroupDetailed.ps1 index 79ac51ef1..b43b987b5 100644 --- a/source/Examples/Resources/SqlAG/3-CreateAvailabilityGroupDetailed.ps1 +++ b/source/Examples/Resources/SqlAG/3-CreateAvailabilityGroupDetailed.ps1 @@ -48,6 +48,7 @@ Configuration Example SqlServerEndpoint 'HADREndpoint' { EndPointName = 'HADR' + EndpointType = 'DatabaseMirroring' Ensure = 'Present' Port = 5022 ServerName = $Node.NodeName diff --git a/source/Examples/Resources/SqlAGReplica/1-CreateAvailabilityGroupReplica.ps1 b/source/Examples/Resources/SqlAGReplica/1-CreateAvailabilityGroupReplica.ps1 index 21d66147b..132f959e0 100644 --- a/source/Examples/Resources/SqlAGReplica/1-CreateAvailabilityGroupReplica.ps1 +++ b/source/Examples/Resources/SqlAGReplica/1-CreateAvailabilityGroupReplica.ps1 @@ -51,6 +51,7 @@ Configuration Example SqlServerEndpoint 'HADREndpoint' { EndPointName = 'HADR' + EndpointType = 'DatabaseMirroring' Ensure = 'Present' Port = 5022 ServerName = $Node.NodeName diff --git a/source/Examples/Resources/SqlServerEndpoint/1-CreateEndpointWithDefaultValues.ps1 b/source/Examples/Resources/SqlServerEndpoint/1-CreateEndpointWithDefaultValues.ps1 index f69bd46ba..ceb897c14 100644 --- a/source/Examples/Resources/SqlServerEndpoint/1-CreateEndpointWithDefaultValues.ps1 +++ b/source/Examples/Resources/SqlServerEndpoint/1-CreateEndpointWithDefaultValues.ps1 @@ -20,6 +20,7 @@ Configuration Example SqlServerEndpoint 'SQLConfigureEndpoint-Instance1' { EndpointName = 'HADR' + EndpointType = 'DatabaseMirroring' InstanceName = 'INST1' PsDscRunAsCredential = $SqlAdministratorCredential @@ -28,6 +29,7 @@ Configuration Example SqlServerEndpoint 'SQLConfigureEndpoint-Instances2' { EndpointName = 'HADR' + EndpointType = 'DatabaseMirroring' InstanceName = 'INST2' PsDscRunAsCredential = $SqlAdministratorCredential diff --git a/source/Examples/Resources/SqlServerEndpoint/2-CreateEndpointWithSpecificPortIPAddressOwner.ps1 b/source/Examples/Resources/SqlServerEndpoint/2-CreateEndpointWithSpecificPortIPAddressOwner.ps1 index e72c1c80e..57ac73f5e 100644 --- a/source/Examples/Resources/SqlServerEndpoint/2-CreateEndpointWithSpecificPortIPAddressOwner.ps1 +++ b/source/Examples/Resources/SqlServerEndpoint/2-CreateEndpointWithSpecificPortIPAddressOwner.ps1 @@ -21,9 +21,11 @@ Configuration Example Ensure = 'Present' EndpointName = 'HADR' + EndpointType = 'DatabaseMirroring' Port = 9001 IpAddress = '192.168.0.20' Owner = 'sa' + State = 'Started' ServerName = 'server1.company.local' InstanceName = 'INST1' diff --git a/source/Examples/Resources/SqlServerEndpoint/3-RemoveEndpoint.ps1 b/source/Examples/Resources/SqlServerEndpoint/3-RemoveEndpoint.ps1 index 6d4d02403..e18e084c2 100644 --- a/source/Examples/Resources/SqlServerEndpoint/3-RemoveEndpoint.ps1 +++ b/source/Examples/Resources/SqlServerEndpoint/3-RemoveEndpoint.ps1 @@ -20,6 +20,7 @@ Configuration Example Ensure = 'Absent' EndpointName = 'HADR' + EndpointType = 'DatabaseMirroring' InstanceName = 'INST1' PsDscRunAsCredential = $SqlAdministratorCredential @@ -30,6 +31,7 @@ Configuration Example Ensure = 'Absent' EndpointName = 'HADR' + EndpointType = 'DatabaseMirroring' InstanceName = 'INST2' PsDscRunAsCredential = $SqlAdministratorCredential diff --git a/source/Examples/Resources/SqlServerEndpointState/1-MakeSureEndpointIsStarted.ps1 b/source/Examples/Resources/SqlServerEndpointState/1-MakeSureEndpointIsStarted.ps1 deleted file mode 100644 index 220d7bf6e..000000000 --- a/source/Examples/Resources/SqlServerEndpointState/1-MakeSureEndpointIsStarted.ps1 +++ /dev/null @@ -1,61 +0,0 @@ -<# - .DESCRIPTION - This example will - - make sure that the endpoint DefaultMirrorEndpoint is in started state - in the default instance, if not it will start the endpoint. - - make sure that the endpoint HADR is in started state in the default - instance, if not it will start the endpoint. - - make sure that the endpoint DefaultMirrorEndpoint is in started state - in the named instance INSTANCE1, if not it will start the endpoint. - - .NOTES - There is three different scenarios in this example to validate the schema - during unit testing. -#> -Configuration Example -{ - param - ( - [Parameter(Mandatory = $true)] - [System.Management.Automation.PSCredential] - $SqlAdministratorCredential - ) - - Import-DscResource -ModuleName 'SqlServerDsc' - - node localhost - { - # Start the DefaultMirrorEndpoint in the default instance - SqlServerEndpointState 'StartEndpoint1' - { - ServerName = 'SQLNODE01.company.local' - InstanceName = 'MSSQLSERVER' - Name = 'DefaultMirrorEndpoint' - State = 'Started' - - PsDscRunAsCredential = $SqlAdministratorCredential - } - - # Start the HADR in the default instance - SqlServerEndpointState 'StartEndpoint2' - { - ServerName = 'SQLNODE01.company.local' - InstanceName = 'MSSQLSERVER' - Name = 'HADR' - State = 'Started' - - PsDscRunAsCredential = $SqlAdministratorCredential - } - - # Start the DefaultMirrorEndpoint in the named instance INSTANCE1 - SqlServerEndpointState 'StartEndpoint3' - { - ServerName = 'SQLNODE01.company.local' - InstanceName = 'INSTANCE1' - Name = 'DefaultMirrorEndpoint' - State = 'Started' - - PsDscRunAsCredential = $SqlAdministratorCredential - } - } -} diff --git a/source/Examples/Resources/SqlServerEndpointState/2-MakeSureEndpointIsStopped.ps1 b/source/Examples/Resources/SqlServerEndpointState/2-MakeSureEndpointIsStopped.ps1 deleted file mode 100644 index 451482c54..000000000 --- a/source/Examples/Resources/SqlServerEndpointState/2-MakeSureEndpointIsStopped.ps1 +++ /dev/null @@ -1,30 +0,0 @@ -<# - .DESCRIPTION - This example will make sure that the endpoint DefaultMirrorEndpoint is - in stopped state, if not it will stop the endpoint. -#> -Configuration Example -{ - param - ( - [Parameter(Mandatory = $true)] - [System.Management.Automation.PSCredential] - $SqlAdministratorCredential - ) - - Import-DscResource -ModuleName 'SqlServerDsc' - - node localhost - { - SqlServerEndpointState 'StopEndpoint' - { - ServerName = 'SQLNODE01.company.local' - InstanceName = 'MSSQLSERVER' - Name = 'DefaultMirrorEndpoint' - State = 'Stopped' - - PsDscRunAsCredential = $SqlAdministratorCredential - - } - } -} diff --git a/tests/Integration/DSC_SqlServerEndPoint.Integration.Tests.ps1 b/tests/Integration/DSC_SqlServerEndpoint.Integration.Tests.ps1 similarity index 95% rename from tests/Integration/DSC_SqlServerEndPoint.Integration.Tests.ps1 rename to tests/Integration/DSC_SqlServerEndpoint.Integration.Tests.ps1 index c2ea37d33..8bdb68fcd 100644 --- a/tests/Integration/DSC_SqlServerEndPoint.Integration.Tests.ps1 +++ b/tests/Integration/DSC_SqlServerEndpoint.Integration.Tests.ps1 @@ -74,9 +74,11 @@ try $resourceCurrentState.Ensure | Should -Be 'Present' $resourceCurrentState.EndpointName | Should -Be $ConfigurationData.AllNodes.EndpointName + $resourceCurrentState.EndpointType | Should -Be 'DatabaseMirroring' $resourceCurrentState.Port | Should -Be $ConfigurationData.AllNodes.Port $resourceCurrentState.IpAddress | Should -Be $ConfigurationData.AllNodes.IpAddress $resourceCurrentState.Owner | Should -Be $ConfigurationData.AllNodes.Owner + $resourceCurrentState.State | Should -Be 'Started' } It 'Should return $true when Test-DscConfiguration is run' { @@ -123,6 +125,7 @@ try $resourceCurrentState.Ensure | Should -Be 'Absent' $resourceCurrentState.EndpointName | Should -BeNullOrEmpty + $resourceCurrentState.EndpointType | Should -Be 'DatabaseMirroring' } It 'Should return $true when Test-DscConfiguration is run' { diff --git a/tests/Integration/DSC_SqlServerEndPoint.config.ps1 b/tests/Integration/DSC_SqlServerEndpoint.config.ps1 similarity index 93% rename from tests/Integration/DSC_SqlServerEndPoint.config.ps1 rename to tests/Integration/DSC_SqlServerEndpoint.config.ps1 index db76d76a7..363dd1344 100644 --- a/tests/Integration/DSC_SqlServerEndPoint.config.ps1 +++ b/tests/Integration/DSC_SqlServerEndpoint.config.ps1 @@ -46,9 +46,11 @@ Configuration DSC_SqlServerEndpoint_Add_Config Ensure = 'Present' EndpointName = $Node.EndpointName + EndpointType = 'DatabaseMirroring' Port = $Node.Port IpAddress = $Node.IpAddress Owner = $Node.Owner + State = 'Started' ServerName = $Node.ServerName InstanceName = $Node.InstanceName @@ -71,6 +73,7 @@ Configuration DSC_SqlServerEndpoint_Remove_Config Ensure = 'Absent' EndpointName = $Node.EndpointName + EndpointType = 'DatabaseMirroring' ServerName = $Node.ServerName InstanceName = $Node.InstanceName diff --git a/tests/TestHelpers/CommonTestHelper.psm1 b/tests/TestHelpers/CommonTestHelper.psm1 index ddad7d34a..56d2f50cd 100644 --- a/tests/TestHelpers/CommonTestHelper.psm1 +++ b/tests/TestHelpers/CommonTestHelper.psm1 @@ -252,7 +252,6 @@ function New-SQLSelfSignedCertificate There are build workers still on Windows Server 2012 R2 so let's use the alternate method of New-SelfSignedCertificate. #> - Install-Module -Name 'PSPKI' -Scope 'CurrentUser' -Force Import-Module -Name 'PSPKI' $newSelfSignedCertificateExParameters = @{ diff --git a/tests/Unit/DSC_SqlServerEndpoint.Tests.ps1 b/tests/Unit/DSC_SqlServerEndpoint.Tests.ps1 index 59e6a3c2d..a1a41a3d8 100644 --- a/tests/Unit/DSC_SqlServerEndpoint.Tests.ps1 +++ b/tests/Unit/DSC_SqlServerEndpoint.Tests.ps1 @@ -75,12 +75,14 @@ try $mockDynamicEndpointListenerPort = $mockEndpointListenerPort $mockDynamicEndpointListenerIpAddress = $mockEndpointListenerIpAddress $mockDynamicEndpointOwner = $mockEndpointOwner + $mockDynamicEndpointState = 'Started' $mockEndpointObject = { # TypeName: Microsoft.SqlServer.Management.Smo.Endpoint return New-Object -TypeName Object | Add-Member -MemberType NoteProperty -Name 'Name' -Value $mockDynamicEndpointName -PassThru | Add-Member -MemberType NoteProperty -Name 'EndpointType' -Value $mockDynamicEndpointType -PassThru | + Add-Member -MemberType NoteProperty -Name 'EndpointState' -Value $mockDynamicEndpointState -PassThru | Add-Member -MemberType NoteProperty -Name 'ProtocolType' -Value $null -PassThru | Add-Member -MemberType NoteProperty -Name 'Owner' -Value $mockDynamicEndpointOwner -PassThru | Add-Member -MemberType ScriptProperty -Name 'Protocol' -Value { @@ -121,6 +123,12 @@ try Add-Member -MemberType ScriptMethod -Name 'Start' -Value { $script:mockMethodStartRan = $true } -PassThru | + Add-Member -MemberType ScriptMethod -Name 'Stop' -Value { + $script:mockMethodStopRan = $true + } -PassThru | + Add-Member -MemberType ScriptMethod -Name 'Disable' -Value { + $script:mockMethodDisableRan = $true + } -PassThru | Add-Member -MemberType ScriptMethod -Name 'Create' -Value { $script:mockMethodCreateRan = $true @@ -155,8 +163,9 @@ try $defaultParameters = @{ InstanceName = $mockInstanceName - ServerName = $mockServerName + ServerName = $mockServerName EndpointName = $mockEndpointName + EndpointType = $mockEndpointType } Describe 'DSC_SqlServerEndpoint\Get-TargetResource' -Tag 'Get' { @@ -224,7 +233,7 @@ try Context 'When endpoint exist but with wrong endpoint type' { It 'Should throw the correct error' { - { Get-TargetResource @testParameters } | Should -Throw ($script:localizedData.EndpointFoundButWrongType -f $testParameters.EndpointName) + { Get-TargetResource @testParameters } | Should -Throw ($script:localizedData.EndpointFoundButWrongType -f $testParameters.EndpointName, $mockOtherEndpointType, $mockEndpointType) } } @@ -305,6 +314,18 @@ try } } + Context 'When State is not in desired state' { + It 'Should return that desired state is absent' { + $testParameters.Add('Ensure', 'Present') + $testParameters.Add('State', 'Stopped') + + $result = Test-TargetResource @testParameters + $result | Should -Be $false + + Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope It + } + } + # Make sure the mock do return the correct endpoint listener port $mockDynamicEndpointListenerPort = $mockEndpointListenerPort @@ -566,6 +587,108 @@ try Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope It } + $script:mockMethodCreateRan = $false + $script:mockMethodStartRan = $false + $script:mockMethodAlterRan = $false + $script:mockMethodDropRan = $false + $script:mockMethodStopRan = $false + $script:mockMethodDisableRan = $false + + $mockDynamicEndpointState = 'Stopped' + + It 'Should call Start() method when State is not ''Started''' { + Mock -CommandName Get-TargetResource -MockWith { + return @{ + Ensure = 'Present' + Port = $mockEndpointListenerPort + IpAddress = $mockEndpointListenerIpAddress + State = 'Stopped' + } + } -Verifiable + + $testParameters.Add('Ensure', 'Present') + $testParameters.Add('State', 'Started') + + { Set-TargetResource @testParameters } | Should -Not -Throw + + $script:mockMethodCreateRan | Should -Be $false + $script:mockMethodStartRan | Should -Be $true + $script:mockMethodStopRan | Should -Be $false + $script:mockMethodAlterRan | Should -Be $false + $script:mockMethodDropRan | Should -Be $false + $script:mockMethodDisableRan | Should -Be $false + + Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope It + } + + $script:mockMethodCreateRan = $false + $script:mockMethodStartRan = $false + $script:mockMethodAlterRan = $false + $script:mockMethodDropRan = $false + $script:mockMethodStopRan = $false + $script:mockMethodDisableRan = $false + + $mockDynamicEndpointState = 'Running' + + It 'Should call Stop() method when State is not ''Stopped''' { + Mock -CommandName Get-TargetResource -MockWith { + return @{ + Ensure = 'Present' + Port = $mockEndpointListenerPort + IpAddress = $mockEndpointListenerIpAddress + State = 'Running' + } + } -Verifiable + + $testParameters.Add('Ensure', 'Present') + $testParameters.Add('State', 'Stopped') + + { Set-TargetResource @testParameters } | Should -Not -Throw + + $script:mockMethodCreateRan | Should -Be $false + $script:mockMethodStartRan | Should -Be $false + $script:mockMethodStopRan | Should -Be $true + $script:mockMethodAlterRan | Should -Be $false + $script:mockMethodDropRan | Should -Be $false + $script:mockMethodDisableRan | Should -Be $false + + Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope It + } + + $script:mockMethodCreateRan = $false + $script:mockMethodStartRan = $false + $script:mockMethodAlterRan = $false + $script:mockMethodDropRan = $false + $script:mockMethodStopRan = $false + $script:mockMethodDisableRan = $false + + $mockDynamicEndpointState = 'Running' + + It 'Should call Disable() method when State is not ''Disabled''' { + Mock -CommandName Get-TargetResource -MockWith { + return @{ + Ensure = 'Present' + Port = $mockEndpointListenerPort + IpAddress = $mockEndpointListenerIpAddress + State = 'Running' + } + } -Verifiable + + $testParameters.Add('Ensure', 'Present') + $testParameters.Add('State', 'Disabled') + + { Set-TargetResource @testParameters } | Should -Not -Throw + + $script:mockMethodCreateRan | Should -Be $false + $script:mockMethodStartRan | Should -Be $false + $script:mockMethodStopRan | Should -Be $false + $script:mockMethodAlterRan | Should -Be $false + $script:mockMethodDropRan | Should -Be $false + $script:mockMethodDisableRan | Should -Be $true + + Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope It + } + # Make sure the mock does not return the correct endpoint $mockDynamicEndpointName = $mockOtherEndpointName @@ -613,7 +736,7 @@ try } } - Context ' ' { + Context 'When the system is in the desired state' { # Make sure the mock do return the correct endpoint $mockDynamicEndpointName = $mockEndpointName $mockDynamicEndpointListenerPort = $mockEndpointListenerPort diff --git a/tests/Unit/DSC_SqlServerEndpointState.Tests.ps1 b/tests/Unit/DSC_SqlServerEndpointState.Tests.ps1 deleted file mode 100644 index 5b62ae7ba..000000000 --- a/tests/Unit/DSC_SqlServerEndpointState.Tests.ps1 +++ /dev/null @@ -1,354 +0,0 @@ -<# - .SYNOPSIS - Automated unit test for DSC_SqlServerEndpointState DSC resource. - - .NOTES - To run this script locally, please make sure to first run the bootstrap - script. Read more at - https://github.com/PowerShell/SqlServerDsc/blob/dev/CONTRIBUTING.md#bootstrap-script-assert-testenvironment -#> - -Import-Module -Name (Join-Path -Path $PSScriptRoot -ChildPath '..\TestHelpers\CommonTestHelper.psm1') - -if (-not (Test-BuildCategory -Type 'Unit')) -{ - return -} - -$script:dscModuleName = 'SqlServerDsc' -$script:dscResourceName = 'DSC_SqlServerEndpointState' - -function Invoke-TestSetup -{ - try - { - Import-Module -Name DscResource.Test -Force -ErrorAction 'Stop' - } - catch [System.IO.FileNotFoundException] - { - throw 'DscResource.Test module dependency not found. Please run ".\build.ps1 -Tasks build" first.' - } - - $script:testEnvironment = Initialize-TestEnvironment ` - -DSCModuleName $script:dscModuleName ` - -DSCResourceName $script:dscResourceName ` - -ResourceType 'Mof' ` - -TestType 'Unit' - - # Load the default SQL Module stub - Import-SQLModuleStub -} - -function Invoke-TestCleanup -{ - Restore-TestEnvironment -TestEnvironment $script:testEnvironment -} - -Invoke-TestSetup - -try -{ - InModuleScope $script:dscResourceName { - $mockNodeName = 'localhost' - $mockInstanceName = 'INSTANCE1' - $mockEndpointName = 'DefaultEndpointMirror' - $mockEndpointStateStarted = 'Started' - $mockEndpointStateStopped = 'Stopped' - - $mockOtherEndpointName = 'OtherEndpoint' - - $mockDynamicEndpointName = $mockEndpointName - $mockDynamicEndpointState = $mockEndpointStateStarted - - $mockConnectSql = { - return New-Object -TypeName Object | - Add-Member -MemberType ScriptProperty -Name 'Endpoints' -Value { - return @( - @{ - # TypeName: Microsoft.SqlServer.Management.Smo.Endpoint - $mockDynamicEndpointName = New-Object -TypeName Object | - Add-Member -MemberType NoteProperty -Name 'Name' -Value $mockDynamicEndpointName -PassThru | - Add-Member -MemberType NoteProperty -Name 'EndpointState' -Value $mockDynamicEndpointState -PassThru -Force - } - ) - } -PassThru -Force - } - - $defaultParameters = @{ - InstanceName = $mockInstanceName - ServerName = $mockNodeName - Name = $mockEndpointName - } - - #endregion Pester Test Initialization - - Describe 'DSC_SqlServerEndpointState\Get-TargetResource' -Tag Get { - BeforeEach { - $testParameters = $defaultParameters.Clone() - - Mock -CommandName Connect-SQL -MockWith $mockConnectSql -Verifiable - } - - $mockDynamicEndpointName = $mockEndpointName - - Context 'When the system is not in the desired state' { - $mockDynamicEndpointState = $mockEndpointStateStopped - - Context 'When desired state should be Started, but the current state is Stopped' { - It 'Should not return the state as Started' { - $result = Get-TargetResource @testParameters - $result.State | Should -Not -Be $mockEndpointStateStarted - } - - It 'Should return the same values as passed as parameters' { - $result = Get-TargetResource @testParameters - $result.ServerName | Should -Be $testParameters.ServerName - $result.InstanceName | Should -Be $testParameters.InstanceName - $result.Name | Should -Be $testParameters.Name - } - - It 'Should call the mock function Connect-SQL' { - $result = Get-TargetResource @testParameters - Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope It - } - } - - $mockDynamicEndpointState = $mockEndpointStateStarted - - Context 'When desired state should be Stopped, but the current state is Started' { - It 'Should not return the state as Stopped' { - $result = Get-TargetResource @testParameters - $result.State | Should -Not -Be $mockEndpointStateStopped - } - - It 'Should return the same values as passed as parameters' { - $result = Get-TargetResource @testParameters - $result.ServerName | Should -Be $testParameters.ServerName - $result.InstanceName | Should -Be $testParameters.InstanceName - $result.Name | Should -Be $testParameters.Name - } - - It 'Should call the mock function Connect-SQL' { - $result = Get-TargetResource @testParameters - Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope It - } - } - - $mockDynamicEndpointName = $mockOtherEndpointName - - Context 'When endpoint is missing' { - It 'Should throw the correct error message' { - { Get-TargetResource @testParameters } | Should -Throw ($script:localizedData.EndpointErrorVerifyExist -f $testParameters.Name) - - Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope It - } - } - - $mockDynamicEndpointName = $mockEndpointName - } - - Context 'When the system is in the desired state' { - $mockDynamicEndpointState = $mockEndpointStateStarted - - Context 'When desired state is Started' { - It 'Should return the state as Started' { - $result = Get-TargetResource @testParameters - $result.State | Should -Be $mockEndpointStateStarted - } - - It 'Should return the same values as passed as parameters' { - $result = Get-TargetResource @testParameters - $result.ServerName | Should -Be $testParameters.ServerName - $result.InstanceName | Should -Be $testParameters.InstanceName - $result.Name | Should -Be $testParameters.Name - } - - It 'Should call the mock function Connect-SQL' { - $result = Get-TargetResource @testParameters - Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope It - } - } - - $mockDynamicEndpointState = $mockEndpointStateStopped - - Context 'When desired state is Stopped' { - It 'Should return the state as Stopped' { - $result = Get-TargetResource @testParameters - $result.State | Should -Be $mockEndpointStateStopped - } - - It 'Should return the same values as passed as parameters' { - $result = Get-TargetResource @testParameters - $result.ServerName | Should -Be $testParameters.ServerName - $result.InstanceName | Should -Be $testParameters.InstanceName - $result.Name | Should -Be $testParameters.Name - } - - It 'Should call the mock function Connect-SQL' { - $result = Get-TargetResource @testParameters - Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope It - } - } - } - - Assert-VerifiableMock - } - - Describe 'DSC_SqlServerEndpointState\Test-TargetResource' -Tag Test { - BeforeEach { - $testParameters = $defaultParameters.Clone() - - Mock -CommandName Connect-SQL -MockWith $mockConnectSql -Verifiable - } - - Context 'When the system is not in the desired state' { - $mockDynamicEndpointState = $mockEndpointStateStopped - - Context 'When desired state should be Started, but the current state is Stopped' { - It 'Should return that desired state as absent' { - $testParameters.Add('State', $mockEndpointStateStarted) - - $result = Test-TargetResource @testParameters - $result | Should -Be $false - - Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope It - } - } - - $mockDynamicEndpointState = $mockEndpointStateStarted - - Context 'When desired state should be Stopped, but the current state is Started' { - It 'Should return that desired state as absent' { - $testParameters.Add('State', $mockEndpointStateStopped) - - $result = Test-TargetResource @testParameters - $result | Should -Be $false - - Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope It - } - } - } - - Context 'When the system is in the desired state' { - $mockDynamicEndpointState = $mockEndpointStateStarted - - Context 'When desired state should be Started, and the current state is Started' { - It 'Should return that desired state as absent' { - $testParameters.Add('State', $mockEndpointStateStarted) - - $result = Test-TargetResource @testParameters - $result | Should -Be $true - - Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope It - } - } - - $mockDynamicEndpointState = $mockEndpointStateStopped - - Context 'When desired state should be Stopped, and the current state is Stopped' { - It 'Should return that desired state as absent' { - $testParameters.Add('State', $mockEndpointStateStopped) - - $result = Test-TargetResource @testParameters - $result | Should -Be $true - - Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope It - } - } - - Context 'When Get-TargetResource returns nothing' { - It 'Should throw the correct error message' { - Mock -CommandName Get-TargetResource -MockWith { - return $null - } -Verifiable - - { Test-TargetResource @testParameters } | Should -Throw $script:localizedData.UnexpectedErrorFromGet - - Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 0 -Scope It - } - } - } - - Assert-VerifiableMock - } - - Describe 'DSC_SqlServerEndpointState\Set-TargetResource' -Tag Set { - BeforeEach { - $testParameters = $defaultParameters.Clone() - - Mock -CommandName Connect-SQL -MockWith $mockConnectSql -Verifiable - Mock Set-SqlHADREndpoint -Verifiable - } - - Context 'When the system is not in the desired state' { - $mockDynamicEndpointState = $mockEndpointStateStopped - - Context 'When desired state should be Started, but the current state is Stopped' { - It 'Should call the mock function Set-SqlHADREndpoint to set the state to Started' { - $testParameters.Add('State', $mockEndpointStateStarted) - - Set-TargetResource @testParameters - - Assert-MockCalled -CommandName Set-SqlHADREndpoint -Exactly -Times 1 -Scope It - } - } - - $mockDynamicEndpointState = $mockEndpointStateStarted - - Context 'When desired state should be Stopped, but the current state is Started' { - It 'Should call the mock function Set-SqlHADREndpoint to set the state to Stopped' { - $testParameters.Add('State', $mockEndpointStateStopped) - - Set-TargetResource @testParameters - - Assert-MockCalled -CommandName Set-SqlHADREndpoint -Exactly -Times 1 -Scope It - } - } - } - - Context 'When the system is in the desired state' { - $mockDynamicEndpointState = $mockEndpointStateStarted - - Context 'When desired state should be Started, and the current state is Started' { - It 'Should not call the mock function Set-SqlHADREndpoint' { - $testParameters.Add('State', $mockEndpointStateStarted) - - Set-TargetResource @testParameters - - Assert-MockCalled -CommandName Set-SqlHADREndpoint -Exactly -Times 0 -Scope It - } - } - - $mockDynamicEndpointState = $mockEndpointStateStopped - - Context 'When desired state should be Stopped, and the current state is Stopped' { - It 'Should not call the mock function Set-SqlHADREndpoint' { - $testParameters.Add('State', $mockEndpointStateStopped) - - Set-TargetResource @testParameters - - Assert-MockCalled -CommandName Set-SqlHADREndpoint -Exactly -Times 0 -Scope It - } - } - - Context 'When Get-TargetResource returns nothing' { - It 'Should throw the correct error message' { - Mock -CommandName Get-TargetResource -MockWith { - return $null - } -Verifiable - - { Set-TargetResource @testParameters } | Should -Throw $script:localizedData.UnexpectedErrorFromGet - - Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 0 -Scope It - } - } - } - - Assert-VerifiableMock - } - } -} -finally -{ - Invoke-TestCleanup -}