DSCResources/ArcGIS_DataStore/ArcGIS_DataStore.psm1
$modulePath = Join-Path -Path (Split-Path -Path (Split-Path -Path $PSScriptRoot -Parent) -Parent) -ChildPath 'Modules' # Import the ArcGIS Common Modules Import-Module -Name (Join-Path -Path $modulePath ` -ChildPath (Join-Path -Path 'ArcGIS.Common' ` -ChildPath 'ArcGIS.Common.psm1')) <# .SYNOPSIS Configures Datastore with the GIS server. - Can be a primary or secondary in case of Relational DataStore. - Can be 1 or upto n in case of a BDS. - TileCache - not sure. .PARAMETER Ensure Take the values Present or Absent. - "Present" ensures that DataStore is Configured if not. - "Absent" ensures that DataStore is unconfigured or derigestered with the GIS Server - Not Implemented). .PARAMETER Version Optional Version of DataStore to be configured .PARAMETER DatastoreMachineHostName Optional Host Name or IP of the Machine on which the DataStore has been installed and is to be configured. .PARAMETER ServerHostName HostName of the GIS Server for which you want to create and register a data store. .PARAMETER SiteAdministrator A MSFT_Credential Object - Primary Site Administrator to access the GIS Server. .PARAMETER ContentDirectory Path for the ArcGIS Data Store directory. This directory contains the data store files, plus the relational data store backup directory. .PARAMETER IsStandby Boolean to Indicate if the datastore (Relational only) being configured with a GIS Server is a Standby Server.(Only Supports 1 StandBy Server) .PARAMETER DataStoreTypes The type of data store to create on the machine.('Relational','SpatioTemporal','TileCache'). Value for this can be one or more. .PARAMETER EnableFailoverOnPrimaryStop Boolean to Indicate if failover Enabled when service on Primary machine is stopped. .PARAMETER IsTileCacheDataStoreClustered Boolean to Indicate if the Tile Cache Datastore is clustered or not. .PARAMETER IsObjectDataStoreClustered Boolean to Indicate if the Object store is clustered or not. .PARAMETER PITRState String to indicate if to enable or disable or do nothing with respect to Point In Time Recovery (Relational only). #> function Get-TargetResource { [CmdletBinding()] [OutputType([System.Collections.Hashtable])] param ( [parameter(Mandatory = $true)] [System.String] $Version, [parameter(Mandatory = $false)] [System.String] $DatastoreMachineHostName, [ValidateSet("Present","Absent")] [System.String] $Ensure, [parameter(Mandatory = $true)] [System.String] $ServerHostName, [parameter(Mandatory = $true)] [System.Management.Automation.PSCredential] $SiteAdministrator, [System.String] $ContentDirectory, [System.Boolean] $IsStandby, [System.Array] $DataStoreTypes, [System.Boolean] $IsTileCacheDataStoreClustered = $false, [System.Boolean] $IsObjectDataStoreClustered = $false, [System.Boolean] $EnableFailoverOnPrimaryStop = $false, [parameter(Mandatory = $False)] [ValidateSet("Enabled","Disabled")] $PITRState = "Disabled" ) $null } function Set-TargetResource { [CmdletBinding()] param ( [parameter(Mandatory = $true)] [System.String] $Version, [parameter(Mandatory = $false)] [System.String] $DatastoreMachineHostName, [parameter(Mandatory = $true)] [System.String] $ServerHostName, [ValidateSet("Present","Absent")] [System.String] $Ensure, [parameter(Mandatory = $true)] [System.Management.Automation.PSCredential] $SiteAdministrator, [System.String] $ContentDirectory, [System.Boolean] $IsStandby, [System.Array] $DataStoreTypes, [System.Boolean] $IsTileCacheDataStoreClustered = $false, [System.Boolean] $IsObjectDataStoreClustered = $false, [System.Boolean] $EnableFailoverOnPrimaryStop = $false, [parameter(Mandatory = $False)] [ValidateSet("Enabled","Disabled")] $PITRState = "Disabled" ) [System.Reflection.Assembly]::LoadWithPartialName("System.Web") | Out-Null if($Ensure -ieq 'Present') { $MachineFQDN = if($DatastoreMachineHostName){ Get-FQDN $DatastoreMachineHostName }else{ Get-FQDN $env:COMPUTERNAME } $Referer = "https://$($MachineFQDN):2443" $ServiceName = 'ArcGIS Data Store' $RegKey = Get-EsriRegistryKeyForService -ServiceName $ServiceName $DataStoreInstallDirectory = (Get-ItemProperty -Path $RegKey -ErrorAction Ignore).InstallDir.TrimEnd('\') $RestartRequired = $false $expectedHostIdentifierType = if($MachineFQDN -as [ipaddress]){ 'ip' }else{ 'hostname' } $hostidentifier = Get-ConfiguredHostIdentifier -InstallDir $DataStoreInstallDirectory $hostidentifierType = Get-ConfiguredHostIdentifierType -InstallDir $DataStoreInstallDirectory Write-Verbose "Current value of property hostidentifier is '$hostidentifier' and hostidentifierType is '$hostidentifierType'" if(($hostidentifier -ieq $MachineFQDN) -and ($hostidentifierType -ieq $expectedHostIdentifierType)) { Write-Verbose "Configured host identifier '$hostidentifier' matches expected value '$MachineFQDN' and host identifier type '$hostidentifierType' matches expected value '$expectedHostIdentifierType'" } else { Write-Verbose "Configured host identifier '$hostidentifier' does not match expected value '$MachineFQDN' or host identifier type '$hostidentifierType' does not match expected value '$expectedHostIdentifierType'. Setting it" if(Set-ConfiguredHostIdentifier -InstallDir $DataStoreInstallDirectory -HostIdentifier $MachineFQDN -HostIdentifierType $expectedHostIdentifierType) { # Need to restart the service to pick up the hostidentifier Write-Verbose "Hostidentifier.properties file was modified. Need to restart the '$ServiceName' service to pick up changes" $RestartRequired = $true } } $FailoverPropertyModified = $False $ExpectedFailoverEnabledString = 'false' $PropertiesFilePath = Join-Path $DataStoreInstallDirectory 'framework\etc\datastore.properties' $FailoverPropertyName = 'failover_on_primary_stop' if($DataStoreTypes -icontains "Relational"){ $FailoverEnabledString = Get-PropertyFromPropertiesFile -PropertiesFilePath $PropertiesFilePath -PropertyName $FailoverPropertyName Write-Verbose "Current value of property $FailoverPropertyName is $FailoverEnabledString" $IsFailoverEnabled = ($FailoverEnabledString -ieq 'true') $ExpectedFailoverEnabledString = if($EnableFailoverOnPrimaryStop){ 'true' }else{ 'false' } if($IsFailoverEnabled -ine $EnableFailoverOnPrimaryStop) { Write-Verbose "Property '$FailoverPropertyName' will be modified. Need to restart the '$ServiceName' service to pick up changes" $FailoverPropertyModified = $true $RestartRequired = $true } else { Write-Verbose "Property value '$FailoverEnabledString' for '$FailoverPropertyName' matches expected value of '$($ExpectedFailoverEnabledString)'" } } if($RestartRequired){ Write-Verbose "Stop Service '$ServiceName' before applying property change" Stop-Service -Name $ServiceName -Force Write-Verbose 'Stopping the service' Wait-ForServiceToReachDesiredState -ServiceName $ServiceName -DesiredState 'Stopped' Write-Verbose 'Stopped the service' if($FailoverPropertyModified -and ($DataStoreTypes -icontains "Relational")){ Write-Verbose "Property '$FailoverPropertyName' will be changed to $ExpectedFailoverEnabledString in 'datastore.properties' file" Set-PropertyFromPropertiesFile -PropertiesFilePath $PropertiesFilePath -PropertyName $FailoverPropertyName -PropertyValue $ExpectedFailoverEnabledString -Verbose Write-Verbose "datastore.properties file was modified." } Write-Verbose "Restarting Service '$ServiceName' to pick up property change" Start-Service $ServiceName Wait-ForServiceToReachDesiredState -ServiceName $ServiceName -DesiredState 'Running' Write-Verbose "Restarted Service '$ServiceName'" Wait-ForUrl -Url "https://$($MachineFQDN):2443/arcgis/datastoreadmin/configure?f=json" -MaxWaitTimeInSeconds 180 -SleepTimeInSeconds 5 -HttpMethod 'GET' -Verbose }else { Write-Verbose "Properties are up to date. No need to restart the 'ArcGIS Data Store' Service" } $ServerFQDN = Get-FQDN $ServerHostName $ServerUrl = "https://$($ServerFQDN):6443" Wait-ForUrl -Url "$ServerUrl/arcgis/admin" -MaxWaitTimeInSeconds 90 -SleepTimeInSeconds 5 -Verbose $token = Get-ServerToken -ServerEndPoint $ServerUrl -ServerSiteName 'arcgis' -Credential $SiteAdministrator -Referer $Referer if(($DataStoreTypes -icontains "Relational") -or ($DataStoreTypes -icontains "TileCache")){ Write-Verbose "Ensure the Publishing GP Service (Tool) is started on Server" $PublishingToolsPath = 'System/PublishingTools.GPServer' $Attempts = 1 $MaxAttempts = 5 $SleepTimeInSeconds = 20 while ($true) { Write-Verbose "Checking state of Service '$PublishingToolsPath'. Attempt # $Attempts" $serviceStatus = Get-ServiceStatus -ServerURL $ServerUrl -Token $token.token -Referer $Referer -ServicePath $PublishingToolsPath Write-Verbose "Service Status :- $serviceStatus" if($serviceStatus.configuredState -ieq 'STARTED' -and $serviceStatus.realTimeState -ieq 'STARTED'){ Write-Verbose "State of Service '$PublishingToolsPath' is STARTED" break }else{ if(($serviceStatus.configuredState -ieq 'STARTED' -or $serviceStatus.realTimeState -ine 'STARTED') -or ($serviceStatus.configuredState -ine 'STARTED' -or $serviceStatus.realTimeState -ieq 'STARTED')){ Write-Verbose "Waiting $SleepTimeInSeconds seconds for Service '$PublishingToolsPath' to be started" Start-Sleep -Seconds $SleepTimeInSeconds }else{ Write-Verbose "Trying to Start Service $PublishingToolsPath" Start-ServerService -ServerURL $ServerUrl -Token $token.token -Referer $Referer -ServicePath $PublishingToolsPath Start-Sleep -Seconds $SleepTimeInSeconds } } $serviceStatus = Get-ServiceStatus -ServerURL $ServerUrl -Token $token.token -Referer $Referer -ServicePath $PublishingToolsPath if($serviceStatus.configuredState -ieq 'STARTED' -and $serviceStatus.realTimeState -ieq 'STARTED'){ Write-Verbose "State of Service '$PublishingToolsPath' is STARTED. Service Status :- $serviceStatus" break }else{ if($Attempts -le $MaxAttempts){ $Attempts += 1 Write-Verbose "Waiting $SleepTimeInSeconds seconds. Current Service Status :- $serviceStatus" Start-Sleep -Seconds $SleepTimeInSeconds }else{ Write-Verbose "Unable to get $PublishingToolsPath started successfully. Service Status :- $serviceStatus" break } } } } $DataStoreAdminEndpoint = 'https://localhost:2443/arcgis/datastoreadmin' $DatastoresToRegisterOrConfigure = Get-DataStoreTypesToRegisterOrConfigure -ServerURL $ServerUrl -Token $token.token -Referer $Referer ` -DataStoreTypes $DataStoreTypes -MachineFQDN $MachineFQDN ` -DataStoreAdminEndpoint $DataStoreAdminEndpoint -ServerSiteAdminCredential $SiteAdministrator ` -IsTileCacheDataStoreClustered $IsTileCacheDataStoreClustered ` -IsObjectDataStoreClustered $IsObjectDataStoreClustered -DataStoreContentDirectory $ContentDirectory #Check if the TileCache mode is correct, only for 10.8.1 and above if($DatastoresToRegisterOrConfigure.Count -gt 0){ $DatastoresToRegisterOrConfigureString = ($DatastoresToRegisterOrConfigure -join ',') Write-Verbose "Registering or configuring datastores $DatastoresToRegisterOrConfigureString" Invoke-RegisterOrConfigureDataStore -DataStoreAdminEndpoint $DataStoreAdminEndpoint -ServerSiteAdminCredential $SiteAdministrator ` -ServerUrl $ServerUrl -DataStoreContentDirectory $ContentDirectory -ServerAdminUrl "$ServerUrl/arcgis/admin" ` -Token $token.token -Referer $Referer -MachineFQDN $MachineFQDN -DataStoreTypes $DataStoreTypes ` -IsTileCacheDataStoreClustered $IsTileCacheDataStoreClustered -DataStoreInstallDirectory $DataStoreInstallDirectory ` -IsObjectDataStoreClustered $IsObjectDataStoreClustered } if($DataStoreTypes -icontains "SpatioTemporal"){ Write-Verbose "Checking if the Spatiotemporal Big Data Store has started." if(-not(Test-SpatiotemporalBigDataStoreStarted -ServerURL $ServerUrl -Token $token.token -Referer $Referer -MachineFQDN $MachineFQDN)) { Write-Verbose "Starting the Spatiotemporal Big Data Store." Start-SpatiotemporalBigDataStore -ServerURL $ServerUrl -Token $token.token -Referer $Referer -MachineFQDN $MachineFQDN $TestBDSStatus = Test-SpatiotemporalBigDataStoreStarted -ServerURL $ServerUrl -Token $token.token -Referer $Referer -MachineFQDN $MachineFQDN Write-Verbose "Just Checking:- $($TestBDSStatus)" }else { Write-Verbose "The Spatiotemporal Big Data Store is already started." } } if($DataStoreTypes -icontains "Relational"){ $CurrPITRState = Get-PITRState -DataStoreAdminEndpoint $DataStoreAdminEndpoint -Referer $Referer -Verbose Write-Verbose "Current PITR state is $CurrPITRState. Requested $PITRState" if($PITRState -ine $CurrPITRState) { Set-PITRState -PITRState $PITRState -DataStoreAdminEndpoint $DataStoreAdminEndpoint -Referer $Referer -Verbose } } }elseif($Ensure -ieq 'Absent') { throw "ArcGIS_DataStore Deregister Method not implemented!" } } function Test-TargetResource { [CmdletBinding()] [OutputType([System.Boolean])] param ( [parameter(Mandatory = $true)] [System.String] $Version, [parameter(Mandatory = $false)] [System.String] $DatastoreMachineHostName, [parameter(Mandatory = $true)] [System.String] $ServerHostName, [ValidateSet("Present","Absent")] [System.String] $Ensure, [parameter(Mandatory = $true)] [System.Management.Automation.PSCredential] $SiteAdministrator, [System.String] $ContentDirectory, [System.Boolean] $IsStandby, [System.Array] $DataStoreTypes, [System.Boolean] $IsTileCacheDataStoreClustered = $false, [System.Boolean] $IsObjectDataStoreClustered = $false, [System.Boolean] $EnableFailoverOnPrimaryStop = $false, [parameter(Mandatory = $False)] [ValidateSet("Enabled","Disabled")] $PITRState = "Disabled" ) [System.Reflection.Assembly]::LoadWithPartialName("System.Web") | Out-Null $result = $true $MachineFQDN = if($DatastoreMachineHostName){ Get-FQDN $DatastoreMachineHostName }else{ Get-FQDN $env:COMPUTERNAME } $Referer = "https://$($MachineFQDN):2443" $ServiceName = 'ArcGIS Data Store' $RegKey = Get-EsriRegistryKeyForService -ServiceName $ServiceName $DataStoreInstallDirectory = (Get-ItemProperty -Path $RegKey -ErrorAction Ignore).InstallDir.TrimEnd('\') if($DataStoreTypes -icontains "Relational"){ $PropertiesFilePath = Join-Path $DataStoreInstallDirectory 'framework\etc\datastore.properties' $FailoverPropertyName = 'failover_on_primary_stop' $FailoverEnabledString = Get-PropertyFromPropertiesFile -PropertiesFilePath $PropertiesFilePath -PropertyName $FailoverPropertyName Write-Verbose "Current value of property $FailoverPropertyName is $FailoverEnabledString" $IsFailoverEnabled = ($FailoverEnabledString -ieq 'true') $ExpectedFailoverEnabledString = if($EnableFailoverOnPrimaryStop){ 'true' }else{ 'false' } if($IsFailoverEnabled -ine $EnableFailoverOnPrimaryStop){ $result = $False Write-Verbose "Property Value for '$FailoverPropertyName' is not set to expected value '$ExpectedFailoverEnabledString'" } else { Write-Verbose "Property value '$FailoverEnabledString' for '$FailoverPropertyName' matches expected value of '$ExpectedFailoverEnabledString'" } } if($result) { $expectedHostIdentifierType = if($MachineFQDN -as [ipaddress]){ 'ip' }else{ 'hostname' } $hostidentifier = Get-ConfiguredHostIdentifier -InstallDir $DataStoreInstallDirectory $hostidentifierType = Get-ConfiguredHostIdentifierType -InstallDir $DataStoreInstallDirectory Write-Verbose "Current value of property hostidentifier is '$hostidentifier' and hostidentifierType is '$hostidentifierType'" if(($hostidentifier -ieq $MachineFQDN) -and ($hostidentifierType -ieq $expectedHostIdentifierType)) { Write-Verbose "Configured host identifier '$hostidentifier' matches expected value '$MachineFQDN' and host identifier type '$hostidentifierType' matches expected value '$expectedHostIdentifierType'" }else { Write-Verbose "Configured host identifier '$hostidentifier' does not match expected value '$MachineFQDN' or host identifier type '$hostidentifierType' does not match expected value '$expectedHostIdentifierType'. Setting it" $result = $false } } $ServerFQDN = Get-FQDN $ServerHostName $ServerUrl = "https://$($ServerFQDN):6443" if($result) { Wait-ForUrl -Url "$ServerUrl/arcgis/admin" -MaxWaitTimeInSeconds 90 -SleepTimeInSeconds 5 -Verbose $token = Get-ServerToken -ServerEndPoint $ServerUrl -ServerSiteName 'arcgis' -Credential $SiteAdministrator -Referer $Referer $DataStoreAdminEndpoint = 'https://localhost:2443/arcgis/datastoreadmin' $DatastoresToRegisterOrConfigure = Get-DataStoreTypesToRegisterOrConfigure -ServerURL $ServerUrl -Token $token.token -Referer $Referer ` -DataStoreTypes $DataStoreTypes -MachineFQDN $MachineFQDN ` -DataStoreAdminEndpoint $DataStoreAdminEndpoint -ServerSiteAdminCredential $SiteAdministrator ` -IsTileCacheDataStoreClustered $IsTileCacheDataStoreClustered ` -IsObjectDataStoreClustered $IsObjectDataStoreClustered -DataStoreContentDirectory $ContentDirectory if($DatastoresToRegisterOrConfigure.Count -gt 0){ $result = $false }else{ if(($DataStoreTypes -icontains "SpatioTemporal") -and -not($DatastoresToRegisterOrConfigure -icontains "SpatioTemporal")){ $resultSpatioTemporal = Test-SpatiotemporalBigDataStoreStarted -ServerURL $ServerUrl -Token $token.token -Referer $Referer -MachineFQDN $MachineFQDN -Verbose if($resultSpatioTemporal) { Write-Verbose 'Big data store is started' }else { $result = $false Write-Verbose 'Big data store is not started' } } } } if($result) { if(($DataStoreTypes -icontains "Relational")) { $CurrPITRState = Get-PITRState -DataStoreAdminEndpoint $DataStoreAdminEndpoint -Referer $Referer -Verbose Write-Verbose "Current PITR state is $CurrPITRState" if($PITRState -ine $CurrPITRState){ Write-Verbose "Current PITR state does not match requested status $PITRState" $result = $false } } } if($Ensure -ieq 'Present') { $result }elseif($Ensure -ieq 'Absent') { -not($result) } } function Invoke-RegisterOrConfigureDataStore { [CmdletBinding()] param( [System.String] $DataStoreAdminEndpoint, [System.Management.Automation.PSCredential] $ServerSiteAdminCredential, [System.String] $ServerUrl, [System.String] $DataStoreContentDirectory, [System.Int32] $MaxAttempts = 5, [System.String] $ServerAdminUrl, [System.String] $Token, [System.String] $Referer, [System.String] $MachineFQDN, [System.Array] $DataStoreTypes, [System.Boolean] $IsTileCacheDataStoreClustered, [System.Boolean] $IsObjectDataStoreClustered, [System.String] $DataStoreInstallDirectory ) Write-Verbose "Version of DataStore is $Version" $VersionArray = $Version.Split('.') $ServerSiteUrl = $ServerURL.TrimEnd('/') + '/arcgis' if(!$DataStoreContentDirectory) { throw "Must Specify DataStoreContentDirectory" } $featuresJson = @{} if($DataStoreTypes) { foreach($dstype in $DataStoreTypes) { if($dstype -ieq 'Relational') { $featuresJson.add("feature.egdb",$true) Write-Verbose "Adding Relational as a data store type" } elseif($dstype -ieq 'TileCache') { $featuresJson.add("feature.nosqldb",$true) Write-Verbose "Adding Tile Cache as a data store type" } elseif($dstype -ieq 'SpatioTemporal') { $featuresJson.add("feature.bigdata",$true) Write-Verbose "Adding SpatioTemporal as a data store type" } elseif($dstype -ieq 'GraphStore') { $featuresJson.add("feature.graphstore",$true) Write-Verbose "Adding GraphStore as a data store type" } elseif($dstype -ieq 'ObjectStore') { $featuresJson.add("feature.ozobjectstore",$true) Write-Verbose "Adding ObjectStore as a data store type" } } } $dsSettings = @{ directory = $DataStoreContentDirectory.Replace('\\', '\').Replace('\\', '\'); features = $featuresJson; } if($DataStoreTypes -icontains "TileCache" -and ($VersionArray[0] -eq 11 -or ($VersionArray[0] -eq 10 -and (($VersionArray[1] -gt 8) -or ($Version -ieq "10.8.1")))) -and $IsTileCacheDataStoreClustered){ $dsSettings.add("storeSetting.tileCache",@{deploymentMode="cluster"}) $dsSettings.add("referer",$Referer) } if($DataStoreTypes -icontains "ObjectStore" -and ($VersionArray[0] -eq 11) -and $IsObjectDataStoreClustered){ $dsSettings.add("storeSetting.objectStore",@{deploymentMode="cluster"}) $dsSettings.add("referer",$Referer) } $WebParams = @{ username = $ServerSiteAdminCredential.UserName password = $ServerSiteAdminCredential.GetNetworkCredential().Password serverURL = $ServerSiteUrl dsSettings = (ConvertTo-Json $dsSettings -Compress) f = 'json' } $DataStoreConfigureUrl = $DataStoreAdminEndpoint.TrimEnd('/') + '/configure' Write-Verbose "Register DataStore at $DataStoreAdminEndpoint with DataStore Content directory at $DataStoreContentDirectory for server $ServerSiteUrl" [bool]$Done = $false [System.Int32]$NumAttempts = 1 while(-not($Done)) { Write-Verbose "Register DataStore Attempt $NumAttempts" [bool]$failed = $false $response = $null try { $DatastoresToRegisterFlag = $true if($NumAttempts -gt 1) { Write-Verbose "Checking if datastore is registered" $DatastoresToRegisterOrConfigure = Get-DataStoreTypesToRegisterOrConfigure -ServerURL $ServerUrl -Token $Token ` -Referer $Referer -DataStoreTypes $DataStoreTypes -MachineFQDN $MachineFQDN ` -DataStoreAdminEndpoint $DataStoreAdminEndpoint -ServerSiteAdminCredential $ServerSiteAdminCredential ` -IsTileCacheDataStoreClustered $IsTileCacheDataStoreClustered ` -IsObjectDataStoreClustered $IsObjectDataStoreClustered -DataStoreContentDirectory $DataStoreContentDirectory $DatastoresToRegisterFlag = ($DatastoresToRegisterOrConfigure.Count -gt 0) } if($DatastoresToRegisterFlag) { Write-Verbose "Register DataStore on Machine $MachineFQDN" $response = Invoke-ArcGISWebRequest -Url $DataStoreConfigureUrl -HttpFormParameters $WebParams -Referer $Referer -TimeOutSec 600 -Verbose if($response.error) { Write-Verbose "Error Response - $($response.error | ConvertTo-Json)" throw [string]::Format("ERROR: failed. {0}" , $response.error.message) } } } catch { Write-Verbose "[WARNING]:- $_" $failed = $true } if($failed -or $response.error){ if($NumAttempts -ge $MaxAttempts) { throw "Register Data Store Failed after multiple attempts. $($response.error)" }else{ Write-Verbose "Attempt [$NumAttempts] Failed. Retrying after 45 seconds" Start-Sleep -Seconds 45 } }else { $Done = $true } $NumAttempts++ } # If we switch from primary standby to cluster mode at 10.8.1, add machine fails with @{code=500; message=Attempt to configure data # store failed.\\nCaused by: This machine cannot be added to the 'tile cache' data store because it cannot access backup location(s) # '[C:/arcgis/datastore/content/backup/tilecache/]' registered with that data store. Ensure that the listed locations are shared # directories and that the ArcGIS Data Store account has permissions to them.; details=} # Includes a fix where we unregister the default backup location for 10.8.1 after the switch when only 1 machine is present if($DataStoreTypes -icontains "TileCache" -and ($Version -ieq "10.8.1") -and $IsTileCacheDataStoreClustered){ if((Get-NumberOfTileCacheDatastoreMachines -ServerURL $ServerUrl -Token $Token -Referer $Referer) -eq 1){ $TilecacheBackupLocations = Get-DataStoreBackupLocation -DataStoreType "TileCache" -DataStoreInstallDirectory $DataStoreInstallDirectory -Verbose $DefaultBackup = ($TilecacheBackupLocations | Where-Object { $_.IsDefault -ieq $true } | Select-Object -First 1 ) if(($null -ne $DefaultBackup) -and -not([string]::IsNullOrEmpty($DefaultBackup.Location))){ $PathInfo=[System.Uri]$DefaultBackup.Location; if(-not($PathInfo.IsUnc)){ Write-Verbose "Unregistering backup location $($DefaultBackup.Location)" Invoke-DataStoreConfigureBackupLocationTool -BackupLocationString "type=$($DefaultBackup.Type);name=$($DefaultBackup.Name)" ` -DataStoreInstallDirectory $DataStoreInstallDirectory ` -DataStoreType "TileCache" -OperationType "unregister" -Verbose Write-Verbose "Unregister of backup location $($DefaultBackup.Location) successful" } } } } } function Get-DataStoreTypesToRegisterOrConfigure { [CmdletBinding()] param( [System.String] $ServerURL, [System.String] $DataStoreAdminEndpoint, [System.Management.Automation.PSCredential] $ServerSiteAdminCredential, [System.String] $Token, [System.String] $Referer, [System.String] $Type, [System.Array] $DataStoreTypes, [System.String] $MachineFQDN, [System.Boolean] $IsTileCacheDataStoreClustered, [System.Boolean] $IsObjectDataStoreClustered, [System.String] $DataStoreContentDirectory ) $DataStoreInfo = Get-DataStoreInfo -DataStoreAdminEndpoint $DataStoreAdminEndpoint -ServerSiteAdminCredential $ServerSiteAdminCredential ` -ServerSiteUrl "$ServerURL/arcgis" -Referer $Referer $DatastoresToRegister = @() foreach($dstype in $DataStoreTypes){ Write-Verbose "Checking if $dstype Datastore is registered" $dsTestResult = $false if($dstype -ieq 'Relational'){ $dsTestResult = $DataStoreInfo.relational.registered }elseif($dstype -ieq 'TileCache') { $dsTestResult = $DataStoreInfo.tileCache.registered }elseif($dstype -ieq 'SpatioTemporal'){ $dsTestResult = $DataStoreInfo.spatioTemporal.registered }elseif($dstype -ieq 'GraphStore'){ $dsTestResult = $DataStoreInfo.graphStore.registered }elseif($dstype -ieq 'ObjectStore'){ $ObjectStoreConfigFile = Join-Path $DataStoreContentDirectory "etc\ozobjectstore-config.json" if(Test-Path $ObjectStoreConfigFile){ $ObjectConfig = (Get-Content $ObjectStoreConfigFile | ConvertFrom-Json) $dsTestResult = ($ObjectConfig.'datastore.registered') -ieq $True }else{ $dsTestResult = $False } } $serverTestResult = Test-DataStoreRegistered -ServerURL $ServerUrl -Token $Token -Referer $Referer -Type "$dstype" -MachineFQDN $MachineFQDN -IsTileCacheDataStoreClustered $IsTileCacheDataStoreClustered -IsObjectDataStoreClustered $IsObjectDataStoreClustered -Verbose if($dsTestResult -and $serverTestResult){ Write-Verbose "The machine with FQDN '$MachineFQDN' already participates in a '$dstype' data store" }else{ $DatastoresToRegister += $dstype Write-Verbose "The machine with FQDN '$MachineFQDN' does NOT participates in a registered '$dstype' data store" } } $DatastoresToRegister } function Get-DataStoreInfo { [CmdletBinding()] param( [System.String] $DataStoreAdminEndpoint, [System.Management.Automation.PSCredential] $ServerSiteAdminCredential, [System.String] $ServerSiteUrl, [System.String] $Referer ) $WebParams = @{ f = 'json' username = $ServerSiteAdminCredential.UserName password = $ServerSiteAdminCredential.GetNetworkCredential().Password serverURL = $ServerSiteUrl dsSettings = '{"features":{"feature.egdb":true,"feature.nosqldb":true,"feature.bigdata":true,"feature.graphstore":true,"feature.ozobjectstore":true}}' getConfigureInfo = 'true' } $DataStoreConfigureUrl = $DataStoreAdminEndpoint.TrimEnd('/') + '/configure' Wait-ForUrl -Url "$($DataStoreConfigureUrl)?f=json" -MaxWaitTimeInSeconds 180 -SleepTimeInSeconds 5 -HttpMethod 'GET' -Verbose Invoke-ArcGISWebRequest -Url $DataStoreConfigureUrl -HttpFormParameters $WebParams -Referer $Referer -HttpMethod 'POST' -Verbose } function Test-DataStoreRegistered { [CmdletBinding()] param( [System.String] $ServerURL, [System.String] $Token, [System.String] $Referer, [System.String] $Type, [System.String] $MachineFQDN, [System.Boolean] $IsTileCacheDataStoreClustered, [System.Boolean] $IsObjectDataStoreClustered ) $result = $false if($Type -like "SpatioTemporal" -or $Type -like "TileCache" -or $Type -like "GraphStore"){ $DBType ='nosql' } elseif($Type -like "ObjectStore"){ $DBType = "cloudStore" } else{ $DBType ='egdb' } $DataItemsUrl = $ServerURL.TrimEnd('/') + '/arcgis/admin/data/findItems' $response = Invoke-ArcGISWebRequest -Url $DataItemsUrl -HttpFormParameters @{ f = 'json'; token = $Token; types = $DBType } -Referer $Referer -Verbose $registered= $($response.items | Where-Object { $_.provider -ieq 'ArcGIS Data Store' } | Measure-Object).Count -gt 0 if($DBType -ieq 'nosql' -or $DBType -ieq 'cloudStore'){ $registered = $($response.items | Where-Object { ($_.provider -ieq 'ArcGIS Data Store') -and ($_.info.dsFeature -ieq $Type) } | Measure-Object).Count -gt 0 } if($registered){ $DB = $($response.items | Where-Object { $_.provider -ieq 'ArcGIS Data Store' } | Select-Object -First 1) if($DBType -ieq 'nosql' -or $DBType -ieq 'cloudStore'){ $DB = ($response.items | Where-Object { ($_.provider -ieq 'ArcGIS Data Store') -and ($_.info.dsFeature -ieq $Type) } | Select-Object -First 1) } $MachinesInDataStoreUrl = $ServerURL.TrimEnd('/') + '/arcgis/admin/data/items' + $DB.path + '/machines' $response = Invoke-ArcGISWebRequest -Url $MachinesInDataStoreUrl -HttpFormParameters @{ f = 'json'; token = $Token } -Referer $Referer -Verbose $result = ($response.machines | Where-Object { $_.name -ieq $MachineFQDN } | Measure-Object).Count -gt 0 if($result -and ($Type -like "TileCache")){ $VersionArray = $DB.info.storeRelease.Split(".") if(($VersionArray[0] -eq 11) -or ($VersionArray[0] -eq 10 -and $VersionArray[1] -gt 8) -or ($DB.info.storeRelease -ieq "10.8.1")){ $tcArchTerminology = if(($VersionArray[0] -eq 11) -or ($VersionArray[0] -eq 10 -and $VersionArray[1] -gt 8)){ "primaryStandby" }else{ "masterSlave" } if($IsTileCacheDataStoreClustered){ if($DB.info.architecture -ieq $tcArchTerminology){ $result = $false }else{ Write-Verbose "Tilecache Architecture is already set to Cluster." } }else{ if($DB.info.architecture -ieq $tcArchTerminology){ Write-Verbose "Tilecache Architecture is already set to $($tcArchTerminology)." }else{ #$result = $false Write-Verbose "Tilecache Architecture is set to Cluster. Cannot be converted to $($tcArchTerminology)." } } } } if($result -and ($Type -like "ObjectStore")){ if($IsObjectDataStoreClustered){ if($DB.info.deployMode -ieq "singleInstance"){ throw "[ERROR] Object store architecture is already set to Single Instance. Cannot be converted to cluster." }else{ Write-Verbose "Object store architecture is already set to Cluster." } }else{ if($DB.info.deployMode -ieq "singleInstance"){ Write-Verbose "Object store Architecture is already set to Single Instance." }else{ #$result = $false throw "[ERROR] Object store Architecture is set to Cluster. Cannot be converted to Single Instance." } } } } $result } function Get-NumberOfTileCacheDatastoreMachines { [CmdletBinding()] param( [System.String] $ServerURL, [System.String] $Token, [System.String] $Referer ) $DataItemsUrl = $ServerURL.TrimEnd('/') + '/arcgis/admin/data/findItems' $response = Invoke-ArcGISWebRequest -Url $DataItemsUrl -HttpFormParameters @{ f = 'json'; token = $Token; types = 'nosql' } -Referer $Referer $DB = ($response.items | Where-Object { ($_.provider -ieq 'ArcGIS Data Store') -and ($_.info.dsFeature -ieq "TileCache") } | Select-Object -First 1) $MachinesInDataStoreUrl = $ServerURL.TrimEnd('/') + '/arcgis/admin/data/items' + $DB.path + '/machines' $response = Invoke-ArcGISWebRequest -Url $MachinesInDataStoreUrl -HttpFormParameters @{ f = 'json'; token = $Token } -Referer $Referer ($response.machines | Measure-Object).Count } function Start-ServerService { [CmdletBinding()] param( [System.String] $ServerURL, [System.String] $Token, [System.String] $Referer, [System.String] $ServicePath ) $ServiceStartOperationUrl = $ServerURL.TrimEnd('/') + '/arcgis/admin/services/' + $ServicePath.Trim('/') + '/start' Invoke-ArcGISWebRequest -Url $ServiceStartOperationUrl -HttpFormParameters @{ f = 'json'; token = $Token } -Referer $Referer -HttpMethod 'POST' -Verbose } function Stop-ServerService { [CmdletBinding()] param( [System.String] $ServerURL, [System.String] $Token, [System.String] $Referer, [System.String] $ServicePath ) $ServiceStopOperationUrl = $ServerURL.TrimEnd('/') + '/arcgis/admin/services/' + $ServicePath.Trim('/') + '/stop' Invoke-ArcGISWebRequest -Url $ServiceStopOperationUrl -HttpFormParameters @{ f = 'json'; token = $Token } -Referer $Referer } function Get-ServiceStatus { [CmdletBinding()] param( [System.String] $ServerURL, [System.String] $Token, [System.String] $Referer, [System.String] $ServicePath ) $ServiceStatusUrl = $ServerURL.TrimEnd('/') + '/arcgis/admin/services/' + $ServicePath.Trim('/') + '/status' Invoke-ArcGISWebRequest -Url $ServiceStatusUrl -HttpFormParameters @{ f = 'json'; token = $Token } -Referer $Referer } function Test-SpatiotemporalBigDataStoreStarted { [CmdletBinding()] [OutputType([System.Boolean])] param( [System.String] $ServerURL, [System.String] $Token, [System.String] $Referer, [System.String] $MachineFQDN ) $DataItemsUrl = $ServerURL.TrimEnd('/') + '/arcgis/admin/data/findItems' $response = Invoke-ArcGISWebRequest -Url $DataItemsUrl -HttpFormParameters @{ f = 'json'; token = $Token; types = 'nosql' } -Referer $Referer $dataStorePath = $null if($response.items -and $response.items.length -gt 0) { $done = $false $i = 0 while(-not($done) -and ($i -lt $response.items.length)) { $dsType = $response.items[$i].info.dsFeature if($dsType -ieq "spatioTemporal") { Write-Verbose "SpatioTemporal DataStore $dataStorePath found" $dataStorePath = $response.items[$i].path $done = $true } $i = $i + 1 } } else { throw "Spatiotemporal Big DataStore not found in arcgis data items" } Write-Verbose "Data Store Path:- $dataStorePath" $Url = $ServerURL.TrimEnd('/') + '/arcgis/admin/data/items' + "$dataStorePath/machines/$MachineFQDN/validate/" Write-Verbose $Url try { $response = Invoke-ArcGISWebRequest -Url $Url -HttpFormParameters @{ f = 'json'; token = $Token } -Referer $Referer -HttpMethod 'POST' $n = $response.nodes | Where-Object {($_.name -ieq (Resolve-DnsName -Type ANY $env:ComputerName).IPAddress) -or ($_.name -ieq $MachineFQDN)} Write-Verbose "Machine Ip --> $($n.name)" $n -and $response.isHealthy -ieq 'True' } catch { Write-Verbose "[WARNING] Attempt to check if Spatiotemporal Big DataStore is started returned error:- $_" $false } } function Start-SpatiotemporalBigDataStore { [CmdletBinding()] param( [System.String] $ServerURL, [System.String] $Token, [System.String] $Referer, [System.String] $MachineFQDN ) $DataItemsUrl = $ServerURL.TrimEnd('/') + '/arcgis/admin/data/findItems' $response = Invoke-ArcGISWebRequest -Url $DataItemsUrl -HttpFormParameters @{ f = 'json'; token = $Token; types = 'nosql' } -Referer $Referer $dataStorePath = $null if($response.items -and $response.items.length -gt 0) { $dataStorePath = $response.items[0].path } else { throw "Spatiotemporal Big DataStore not found in arcgis data items" } Write-Verbose "Data Store Path:- $dataStorePath" $Url = $ServerURL.TrimEnd('/') + '/arcgis/admin/data/items' + "$dataStorePath/machines/$MachineFQDN/start/" Invoke-ArcGISWebRequest -Url $Url -HttpFormParameters @{ f = 'json'; token = $Token } -Referer $Referer -HttpMethod 'POST' -Verbose } function Get-PITRState { [CmdletBinding()] param( [System.String] $DataStoreAdminEndpoint, [System.String] $Referer ) $result = $null $WebParams = @{ f = 'json' } $DataStoreConfigurePITRUrl = $DataStoreAdminEndpoint.TrimEnd('/') + '/configurePITR' Wait-ForUrl -Url "$($DataStoreConfigurePITRUrl)?f=json" -MaxWaitTimeInSeconds 180 -SleepTimeInSeconds 5 -HttpMethod 'GET' -Verbose $Response = Invoke-ArcGISWebRequest -Url $DataStoreConfigurePITRUrl -HttpFormParameters $WebParams -Referer $Referer -TimeOutSec 600 -HttpMethod "GET" -Verbose if($Response.status -ieq "success"){ if($Response.pitrEnabled -ieq $True){ $result = 'Enabled' }else { $result = 'Disabled' } }else{ throw "[ERROR] Configure PITR web request returned an error." } $result } function Set-PITRState { [CmdletBinding()] param( [System.String] $DataStoreAdminEndpoint, [System.String] $Referer, [System.String] $PITRState ) $WebParams = @{ f = 'json' "enable-pitr" = if ($PITRState -ieq 'Enabled') { "true" }else{ "false" } } $DataStoreConfigurePITRUrl = $DataStoreAdminEndpoint.TrimEnd('/') + '/configurePITR' Wait-ForUrl -Url "$($DataStoreConfigurePITRUrl)?f=json" -MaxWaitTimeInSeconds 180 -SleepTimeInSeconds 5 -HttpMethod 'GET' -Verbose $Response = Invoke-ArcGISWebRequest -Url $DataStoreConfigurePITRUrl -HttpFormParameters $WebParams -Referer $Referer -TimeOutSec 600 -Verbose if($response.error) { Write-Verbose "Error Response - $($response.error | ConvertTo-Json)" throw [string]::Format("ERROR: failed. {0}" , $response.error.message) }else{ if($Response.status -ieq "success"){ Write-Verbose "PITR state changed to $PITRState" }else{ throw "[ERROR] Configure PITR web request returned unknown response $($Response.status)." } } } Export-ModuleMember -Function *-TargetResource |