Skip to content

Instantly share code, notes, and snippets.

@jermdavis
Last active November 23, 2021 13:29
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save jermdavis/49018386ae7544ce0689568edb7ca2b8 to your computer and use it in GitHub Desktop.
Save jermdavis/49018386ae7544ce0689568edb7ca2b8 to your computer and use it in GitHub Desktop.
A Sitecore Install Framework extension to install a development instance of Solr - Further detail at: https://blog.jermdavis.dev/posts/2017/solr-installs-with-sif
##
## private functions
##
#
# If necessary, download a file and unzip it to the specified location
#
function downloadAndUnzipIfRequired
{
Param(
[string]$toolName,
[string]$toolFolder,
[string]$toolZip,
[string]$toolSourceFile,
[string]$installRoot
)
if(!(Test-Path -Path $toolFolder))
{
if(!(Test-Path -Path $toolZip))
{
Write-TaskInfo -Message $toolSourceFile -Tag "Downloading $toolName"
if($pscmdlet.ShouldProcess("$toolSourceFile", "Download source file"))
{
Start-BitsTransfer -Source $toolSourceFile -Destination $toolZip
}
}
else
{
Write-TaskInfo -Message $toolZip -Tag "$toolName already downloaded"
}
Write-TaskInfo -Message $targetFile -Tag "Extracting $toolName"
if($pscmdlet.ShouldProcess("$toolZip", "Extract archive file"))
{
Expand-Archive $toolZip -DestinationPath $installRoot -Force
}
}
else
{
Write-TaskInfo -Message $toolFolder -Tag "$toolName folder already exists - skipping"
}
}
#
# Update the Solr configuration with the changes for HTTP access
#
function configureHTTP
{
Param(
[string]$solrHost,
[string]$solrRoot
)
$solrConfig = "$solrRoot\bin\solr.in.cmd"
if(!(Test-Path -Path "$solrConfig.old"))
{
if($pscmdlet.ShouldProcess("$solrConfig", "Rewriting Solr config file HTTP"))
{
$cfg = Get-Content $solrConfig
Rename-Item $solrConfig "$solrConfig.old"
$newCfg = $newCfg | % { $_ -replace "REM set SOLR_HOST=192.168.1.1", "set SOLR_HOST=$solrHost" }
$newCfg | Set-Content $solrConfig
}
Write-TaskInfo -Message "$solrConfig" -Tag "Solr config updated for HTTP access"
}
else
{
Write-TaskInfo -Message "$solrConfig" -Tag "Solr config already updated for HTTP access - skipping"
}
}
#
# Update the Solr configuration with the changes for HTTPS access
#
function configureHTTPS
{
Param(
[string]$solrHost,
[string]$solrRoot,
[string]$certStore
)
$solrConfig = "$solrRoot\bin\solr.in.cmd"
if(!(Test-Path -Path "$solrConfig.old"))
{
if($pscmdlet.ShouldProcess("$solrConfig", "Rewriting Solr config file for HTTPS"))
{
$cfg = Get-Content $solrConfig
Rename-Item $solrConfig "$solrRoot\bin\solr.in.cmd.old"
$newCfg = $cfg | % { $_ -replace "REM set SOLR_SSL_KEY_STORE=etc/solr-ssl.keystore\.(p12|jks)", "set SOLR_SSL_KEY_STORE=$certStore" }
$newCfg = $newCfg | % { $_ -replace "REM set SOLR_SSL_KEY_STORE_PASSWORD=secret", "set SOLR_SSL_KEY_STORE_PASSWORD=secret" }
$newCfg = $newCfg | % { $_ -replace "REM set SOLR_SSL_TRUST_STORE=etc/solr-ssl.keystore.\.(p12|jks)", "set SOLR_SSL_TRUST_STORE=$certStore" }
$newCfg = $newCfg | % { $_ -replace "REM set SOLR_SSL_TRUST_STORE_PASSWORD=secret", "set SOLR_SSL_TRUST_STORE_PASSWORD=secret" }
$newCfg = $newCfg | % { $_ -replace "REM set SOLR_HOST=192.168.1.1", "set SOLR_HOST=$solrHost" }
$newCfg | Set-Content $solrConfig
}
Write-TaskInfo -Message "$solrConfig" -Tag "Solr config updated for HTTPS access"
}
else
{
Write-TaskInfo -Message "$solrConfig" -Tag "Solr config already updated for HTTPS access - skipping"
}
}
##
## Exported functions
##
#
# Download and unzip the appropriate version of NSSM if it's not already in place
#
function Invoke-EnsureNSSMTask
{
[CmdletBinding(SupportsShouldProcess=$true)]
param(
[parameter(Mandatory=$true)]
[string]$downloadFolder,
[parameter(Mandatory=$true)]
[string]$nssmVersion,
[parameter(Mandatory=$true)]
[string]$nssmSourcePackage,
[parameter(Mandatory=$true)]
[string]$installFolder
)
PROCESS
{
$targetFile = "$installFolder\nssm-$nssmVersion"
$nssmZip = "$downloadFolder\nssm-$nssmVersion.zip"
Write-TaskInfo -Message "$nssmVersion" -Tag "Ensuring NSSM installed"
downloadAndUnzipIfRequired "NSSM" $targetFile $nssmZip $nssmSourcePackage $installFolder
}
}
#
# Download and unzip the appropriate version of Solr if it's not already in place
#
function Invoke-EnsureSolrTask
{
[CmdletBinding(SupportsShouldProcess=$true)]
param(
[parameter(Mandatory=$true)]
[string]$downloadFolder,
[parameter(Mandatory=$true)]
[string]$solrVersion,
[parameter(Mandatory=$true)]
[string]$solrSourcePackage,
[parameter(Mandatory=$true)]
[string]$installFolder
)
PROCESS
{
$targetFile = "$installFolder\solr-$solrVersion"
$solrZip = "$downloadFolder\solr-$solrVersion.zip"
Write-TaskInfo -Message "$solrVersion" -Tag "Ensuring Solr installed"
downloadAndUnzipIfRequired "Solr" $targetFile $solrZip $solrSourcePackage $installFolder
}
}
#
# Update the JAVA_HOME environment variable if required
#
function Invoke-EnsureJavaHomeTask
{
[CmdletBinding(SupportsShouldProcess=$true)]
param(
[parameter(Mandatory=$true)]
[string]$jrePath
)
PROCESS
{
$jreVal = [Environment]::GetEnvironmentVariable("JAVA_HOME", [EnvironmentVariableTarget]::Machine)
if($jreVal -ne $jrePath)
{
Write-TaskInfo -Message "$jrePath" -Tag "Ensuring JAVA_HOME environment variable set"
Write-Host "Setting JAVA_HOME environment variable"
if($pscmdlet.ShouldProcess("$jrePath", "Setting JAVA_HOME environment variable"))
{
[Environment]::SetEnvironmentVariable("JAVA_HOME", $jrePath, [EnvironmentVariableTarget]::Machine)
}
}
else
{
Write-TaskInfo -Message "$jrePath" -Tag "JAVA_HOME environment variable already set - skipping"
}
}
}
#
# Make sure that the solr host name exists in the hosts file
#
function Invoke-EnsureHostNameTask
{
[CmdletBinding(SupportsShouldProcess=$true)]
param(
[parameter(Mandatory=$true)]
[string]$solrHost
)
PROCESS
{
$hostFileName = "c:\\windows\system32\drivers\etc\hosts"
$hostFile = [System.Io.File]::ReadAllText($hostFileName)
if(!($hostFile -like "*$solrHost*"))
{
Write-TaskInfo -Message "$solrHost" -Tag "Adding host entry"
if($pscmdlet.ShouldProcess("$solrHost", "Configure host file entry"))
{
"`r`n127.0.0.1`t$solrHost" | Add-Content $hostFileName
}
}
else
{
Write-TaskInfo -Message "$solrHost" -Tag "Host entry already set - skipping"
}
}
}
#
# Process the configuration changes necessary for Solr to run
#
function Invoke-ConfigureSolrTask
{
[CmdletBinding(SupportsShouldProcess=$true)]
param(
[parameter(Mandatory=$true)]
[bool]$solrSSL,
[parameter(Mandatory=$true)]
[string]$solrHost,
[parameter(Mandatory=$true)]
[string]$solrRoot,
[parameter(Mandatory=$true)]
[string]$certificateStore
)
PROCESS
{
if($solrSSL)
{
Write-TaskInfo -Message "HTTPS" -Tag "Configuring Solr for HTTPS access"
configureHTTPS $solrHost $solrRoot $certificateStore
}
else
{
Write-TaskInfo -Message "HTTP" -Tag "Configuring Solr for HTTP access"
configureHTTP $solrHost $solrRoot
}
}
}
#
# Ensure that a trusted SSL Certificate exists for the Solr host name, and export it for Solr to use
#
function Invoke-EnsureSSLCertificateTask
{
[CmdletBinding(SupportsShouldProcess=$true)]
param(
[parameter(Mandatory=$true)]
[bool]$solrSSL,
[parameter(Mandatory=$true)]
[string]$solrName,
[parameter(Mandatory=$true)]
[string]$solrHost,
[parameter(Mandatory=$true)]
[string]$certificateStore
)
PROCESS
{
if($solrSSL)
{
# Generate SSL cert
$existingCert = Get-ChildItem Cert:\LocalMachine\Root | where FriendlyName -eq "$solrName"
if(!($existingCert))
{
Write-TaskInfo -Message "$solrHost" -Tag "Creating and trusting an new SSL Cert"
if($pscmdlet.ShouldProcess("$solrHost", "Generate new trusted SSL certificate"))
{
# Generate a cert
# https://docs.microsoft.com/en-us/powershell/module/pkiclient/new-selfsignedcertificate?view=win10-ps
$cert = New-SelfSignedCertificate -FriendlyName "$solrName" -DnsName "$solrHost" -CertStoreLocation "cert:\LocalMachine" -NotAfter (Get-Date).AddYears(10)
# Trust the cert
# https://stackoverflow.com/questions/8815145/how-to-trust-a-certificate-in-windows-powershell
$store = New-Object System.Security.Cryptography.X509Certificates.X509Store "Root","LocalMachine"
$store.Open("ReadWrite")
$store.Add($cert)
$store.Close()
# remove the untrusted copy of the cert
$cert | Remove-Item
}
}
else
{
Write-TaskInfo -Message "$solrHost" -Tag "Trusted SSL certificate already exists - skipping"
}
# export the cert to pfx using solr's default password
if(!(Test-Path -Path $certificateStore))
{
Write-TaskInfo -Message "$certificateStore" -Tag "Exporting certificate to disk"
$cert = Get-ChildItem Cert:\LocalMachine\Root | where FriendlyName -eq "$solrName"
$certPwd = ConvertTo-SecureString -String "secret" -Force -AsPlainText
if($pscmdlet.ShouldProcess("$certificateStore", "Export certificate to disk"))
{
$cert | Export-PfxCertificate -FilePath $certificateStore -Password $certpwd | Out-Null
}
}
else
{
Write-TaskInfo -Message "$certificateStore" -Tag "Certificate file already exported - skipping"
}
}
}
}
#
# Ensure that a service exists to run the specified version of Solr
#
function Invoke-EnsureSolrServiceTask
{
[CmdletBinding(SupportsShouldProcess=$true)]
param(
[parameter(Mandatory=$true)]
[string]$solrName,
[parameter(Mandatory=$true)]
[string]$installFolder,
[parameter(Mandatory=$true)]
[string]$nssmVersion,
[parameter(Mandatory=$true)]
[string]$solrRoot,
[parameter(Mandatory=$true)]
[string]$solrPort
)
PROCESS
{
$svc = Get-Service "$solrName" -ErrorAction SilentlyContinue
if(!($svc))
{
Write-TaskInfo -Message "$solrName" -Tag "Installing Solr service"
if($pscmdlet.ShouldProcess("$solrName", "Install Solr service using NSSM"))
{
&"$installFolder\nssm-$nssmVersion\win64\nssm.exe" install "$solrName" "$solrRoot\bin\solr.cmd" "-f" "-p $solrPort"
}
$svc = Get-Service "$solrName" -ErrorAction SilentlyContinue
}
else
{
Write-TaskInfo -Message "$solrName" -Tag "Solr service already installed - skipping"
}
if($svc.Status -ne "Running")
{
Write-TaskInfo -Message "$solrName" -Tag "Starting Solr service"
if($pscmdlet.ShouldProcess("$solrName", "Starting Solr service"))
{
Start-Service "$solrName"
}
}
else
{
Write-TaskInfo -Message "$solrName" -Tag "Solr service already started - skipping"
}
}
}
#
# Verify Solr is working by opening a browser to the admin UI.
#
function Confirm-SolrInstallTask
{
[CmdletBinding(SupportsShouldProcess=$true)]
param(
[parameter(Mandatory=$true)]
[bool]$solrSSL,
[parameter(Mandatory=$true)]
[string]$solrHost,
[parameter(Mandatory=$true)]
[string]$solrPort
)
PROCESS
{
$protocol = "http"
if($solrSSL -eq $true)
{
$protocol = "https"
}
$url = "$($protocol)://$($solrHost):$solrPort/solr/"
Write-TaskInfo -Message "$url" -Tag "Verifying Solr is running"
if($pscmdlet.ShouldProcess("$url", "Open Solr in default browser to verify it"))
{
Invoke-Expression "start $url"
}
}
}
Register-SitecoreInstallExtension -Command Invoke-EnsureNSSMTask -As EnsureNssm -Type Task
Register-SitecoreInstallExtension -Command Invoke-EnsureSolrTask -As EnsureSolr -Type Task
Register-SitecoreInstallExtension -Command Invoke-EnsureJavaHomeTask -As EnsureJavaHome -Type Task
Register-SitecoreInstallExtension -Command Invoke-EnsureHostNameTask -As EnsureHostName -Type Task
Register-SitecoreInstallExtension -Command Invoke-ConfigureSolrTask -As ConfigureSolr -Type Task
Register-SitecoreInstallExtension -Command Invoke-EnsureSSLCertificateTask -As EnsureSSLCertificate -Type Task
Register-SitecoreInstallExtension -Command Invoke-EnsureSolrServiceTask -As EnsureSolrService -Type Task
Register-SitecoreInstallExtension -Command Confirm-SolrInstallTask -As SolrInstall -Type Task
{
"Parameters" : {
"JREVersion": {
"Type": "string",
"DefaultValue": "1.8.0_151",
"Description": "What version of the Java Runtime should "
},
"SolrVersion": {
"Type": "string",
"DefaultValue": "6.6.2",
"Description": "What version of Solr should be downloaded for install"
},
"NSSMVersion": {
"Type": "string",
"DefaultValue": "2.24",
"Description": "What version of NSSM should be downloaded for install"
},
"InstallFolder": {
"Type": "string",
"DefaultValue": "c:\\solr",
"Description": "Where should Solr and NSSM be installed to"
},
"DownloadFolder": {
"Type": "string",
"DefaultValue": "~\\Downloads",
"Description": "Where should downloaded files be placed"
},
"SolrUseSSL": {
"Type": "boolean",
"DefaultValue": true,
"Description": "Should Solr require HTTPS for access?"
},
"SolrHost": {
"Type": "string",
"DefaultValue": "solr",
"Description": "What host name should the Solr service use"
},
"SolrPort": {
"Type": "string",
"DefaultValue": "8983",
"Description": "The port the Solr service should use"
}
},
"Modules" : [
"SolrInstall-SIF-Extension.psm1"
],
"Variables" : {
"NSSMSourcePackage": "[concat('https://nssm.cc/release/nssm-', parameter('NSSMVersion'), '.zip')]",
"SolrSourcePackage": "[concat('https://archive.apache.org/dist/lucene/solr/', parameter('SolrVersion'), '/solr-', parameter('SolrVersion'), '.zip')]",
"JREPath": "[concat('C:\\Program Files (x86)\\Java\\jre', parameter('JREVersion'))]",
"SolrInstallFolder": "[concat(parameter('InstallFolder'), '\\solr-', parameter('SolrVersion'))]",
"SolrName": "[concat('solr-', parameter('SolrVersion'))]",
"CertStoreFile": "[concat(variable('SolrInstallFolder'), '\\server\\etc\\solr-ssl.keystore.pfx')]"
},
"Tasks" : {
"Ensure NSSM is installed": {
"Type": "EnsureNSSM",
"Params": {
"downloadFolder": "[parameter('DownloadFolder')]",
"nssmVersion": "[parameter('NSSMVersion')]",
"installFolder": "[parameter('InstallFolder')]",
"nssmSourcePackage": "[variable('NSSMSourcePackage')]"
}
},
"Ensure Solr is installed": {
"Type": "EnsureSolr",
"Params": {
"downloadFolder": "[parameter('DownloadFolder')]",
"solrVersion": "[parameter('SolrVersion')]",
"installFolder": "[parameter('InstallFolder')]",
"solrSourcePackage": "[variable('SolrSourcePackage')]"
}
},
"Ensure Java_Home environent variable is set": {
"Type": "EnsureJavaHome",
"Params": {
"jrePath": "[variable('JREPath')]"
}
},
"Ensure host name exists": {
"Type": "EnsureHostName",
"Params": {
"solrHost": "[parameter('SolrHost')]"
}
},
"Rewrite Solr config file": {
"Type": "ConfigureSolr",
"Params": {
"solrSSL": "[parameter('SolrUseSSL')]",
"solrHost": "[parameter('SolrHost')]",
"solrRoot": "[variable('SolrInstallFolder')]",
"certificateStore": "[variable('CertStoreFile')]"
}
},
"Ensure trusted SSL certificate exists (if required)": {
"Type": "EnsureSSLCertificate",
"Params": {
"solrSSL": "[parameter('SolrUseSSL')]",
"solrName": "[variable('SolrName')]",
"solrHost": "[parameter('SolrHost')]",
"certificateStore": "[variable('CertStoreFile')]"
}
},
"Ensure Solr runs as a service": {
"Type": "EnsureSolrService",
"Params": {
"solrName": "[variable('SolrName')]",
"installFolder": "[parameter('InstallFolder')]",
"nssmVersion": "[parameter('NSSMVersion')]",
"solrRoot": "[variable('SolrInstallFolder')]",
"solrPort": "[parameter('SolrPort')]"
}
},
"Verify Solr is working": {
"Type": "SolrInstall",
"Params": {
"solrSSL": "[parameter('SolrUseSSL')]",
"solrHost": "[parameter('SolrHost')]",
"solrPort": "[parameter('SolrPort')]"
}
}
}
}
@danielgovier
Copy link

Thanks for the script, Jeremy.

I noticed a small spelling discrepancy in the SolrServer.json that caused a "no valid module was found..." error

"Modules" : [ "SolrInstall-SIF-Extensions.psm1" ],

SolrInstall-SIF-Extensions.psm1 is plural and the module name is singular: SolrInstall-SIF-Extension.psm1

@anischohan
Copy link

Ahh the plot thickens, thanks for this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment