mirror of https://github.com/apache/cassandra
392 lines
12 KiB
PowerShell
392 lines
12 KiB
PowerShell
#
|
|
# Licensed to the Apache Software Foundation (ASF) under one or more
|
|
# contributor license agreements. See the NOTICE file distributed with
|
|
# this work for additional information regarding copyright ownership.
|
|
# The ASF licenses this file to You under the Apache License, Version 2.0
|
|
# (the "License"); you may not use this file except in compliance with
|
|
# the License. You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
#-----------------------------------------------------------------------------
|
|
Function PrintUsage
|
|
{
|
|
echo @"
|
|
usage: cassandra.ps1 [-f] [-h] [-q] [-a] [-p pidfile] [-H dumpfile] [-D arg] [-E errorfile] [-install | -uninstall] [-help]
|
|
-f Run cassandra in foreground
|
|
-install install cassandra as a service
|
|
-uninstall remove cassandra service
|
|
-p pidfile tracked by server and removed on close (defaults to pid.txt)
|
|
-H change JVM HeapDumpPath
|
|
-D items to append to JVM_OPTS
|
|
-E change JVM ErrorFile
|
|
-v Print cassandra version and exit
|
|
-s Show detailed jvm environment information during launch
|
|
-a Aggressive startup. Skip VerifyPorts check. For use in dev environments.
|
|
-q Quiet output. Does not print stdout/stderr to console (when run without -f)
|
|
-help print this message
|
|
|
|
NOTE: installing cassandra as a service requires Commons Daemon Service Runner
|
|
available at http://commons.apache.org/proper/commons-daemon/"
|
|
"@
|
|
exit
|
|
}
|
|
|
|
#-----------------------------------------------------------------------------
|
|
Function Main
|
|
{
|
|
ValidateArguments
|
|
|
|
# support direct run of .ps1 file w/out batch file
|
|
if ($env:CASSANDRA_HOME -eq $null)
|
|
{
|
|
$scriptDir = Split-Path $script:MyInvocation.MyCommand.Path
|
|
$env:CASSANDRA_HOME = (Get-Item $scriptDir).parent.FullName
|
|
}
|
|
. "$env:CASSANDRA_HOME\bin\source-conf.ps1"
|
|
|
|
$conf = Find-Conf
|
|
if ($s)
|
|
{
|
|
echo "Sourcing cassandra config file: $conf"
|
|
}
|
|
. $conf
|
|
|
|
SetCassandraEnvironment
|
|
if ($v)
|
|
{
|
|
PrintVersion
|
|
exit
|
|
}
|
|
$pidfile = "$env:CASSANDRA_HOME\$pidfile"
|
|
|
|
# Other command line params
|
|
if ($H)
|
|
{
|
|
$env:JVM_OPTS = $env:JVM_OPTS + " -XX:HeapDumpPath=$H"
|
|
}
|
|
if ($E)
|
|
{
|
|
$env:JVM_OPTS = $env:JVM_OPTS + " -XX:ErrorFile=$E"
|
|
}
|
|
if ($p)
|
|
{
|
|
$pidfile = "$p"
|
|
$env:CASSANDRA_PARAMS = $env:CASSANDRA_PARAMS + ' -Dcassandra-pidfile="' + "$pidfile" + '"'
|
|
}
|
|
|
|
# Parse -D and -X JVM_OPTS
|
|
for ($i = 0; $i -lt $script:args.Length; ++$i)
|
|
{
|
|
if ($script:args[$i].StartsWith("-D") -Or $script:args[$i].StartsWith("-X"))
|
|
{
|
|
$env:JVM_OPTS = "$env:JVM_OPTS " + $script:args[$i]
|
|
}
|
|
}
|
|
|
|
if ($install -or $uninstall)
|
|
{
|
|
HandleInstallation
|
|
}
|
|
else
|
|
{
|
|
VerifyPortsAreAvailable
|
|
RunCassandra($f)
|
|
}
|
|
}
|
|
|
|
#-----------------------------------------------------------------------------
|
|
Function HandleInstallation
|
|
{
|
|
$SERVICE_JVM = """cassandra"""
|
|
$PATH_PRUNSRV = "$env:CASSANDRA_HOME\bin\daemon"
|
|
$PR_LOGPATH = $serverPath
|
|
|
|
if (-Not (Test-Path $PATH_PRUNSRV\prunsrv.exe))
|
|
{
|
|
Write-Warning "Cannot find $PATH_PRUNSRV\prunsrv.exe. Please download package from http://www.apache.org/dist/commons/daemon/binaries/windows/ to install as a service."
|
|
Break
|
|
}
|
|
|
|
If (-NOT ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator"))
|
|
{
|
|
Write-Warning "Cannot perform installation without admin credentials. Please re-run as administrator."
|
|
Break
|
|
}
|
|
if (!$env:PRUNSRV)
|
|
{
|
|
$env:PRUNSRV="$PATH_PRUNSRV\prunsrv"
|
|
}
|
|
|
|
$regPath = "HKLM:\SYSTEM\CurrentControlSet\services\Tcpip\Parameters\"
|
|
|
|
echo "Attempting to delete existing $SERVICE_JVM service..."
|
|
Start-Sleep -s 2
|
|
$proc = Start-Process -FilePath "$env:PRUNSRV" -ArgumentList "//DS//$SERVICE_JVM" -PassThru -WindowStyle Hidden
|
|
|
|
echo "Reverting to default TCP keepalive settings (2 hour timeout)"
|
|
Remove-ItemProperty -Path $regPath -Name KeepAliveTime -EA SilentlyContinue
|
|
|
|
# Quit out if this is uninstall only
|
|
if ($uninstall)
|
|
{
|
|
return
|
|
}
|
|
|
|
echo "Installing [$SERVICE_JVM]."
|
|
Start-Sleep -s 2
|
|
$proc = Start-Process -FilePath "$env:PRUNSRV" -ArgumentList "//IS//$SERVICE_JVM" -PassThru -WindowStyle Hidden
|
|
|
|
echo "Setting launch parameters for [$SERVICE_JVM]"
|
|
Start-Sleep -s 2
|
|
|
|
$args = @"
|
|
//US//$SERVICE_JVM
|
|
--Jvm=auto --StdOutput auto --StdError auto
|
|
--Classpath=$env:CLASSPATH
|
|
--StartMode=jvm --StartClass=$env:CASSANDRA_MAIN --StartMethod=main
|
|
--StopMode=jvm --StopClass=$env:CASSANDRA_MAIN --StopMethod=stop
|
|
--PidFile "$pidfile"
|
|
"@
|
|
|
|
# Include cassandra params
|
|
$prunArgs = "$env:CASSANDRA_PARAMS $env:JVM_OPTS"
|
|
|
|
# Change to semicolon delim as we can't split on space due to potential spaces in directory names
|
|
$prunArgs = $prunArgs -replace " -", ";-"
|
|
|
|
# JvmOptions w/multiple semicolon delimited items isn't working correctly. storagedir and logdir were
|
|
# both being ignored / failing to parse on startup. See CASSANDRA-8115
|
|
$split_opts = $prunArgs.Split(";")
|
|
foreach ($arg in $split_opts)
|
|
{
|
|
$args += " ++JvmOptions=$arg"
|
|
}
|
|
|
|
$args = $args -replace [Environment]::NewLine, ""
|
|
$proc = Start-Process -FilePath "$env:PRUNSRV" -ArgumentList $args -PassThru -WindowStyle Hidden
|
|
|
|
echo "Setting KeepAliveTimer to 5 minutes for TCP keepalive"
|
|
Set-ItemProperty -Path $regPath -Name KeepAliveTime -Value 300000
|
|
|
|
echo "Installation of [$SERVICE_JVM] is complete"
|
|
}
|
|
|
|
#-----------------------------------------------------------------------------
|
|
Function PrintVersion()
|
|
{
|
|
Write-Host "Cassandra Version: " -NoNewLine
|
|
$pinfo = New-Object System.Diagnostics.ProcessStartInfo
|
|
$pinfo.FileName = "$env:JAVA_BIN"
|
|
$pinfo.UseShellExecute = $false
|
|
$pinfo.Arguments = "-Dlogback.configurationFile=logback-tools.xml -cp $env:CLASSPATH org.apache.cassandra.tools.GetVersion"
|
|
$p = New-Object System.Diagnostics.Process
|
|
$p.StartInfo = $pinfo
|
|
$p.Start() | Out-Null
|
|
$p.WaitForExit()
|
|
}
|
|
|
|
#-----------------------------------------------------------------------------
|
|
Function RunCassandra([string]$foreground)
|
|
{
|
|
$cmd = @"
|
|
$env:JAVA_BIN
|
|
"@
|
|
$arg1 = $env:CASSANDRA_PARAMS
|
|
$arg2 = $env:JVM_OPTS
|
|
$arg3 = "-cp $env:CLASSPATH"
|
|
$arg4 = @"
|
|
"$env:CASSANDRA_MAIN"
|
|
"@
|
|
|
|
$proc = $null
|
|
|
|
if ($s)
|
|
{
|
|
echo "Running cassandra with: [$cmd $arg1 $arg2 $arg3 $arg4]"
|
|
}
|
|
|
|
if ($foreground)
|
|
{
|
|
$cygwin = $false
|
|
try
|
|
{
|
|
$uname = uname -o
|
|
if ($uname.CompareTo("Cygwin") -eq 0)
|
|
{
|
|
$cygwin = $true
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
# Failed at uname call, not in cygwin
|
|
}
|
|
|
|
if ($cygwin)
|
|
{
|
|
# if running on cygwin, we cannot capture ctrl+c signals as mintty traps them and then
|
|
# SIGKILLs processes, so we'll need to record our $pidfile file for future
|
|
# stop-server usage
|
|
if (!$p)
|
|
{
|
|
echo "Detected cygwin runtime environment. Adding -Dcassandra-pidfile=$pidfile to JVM params as control+c trapping on mintty is inconsistent"
|
|
$arg2 = $arg2 + " -Dcassandra-pidfile=$pidfile"
|
|
}
|
|
}
|
|
|
|
$arg2 = $arg2 + " -Dcassandra-foreground=yes"
|
|
|
|
$pinfo = New-Object System.Diagnostics.ProcessStartInfo
|
|
$pinfo.FileName = "$env:JAVA_BIN"
|
|
$pinfo.RedirectStandardInput = $true
|
|
$pinfo.UseShellExecute = $false
|
|
$pinfo.Arguments = $arg1,$arg2,$arg3,$arg4
|
|
$p = New-Object System.Diagnostics.Process
|
|
$p.StartInfo = $pinfo
|
|
$p.Start() | Out-Null
|
|
echo $p.Id > $pidfile
|
|
$p.WaitForExit()
|
|
}
|
|
else
|
|
{
|
|
if ($q)
|
|
{
|
|
$proc = Start-Process -FilePath "$cmd" -ArgumentList $arg1,$arg2,$arg3,$arg4 -PassThru -WindowStyle Hidden
|
|
}
|
|
else
|
|
{
|
|
$proc = Start-Process -FilePath "$cmd" -ArgumentList $arg1,$arg2,$arg3,$arg4 -PassThru -NoNewWindow
|
|
}
|
|
|
|
$exitCode = $?
|
|
|
|
try
|
|
{
|
|
echo $proc.Id > $pidfile
|
|
}
|
|
catch
|
|
{
|
|
echo @"
|
|
WARNING! Failed to write pidfile to $pidfile. stop-server.bat and
|
|
startup protection will not be available.
|
|
"@
|
|
echo $_.Exception.Message
|
|
exit 1
|
|
}
|
|
|
|
if (-Not $exitCode)
|
|
{
|
|
exit 1
|
|
}
|
|
}
|
|
}
|
|
|
|
#-----------------------------------------------------------------------------
|
|
Function VerifyPortsAreAvailable
|
|
{
|
|
if ($a)
|
|
{
|
|
return
|
|
}
|
|
# Need to confirm 5 different ports are available or die if any are currently bound
|
|
# From cassandra.yaml:
|
|
# storage_port
|
|
# ssl_storage_port
|
|
# native_transport_port
|
|
# rpc_port, which we'll match to rpc_address
|
|
# and from env: JMX_PORT which we cache in our environment during SetCassandraEnvironment for this check
|
|
$yamlRegex = "storage_port:|ssl_storage_port:|native_transport_port:|rpc_port"
|
|
$yaml = Get-Content "$env:CASSANDRA_CONF\cassandra.yaml"
|
|
$portRegex = ":$env:JMX_PORT |"
|
|
|
|
foreach ($line in $yaml)
|
|
{
|
|
if ($line -match $yamlRegex)
|
|
{
|
|
$sa = $line.Split(":")
|
|
$portRegex = $portRegex + ":" + ($sa[1] -replace " ","") + " |"
|
|
}
|
|
}
|
|
$portRegex = $portRegex.Substring(0, $portRegex.Length - 2)
|
|
|
|
$netstat = netstat -an
|
|
|
|
foreach ($line in $netstat)
|
|
{
|
|
if ($line -match "TCP" -and $line -match $portRegex)
|
|
{
|
|
Write-Error "Found a port already in use. Aborting startup"
|
|
Write-Error $line
|
|
Exit
|
|
}
|
|
}
|
|
}
|
|
|
|
#-----------------------------------------------------------------------------
|
|
Function ValidateArguments
|
|
{
|
|
if ($install -and $uninstall)
|
|
{
|
|
echo "Cannot install and uninstall"
|
|
exit
|
|
}
|
|
if ($help)
|
|
{
|
|
PrintUsage
|
|
}
|
|
}
|
|
|
|
#-----------------------------------------------------------------------------
|
|
Function CheckEmptyParam($param)
|
|
{
|
|
if ([String]::IsNullOrEmpty($param))
|
|
{
|
|
echo "Invalid parameter: empty value"
|
|
PrintUsage
|
|
}
|
|
}
|
|
|
|
#-----------------------------------------------------------------------------
|
|
# Populate arguments
|
|
for ($i = 0; $i -lt $args.count; $i++)
|
|
{
|
|
# Skip JVM args
|
|
if ($args[$i].StartsWith("-D") -Or $args[$i].StartsWith("-X"))
|
|
{
|
|
continue;
|
|
}
|
|
Switch($args[$i])
|
|
{
|
|
"-install" { $install = $True }
|
|
"-uninstall" { $uninstall = $True }
|
|
"-help" { PrintUsage }
|
|
"-?" { PrintUsage }
|
|
"--help" { PrintUsage }
|
|
"-v" { $v = $True }
|
|
"-f" { $f = $True }
|
|
"-s" { $s = $True }
|
|
"-p" { $p = $args[++$i]; CheckEmptyParam($p) }
|
|
"-H" { $H = $args[++$i]; CheckEmptyParam($H) }
|
|
"-E" { $E = $args[++$i]; CheckEmptyParam($E) }
|
|
"-a" { $a = $True }
|
|
"-q" { $q = $True }
|
|
default
|
|
{
|
|
"Invalid argument: " + $args[$i];
|
|
if (-Not $args[$i].startsWith("-"))
|
|
{
|
|
echo "Note: All options require -"
|
|
}
|
|
exit
|
|
}
|
|
}
|
|
}
|
|
$pidfile = "pid.txt"
|
|
|
|
Main
|