DSCResources/ArcGIS_NotebookServer/ArcGIS_NotebookServer.psm1
<#
.SYNOPSIS Makes a request to the installed Notebook Server to create a New Server Site .PARAMETER Ensure Ensure makes sure that a Notebook Server site is configured. Take the values Present or Absent. - "Present" ensures that a Notebook server site is created. - "Absent" ensures that existing Notebook server site is deleted. .PARAMETER ConfigurationStoreLocation Key - Path to Configuration store - Can be a Physical Location or Network Share Address .PARAMETER ServerDirectoriesRootLocation Path to Notebook Server Root Directories - Can be a Physical Location or Network Share Address .PARAMETER ConfigStoreCloudStorageConnectionString Connection string to Azure Cloud Storage Account to configure a Site with config store using a Cloud Store .PARAMETER ConfigStoreCloudStorageConnectionSecret Connection string Secret to Azure Cloud Storage Account to configure a Site with config store using a Cloud Store .PARAMETER SiteAdministrator A MSFT_Credential Object - Primary Site Administrator .PARAMETER LogLevel Defines the Logging Level of Notebook Server. Can have values - "OFF","SEVERE","WARNING","INFO","FINE","VERBOSE","DEBUG" .PARAMETER WebContextURL External Enpoint when using a reverse proxy server and the URL to your site does not end with the default string /arcgis (all lowercase). #> function Get-TargetResource { [CmdletBinding()] [OutputType([System.Collections.Hashtable])] param ( [ValidateSet("Present","Absent")] [System.String] $Ensure, [parameter(Mandatory = $true)] [System.String] $ConfigurationStoreLocation, [System.String] $ConfigStoreCloudStorageConnectionString, [System.String] $ConfigStoreCloudStorageConnectionSecret, [parameter(Mandatory = $true)] [System.String] $ServerDirectoriesRootLocation, [parameter(Mandatory = $true)] [System.Management.Automation.PSCredential] $SiteAdministrator, [parameter(Mandatory = $false)] [System.String] $LogLevel, [parameter(Mandatory = $false)] [System.String] $WebContextURL ) Import-Module $PSScriptRoot\..\..\ArcGISUtility.psm1 -Verbose:$false $null } function Set-TargetResource { [CmdletBinding()] [OutputType([System.Collections.Hashtable])] param ( [ValidateSet("Present","Absent")] [System.String] $Ensure, [parameter(Mandatory = $true)] [System.String] $ConfigurationStoreLocation, [System.String] $ConfigStoreCloudStorageConnectionString, [System.String] $ConfigStoreCloudStorageConnectionSecret, [parameter(Mandatory = $true)] [System.String] $ServerDirectoriesRootLocation, [parameter(Mandatory = $true)] [System.Management.Automation.PSCredential] $SiteAdministrator, [parameter(Mandatory = $false)] [System.String] $LogLevel, [parameter(Mandatory = $false)] [System.String] $WebContextURL ) Import-Module $PSScriptRoot\..\..\ArcGISUtility.psm1 -Verbose:$false [System.Reflection.Assembly]::LoadWithPartialName("System.Web") | Out-Null if($VerbosePreference -ine 'SilentlyContinue') { Write-Verbose ("Site Administrator UserName:- " + $SiteAdministrator.UserName) } $FQDN = Get-FQDN $env:COMPUTERNAME Write-Verbose "Fully Qualified Domain Name :- $FQDN" $ServiceName = 'ArcGIS Notebook Server' $RegKey = Get-EsriRegistryKeyForService -ServiceName $ServiceName $InstallDir = (Get-ItemProperty -Path $RegKey -ErrorAction Ignore).InstallDir Write-Verbose "Waiting for Server 'https://$($FQDN):11443/arcgis/admin' to initialize" Wait-ForUrl "https://$($FQDN):11443/arcgis/admin" -HttpMethod 'GET' if($Ensure -ieq 'Present') { $Referer = 'http://localhost' $RestartRequired = $false $configuredHostName = Get-ConfiguredHostName -InstallDir $InstallDir if($configuredHostName -ine $FQDN){ Write-Verbose "Configured Host Name '$configuredHostName' is not equal to '$($FQDN)'. Setting it" if(Set-ConfiguredHostName -InstallDir $InstallDir -HostName $FQDN) { # Need to restart the service to pick up the hostname $RestartRequired = $true } } if($RestartRequired) { try { Write-Verbose "Restarting Service $ServiceName" Stop-Service -Name $ServiceName -Force -ErrorAction Ignore Write-Verbose 'Stopping the service' Wait-ForServiceToReachDesiredState -ServiceName $ServiceName -DesiredState 'Stopped' Write-Verbose 'Stopped the service' }catch { Write-Verbose "[WARNING] Stopping Service $_" } try { Write-Verbose 'Starting the service' Start-Service -Name $ServiceName -ErrorAction Ignore Wait-ForServiceToReachDesiredState -ServiceName $ServiceName -DesiredState 'Running' Write-Verbose "Restarted Service $ServiceName" }catch { Write-Verbose "[WARNING] Starting Service $_" } Write-Verbose "Waiting for Server 'https://$($FQDN):11443/arcgis/admin' to initialize" Wait-ForUrl "https://$($FQDN):11443/arcgis/admin" -HttpMethod 'GET' } $ServerUrl = "https://$($FQDN):11443" Write-Verbose "Checking for Notebook Server site on '$ServerUrl'" $siteExists = $false try { $token = Get-ServerToken -ServerEndPoint $ServerUrl -ServerSiteName 'arcgis' -Credential $SiteAdministrator -Referer $Referer $siteExists = ($token.token -ne $null) } catch { Write-Verbose "[WARNING] GetToken returned:- $_" } if(-not($siteExists)) { [int]$Attempt = 1 [bool]$Done = $false while(-not($Done) -and ($Attempt -le 3)) { try { Write-Verbose 'Creating Site' if($Attempt -gt 1) { Write-Verbose "Attempt # $Attempt" } Create-Site -ServerURL $ServerUrl -Credential $SiteAdministrator -ConfigurationStoreLocation $ConfigurationStoreLocation ` -ServerDirectories $ServerDirectoriesRootLocation -Verbose -ConfigStoreCloudStorageConnectionString $ConfigStoreCloudStorageConnectionString ` -ConfigStoreCloudStorageConnectionSecret $ConfigStoreCloudStorageConnectionSecret $Done = $true Write-Verbose 'Created Site' }catch{ Write-Verbose "[WARNING] Error while creating site on attempt $Attempt Error:- $_" if($Attempt -lt 1) { Write-Verbose "Restarting Service $ServiceName" Stop-Service -Name $ServiceName -Force Write-Verbose 'Stopping the service' Wait-ForServiceToReachDesiredState -ServiceName $ServiceName -DesiredState 'Stopped' Write-Verbose 'Starting the service' Start-Service -Name $ServiceName Wait-ForServiceToReachDesiredState -ServiceName $ServiceName -DesiredState 'Running' Write-Verbose "Restarted Service $ServiceName" Write-Verbose "Waiting for Server 'https://$($FQDN):11443/arcgis/admin' to initialize" Wait-ForUrl -Url "https://$($FQDN):11443/arcgis/admin" -HttpMethod 'GET' }else{ if($_.ToString().IndexOf('The remote name could not be resolved') -gt -1) { if($Attempt -ge 3) { throw "Failed to create site after multiple attempts due to network initialization. Please retry using the back and finish buttons" }else { # ArcGIS Server was not able to resolve the host (networking race conditions). Retry Write-Verbose "Possible networking initialization error. Retry site creation after 30 seconds" Start-Sleep -Seconds 30 } }else { throw $_ } } } $Attempt = $Attempt + 1 } Write-Verbose "Waiting for Server 'https://$($FQDN):11443/arcgis/admin' to initialize" Wait-ForUrl -Url "https://$($FQDN):11443/arcgis/admin" -HttpMethod 'GET' -Verbose }else{ Write-Verbose "Site Already Exists." } #Write-Verbose 'Get Server Token' $token = Get-ServerToken -ServerEndPoint "https://$($FQDN):11443" -ServerSiteName 'arcgis' -Credential $SiteAdministrator -Referer $Referer Write-Verbose "Ensuring Log Level $LogLevel" $logSettings = Get-LogSettings -ServerURL $ServerUrl -Token $token.token -Referer $Referer Write-Verbose "Current Log Level:- $($logSettings.logLevel)" if($logSettings.logLevel -ine $LogLevel) { $logSettings.logLevel = $LogLevel Write-Verbose "Updating log level to $($logSettings.logLevel)" Update-LogSettings -ServerURL "https://$($FQDN):11443" -Token $token.token -Referer $Referer -logSettings $logSettings #Write-Verbose "Updated log level to $($logSettings.settings.logLevel)" } if($WebContextURL){ $systemProperties = Get-AdminSettings -ServerUrl $ServerUrl -SettingUrl "arcgis/admin/system/properties/" -Token $token.token if(-not($systemProperties.WebContextURL) -or $systemProperties.WebContextURL -ine $WebContextURL){ Write-Verbose "Web Context URL '$($systemProperties.WebContextURL)' doesn't match expected value '$WebContextURL'" if(-not($systemProperties.WebContextURL)){ Add-Member -InputObject $systemProperties -MemberType NoteProperty -Name "WebContextURL" -Value $WebContextURL }else{ $systemProperties.WebContextURL = $WebContextURL } Set-AdminSettings -ServerUrl $ServerUrl -SettingUrl "arcgis/admin/system/properties/update" -Token $token.token -Properties $systemProperties } } } elseif($Ensure -ieq 'Absent') { Write-Verbose 'Deleting Site' Delete-Site -ServerURL "https://$($FQDN):11443" -Credential $SiteAdministrator Write-Verbose 'Site Deleted' Write-Verbose "Deleting contents of $ConfigStoreRootLocation" Remove-Item $ConfigurationStoreLocation -Recurse -Force Write-Verbose "Deleted contents of $ServerDirectoriesRootLocation" Remove-Item $ServerDirectoriesRootLocation -Recurse -Force } } function Test-TargetResource { [CmdletBinding()] [OutputType([System.Boolean])] param ( [ValidateSet("Present","Absent")] [System.String] $Ensure, [parameter(Mandatory = $true)] [System.String] $ConfigurationStoreLocation, [System.String] $ConfigStoreCloudStorageConnectionString, [System.String] $ConfigStoreCloudStorageConnectionSecret, [parameter(Mandatory = $true)] [System.String] $ServerDirectoriesRootLocation, [parameter(Mandatory = $true)] [System.Management.Automation.PSCredential] $SiteAdministrator, [parameter(Mandatory = $false)] [System.String] $LogLevel, [parameter(Mandatory = $false)] [System.String] $WebContextURL ) Import-Module $PSScriptRoot\..\..\ArcGISUtility.psm1 -Verbose:$false [System.Reflection.Assembly]::LoadWithPartialName("System.Web") | Out-Null $FQDN = Get-FQDN $env:COMPUTERNAME Write-Verbose "Fully Qualified Domain Name :- $FQDN" $Referer = 'http://localhost' $ServerUrl = "https://$($FQDN):11443" $result = $false try { Write-Verbose "Checking for site on '$ServerUrl'" Wait-ForUrl -Url $ServerUrl -SleepTimeInSeconds 5 -HttpMethod 'GET' $token = Get-ServerToken -ServerEndPoint $ServerUrl -ServerSiteName 'arcgis' -Credential $SiteAdministrator -Referer $Referer $result = ($token.token -ne $null) if($result){ Write-Verbose "Site Exists. Was able to retrieve token for PSA" }else{ Write-Verbose "Unable to detect if Site Exists. Was NOT able to retrieve token for PSA" } } catch { Write-Verbose "[WARNING]:- $($_)" } if($result -and $LogLevel){ $logSettings = Get-LogSettings -ServerURL $ServerUrl -Token $token.token -Referer $Referer Write-Verbose "Current Log Level $($logSettings.logLevel)" if($logSettings.logLevel -ine $LogLevel) { Write-Verbose "Current Log Level $($logSettings.settings.logLevel) not set to '$LogLevel'" $result = $false } } if($result -and $WebContextURL){ $systemProperties = Get-AdminSettings -ServerUrl $ServerUrl -SettingUrl "arcgis/admin/system/properties/" -Token $token.token if(-not($systemProperties.WebContextURL) -or $systemProperties.WebContextURL -ine $WebContextURL){ Write-Verbose "Web Context URL '$($systemProperties.WebContextURL)' doesn't match expected value '$WebContextURL'" $result = $false } } if($result) { $ServiceName = 'ArcGIS Notebook Server' $RegKey = Get-EsriRegistryKeyForService -ServiceName $ServiceName $InstallDir =(Get-ItemProperty -Path $RegKey -ErrorAction Ignore).InstallDir $configuredHostName = Get-ConfiguredHostName -InstallDir $InstallDir if($configuredHostName -ine $FQDN){ Write-Verbose "Configured Host Name '$configuredHostName' is not equal to '$FQDN'" $result = $false } } if($Ensure -ieq 'Present') { $result } elseif($Ensure -ieq 'Absent') { (-not($result)) } } function Create-Site { [CmdletBinding()] Param ( [System.String] $ServerURL, [System.Management.Automation.PSCredential] $Credential, [System.String] $ConfigurationStoreLocation, [System.String] $ConfigStoreCloudStorageConnectionString, [System.String] $ConfigStoreCloudStorageConnectionSecret, [System.String] $ServerDirectories, [System.Int32] $TimeOut = 1000 ) $createNewSiteUrl = $ServerURL.TrimEnd("/") + "/arcgis/admin/createNewSite" $baseHostUrl = $ServerURL.TrimEnd("/") + "/" if(($ConfigStoreCloudStorageConnectionString) -and ($ConfigStoreCloudStorageConnectionSecret) -and ($ConfigStoreCloudStorageConnectionString.IndexOf('AccountName=') -gt -1)) { Write-Verbose "Using Azure Cloud Storage for the config store" $configStoreConnection = @{ configPersistenceType= "AZURE"; connectionString = $ConfigStoreCloudStorageConnectionString + ";" + $ConfigStoreCloudStorageConnectionSecret; className = "com.esri.arcgis.carbon.persistence.impl.azure.AzureConfigPersistence" } $Timeout = 2 * $Timeout # Double the timeout if using cloud storage for the config store } else { Write-Verbose "Using File System Based Storage for the config store" $configStoreConnection = @{ configPersistenceType= "FILESYSTEM" connectionString = $ConfigurationStoreLocation className = "com.esri.arcgis.carbon.persistence.impl.filesystem.FSConfigPersistence" } } $directories = @( @{ name = "arcgisworkspace" path = "$ServerDirectories\arcgisworkspace" type = "WORKSPACE" }, @{ name = "arcgisoutput" path = "$ServerDirectories\arcgisoutput" type = "OUTPUT" }, @{ name = "arcgissystem" path = "$ServerDirectories\arcgissystem" type = "SYSTEM" } ) $requestParams = @{ username = $Credential.UserName password = $Credential.GetNetworkCredential().Password configStoreConnection = ConvertTo-JSON $configStoreConnection -Compress -Depth 5 directories = ConvertTo-JSON $directories -Compress #logsSettings = "{}" async = "false" f = "pjson" } # make sure Tomcat is up and running BEFORE sending a request Write-Verbose "Waiting for Server 'https://$($FQDN):11443/arcgis/admin' to initialize" Wait-ForUrl -Url $baseHostUrl -SleepTimeInSeconds 5 -HttpMethod 'GET' -Verbose $httpRequestBody = To-HttpBody -props $requestParams $response = Invoke-RestMethod -Method Post -Uri $createNewSiteUrl -Body $httpRequestBody -TimeoutSec $TimeOut if($response.status -ieq "success"){ Write-Verbose "Site Created Successfully!" }else{ Write-Verbose ("Response from CreateSite:-" + ($response | ConvertTo-JSON -Depth 5)) if($response.error){ throw "Create Site Failed. Code:- $($response.error.code), Error:- $($response.error.message)" } } } function Get-LogSettings { [CmdletBinding()] Param ( [System.String] $ServerURL, [System.String] $Token, [System.String] $Referer ) $ServerURL = $ServerURL.TrimEnd("/") + "/arcgis/admin/logs/settings" Invoke-ArcGISWebRequest -Url $ServerURL -HttpFormParameters @{ f= 'json'; token = $Token } -Referer $Referer -TimeoutSec 30 -HttpMethod 'GET' } function Update-LogSettings { [CmdletBinding()] Param ( [System.String] $ServerURL, [System.String] $Token, [System.String] $Referer, $logSettings ) $UpdateLogSettingsUrl = $ServerURL.TrimEnd("/") + "/arcgis/admin/logs/settings/edit" Write-Verbose ($logSettings | ConvertTo-JSON -Depth 5) $props = @{ f= 'pjson'; token = $Token; logDir = $logSettings.logDir; logLevel = $logSettings.logLevel; maxLogFileAge = $logSettings.maxLogFileAge; maxErrorReportsCount = $logSettings.maxErrorReportsCount; usageMeteringEnabled = $logSettings.usageMeteringEnabled } $cmdBody = To-HttpBody $props $headers = @{ 'Content-type'='application/x-www-form-urlencoded' 'Content-Length' = $cmdBody.Length 'Accept' = 'text/plain' 'Referer' = $Referer } $res = Invoke-WebRequest -Uri $UpdateLogSettingsUrl -Body $cmdBody -Method POST -Headers $headers -UseDefaultCredentials -DisableKeepAlive -UseBasicParsing $response = $res | ConvertFrom-Json if($response.status -ieq "success"){ Write-Verbose "Log Settings Update Successfully" }else{ Write-Verbose "[WARNING]: Code:- $($response.error.code), Error:- $($response.error.message)" } } function Delete-Site { [CmdletBinding()] Param ( [System.String] $ServerURL, [System.Management.Automation.PSCredential] $Credential, [System.Int32] $TimeOut = 300 ) $Referer = $ServerURL $token = Get-ServerToken -ServerEndPoint $ServerURL -ServerSiteName 'arcgis' -Credential $Credential -Referer $Referer $DeleteSiteUrl = $ServerURL.TrimEnd("/") + "/arcgis/admin/deleteSite" $RequestParams = @{ f = "json" token= $token.token } $HttpBody = To-HttpBody -props $RequestParams $Headers = @{ 'Content-type'='application/x-www-form-urlencoded' 'Content-Length' = $HttpBody.Length 'Accept' = 'text/plain' 'Referer' = $Referer } $response = Invoke-RestMethod -Method Post -Uri $DeleteSiteUrl -Body $HttpBody -Headers $Headers -TimeoutSec $TimeOut Write-Verbose ($response | ConvertTo-Json -Depth 5) } function Get-AdminSettings { [CmdletBinding()] Param ( [System.String] $ServerUrl, [System.String] $SettingUrl, [System.String] $Token ) $RequestParams = @{ f= 'json'; token = $Token; } $RequestUrl = $ServerUrl.TrimEnd("/") + "/" + $SettingUrl.TrimStart("/") $Response = Invoke-ArcGISWebRequest -Url $RequestUrl -HttpFormParameters $RequestParams Check-ResponseStatus $Response $Response } function Set-AdminSettings { [CmdletBinding()] Param ( [System.String] $ServerUrl, [System.String] $SettingUrl, [System.String] $Token, $Properties ) $RequestUrl = $ServerUrl.TrimEnd("/") + "/" + $SettingUrl.TrimStart("/") $RequestParams = @{ f= 'json'; token = $Token; properties = ( $Properties | ConvertTo-Json -Depth 5 -Compress ) } $Response = Invoke-ArcGISWebRequest -Url $RequestUrl -HttpFormParameters $RequestParams if($response.status -ieq "success"){ Write-Verbose "Admin Settings Update Successfully" }else{ Write-Verbose "[WARNING]: Code:- $($response.error.code), Error:- $($response.error.message)" } } Export-ModuleMember -Function *-TargetResource |