2019-10-10 00:52:42 -04:00
#!/bin/bash
# runner will replace key words in the template and generate a batch script to run.
# Keywords:
# PROCESSID = pid
# RUNNERPROCESSNAME = Runner.Listener[.exe]
# ROOTFOLDER = ./
# EXISTRUNNERVERSION = 2.100.0
# DOWNLOADRUNNERVERSION = 2.101.0
# UPDATELOG = _diag/SelfUpdate-UTC.log
# RESTARTINTERACTIVERUNNER = 0/1
runnerpid = _PROCESS_ID_
runnerprocessname = _RUNNER_PROCESS_NAME_
rootfolder = "_ROOT_FOLDER_"
existrunnerversion = _EXIST_RUNNER_VERSION_
downloadrunnerversion = _DOWNLOAD_RUNNER_VERSION_
logfile = "_UPDATE_LOG_"
restartinteractiverunner = _RESTART_INTERACTIVE_RUNNER_
2021-09-29 15:49:31 -04:00
telemetryfile = " $rootfolder /_diag/.telemetry "
2019-10-10 00:52:42 -04:00
# log user who run the script
date "+[%F %T-%4N] --------whoami--------" >> " $logfile " 2>& 1
whoami >> " $logfile " 2>& 1
date "+[%F %T-%4N] --------whoami--------" >> " $logfile " 2>& 1
# wait for runner process to exit.
date " +[%F %T-%4N] Waiting for $runnerprocessname ( $runnerpid ) to complete " >> " $logfile " 2>& 1
while [ -e /proc/$runnerpid ]
do
date " +[%F %T-%4N] Process $runnerpid still running " >> " $logfile " 2>& 1
2022-03-01 14:08:52 +01:00
" $rootfolder " /safe_sleep.sh 2
2019-10-10 00:52:42 -04:00
done
date " +[%F %T-%4N] Process $runnerpid finished running " >> " $logfile " 2>& 1
# start re-organize folders
date "+[%F %T-%4N] Sleep 1 more second to make sure process exited" >> " $logfile " 2>& 1
2022-03-01 14:08:52 +01:00
" $rootfolder " /safe_sleep.sh 1
2019-10-10 00:52:42 -04:00
# the folder structure under runner root will be
# ./bin -> bin.2.100.0 (junction folder)
# ./externals -> externals.2.100.0 (junction folder)
# ./bin.2.100.0
# ./externals.2.100.0
# ./bin.2.99.0
# ./externals.2.99.0
# by using the juction folder we can avoid file in use problem.
# if the bin/externals junction point already exist, we just need to delete the juction point then re-create to point to new bin/externals folder.
# if the bin/externals still are real folders, we need to rename the existing folder to bin.version format then create junction point to new bin/externals folder.
# check bin folder
if [ [ -L " $rootfolder /bin " && -d " $rootfolder /bin " ] ]
then
# return code 0 means it find a bin folder that is a junction folder
# we just need to delete the junction point.
date "+[%F %T-%4N] Delete existing junction bin folder" >> " $logfile "
rm " $rootfolder /bin " >> " $logfile "
if [ $? -ne 0 ]
then
date "+[%F %T-%4N] Can't delete existing junction bin folder" >> " $logfile "
mv -fv " $logfile " " $logfile .failed "
exit 1
fi
else
# otherwise, we need to move the current bin folder to bin.2.99.0 folder.
date " +[%F %T-%4N] move $rootfolder /bin $rootfolder /bin. $existrunnerversion " >> " $logfile " 2>& 1
mv -fv " $rootfolder /bin " " $rootfolder /bin. $existrunnerversion " >> " $logfile " 2>& 1
if [ $? -ne 0 ]
then
date " +[%F %T-%4N] Can't move $rootfolder /bin to $rootfolder /bin. $existrunnerversion " >> " $logfile " 2>& 1
mv -fv " $logfile " " $logfile .failed "
exit 1
fi
fi
# check externals folder
if [ [ -L " $rootfolder /externals " && -d " $rootfolder /externals " ] ]
then
# the externals folder is already a junction folder
# we just need to delete the junction point.
date "+[%F %T-%4N] Delete existing junction externals folder" >> " $logfile "
rm " $rootfolder /externals " >> " $logfile "
if [ $? -ne 0 ]
then
date "+[%F %T-%4N] Can't delete existing junction externals folder" >> " $logfile "
mv -fv " $logfile " " $logfile .failed "
exit 1
fi
else
# otherwise, we need to move the current externals folder to externals.2.99.0 folder.
date " +[%F %T-%4N] move $rootfolder /externals $rootfolder /externals. $existrunnerversion " >> " $logfile " 2>& 1
mv -fv " $rootfolder /externals " " $rootfolder /externals. $existrunnerversion " >> " $logfile " 2>& 1
if [ $? -ne 0 ]
then
date " +[%F %T-%4N] Can't move $rootfolder /externals to $rootfolder /externals. $existrunnerversion " >> " $logfile " 2>& 1
mv -fv " $logfile " " $logfile .failed "
exit 1
fi
fi
# create junction bin folder
date "+[%F %T-%4N] Create junction bin folder" >> " $logfile " 2>& 1
ln -s " $rootfolder /bin. $downloadrunnerversion " " $rootfolder /bin " >> " $logfile " 2>& 1
if [ $? -ne 0 ]
then
date "+[%F %T-%4N] Can't create junction bin folder" >> " $logfile " 2>& 1
mv -fv " $logfile " " $logfile .failed "
exit 1
fi
# create junction externals folder
date "+[%F %T-%4N] Create junction externals folder" >> " $logfile " 2>& 1
ln -s " $rootfolder /externals. $downloadrunnerversion " " $rootfolder /externals " >> " $logfile " 2>& 1
if [ $? -ne 0 ]
then
date "+[%F %T-%4N] Can't create junction externals folder" >> " $logfile " 2>& 1
mv -fv " $logfile " " $logfile .failed "
exit 1
fi
2021-09-29 15:49:31 -04:00
# fix upgrade issue with macOS when running as a service
attemptedtargetedfix = 0
2021-09-01 15:39:17 -04:00
currentplatform = $( uname | awk '{print tolower($0)}' )
2025-07-25 16:42:28 +01:00
if [ [ " $currentplatform " = = 'darwin' && $restartinteractiverunner -eq 0 ] ] ; then
2021-09-29 15:49:31 -04:00
# We needed a fix for https://github.com/actions/runner/issues/743
2022-02-14 15:06:08 +01:00
# We will recreate the ./externals/nodeXY/bin/node of the past runner version that launched the runnerlistener service
2021-09-29 15:49:31 -04:00
# Otherwise mac gatekeeper kills the processes we spawn on creation as we are running a process with no backing file
# We need the pid for the nodejs loop, get that here, its the parent of the runner C# pid
# assumption here is only one process is invoking rootfolder/runsvc.sh
procgroup = $( ps x -o pgid,command | grep " $rootfolder /runsvc.sh " | grep -v grep | awk '{print $1}' )
if [ [ $? -eq 0 && -n " $procgroup " ] ]
2021-09-01 15:39:17 -04:00
then
2021-09-29 15:49:31 -04:00
# inspect the open file handles to find the node process
# we can't actually inspect the process using ps because it uses relative paths and doesn't follow symlinks
2025-07-17 02:00:17 +01:00
# Try finding node24 first, then fallback to earlier versions if needed
nodever = "node24"
2022-02-14 15:06:08 +01:00
path = $( lsof -a -g " $procgroup " -F n | grep $nodever /bin/node | grep externals | tail -1 | cut -c2-)
2025-07-17 02:00:17 +01:00
if [ [ $? -ne 0 || -z " $path " ] ] # Fallback if RunnerService.js was started with node20
2022-02-14 15:06:08 +01:00
then
2025-07-17 02:00:17 +01:00
nodever = "node20"
2022-02-14 15:06:08 +01:00
path = $( lsof -a -g " $procgroup " -F n | grep $nodever /bin/node | grep externals | tail -1 | cut -c2-)
2025-07-17 02:00:17 +01:00
if [ [ $? -ne 0 || -z " $path " ] ] # Fallback if RunnerService.js was started with node16
then
nodever = "node16"
path = $( lsof -a -g " $procgroup " -F n | grep $nodever /bin/node | grep externals | tail -1 | cut -c2-)
2025-07-25 16:42:28 +01:00
if [ [ $? -ne 0 || -z " $path " ] ] # Fallback if RunnerService.js was started with node12
then
nodever = "node12"
path = $( lsof -a -g " $procgroup " -F n | grep $nodever /bin/node | grep externals | tail -1 | cut -c2-)
fi
2024-10-16 22:42:43 -04:00
fi
2022-02-14 15:06:08 +01:00
fi
2021-09-29 15:49:31 -04:00
if [ [ $? -eq 0 && -n " $path " ] ]
then
# trim the last 5 characters of the path '/node'
trimmedpath = $( dirname " $path " )
if [ [ $? -eq 0 && -n " $trimmedpath " ] ]
then
attemptedtargetedfix = 1
# Create the path if it does not exist
if [ [ ! -e " $path " ] ]
then
date " +[%F %T-%4N] Creating fallback node at path $path " >> " $logfile " 2>& 1
mkdir -p " $trimmedpath "
2022-02-14 15:06:08 +01:00
cp " $rootfolder /externals/ $nodever /bin/node " " $path "
2021-09-29 15:49:31 -04:00
else
date " +[%F %T-%4N] Path for fallback node exists, skipping creating $path " >> " $logfile " 2>& 1
fi
else
date " +[%F %T-%4N] DarwinRunnerUpgrade: Failed to trim runner path. TrimmedPath: $trimmedpath , path: $path , pgid: $procgroup , root: $rootfolder " >> " $logfile " 2>& 1
date " +[%F %T-%4N] DarwinRunnerUpgrade: Failed to trim runner path. TrimmedPath: $trimmedpath , path: $path , pgid: $procgroup , root: $rootfolder " >> " $telemetryfile " 2>& 1
fi
else
date " +[%F %T-%4N] DarwinRunnerUpgrade: Failed to find runner path. Path: $path , pgid: $procgroup , root: $rootfolder " >> " $logfile " 2>& 1
date " +[%F %T-%4N] DarwinRunnerUpgrade: Failed to find runner path. Path: $path , pgid: $procgroup , root: $rootfolder " >> " $telemetryfile " 2>& 1
fi
else
2021-10-19 10:15:37 -04:00
runproc = $( ps x -o pgid,command | grep "run.sh" | grep -v grep | awk '{print $1}' )
if [ [ $? -eq 0 && -n " $runproc " ] ]
then
date "+[%F %T-%4N] Running as ephemeral using run.sh, no need to recreate node folder" >> " $logfile " 2>& 1
else
2021-09-29 15:49:31 -04:00
date " +[%F %T-%4N] DarwinRunnerUpgrade: Failed to find runner pgid. pgid: $procgroup , root: $rootfolder " >> " $logfile " 2>& 1
date " +[%F %T-%4N] DarwinRunnerUpgrade: Failed to find runner pgid. pgid: $procgroup , root: $rootfolder " >> " $telemetryfile " 2>& 1
fi
2021-09-01 15:39:17 -04:00
fi
fi
2024-10-16 22:42:43 -04:00
# update runsvc.sh
if [ -f " $rootfolder /runsvc.sh " ]
then
date "+[%F %T-%4N] Update runsvc.sh" >> " $logfile " 2>& 1
cat " $rootfolder /bin/runsvc.sh " > " $rootfolder /runsvc.sh "
if [ $? -ne 0 ]
then
date " +[%F %T-%4N] Can't update $rootfolder /runsvc.sh using $rootfolder /bin/runsvc.sh " >> " $logfile " 2>& 1
mv -fv " $logfile " " $logfile .failed "
exit 1
fi
fi
2019-10-10 00:52:42 -04:00
date "+[%F %T-%4N] Update succeed" >> " $logfile "
2022-08-08 23:37:43 +02:00
touch update.finished
date "+[%F %T-%4N] update.finished file creation succeed" >> " $logfile "
2019-10-10 00:52:42 -04:00
# rename the update log file with %logfile%.succeed/.failed/succeedneedrestart
# runner service host can base on the log file name determin the result of the runner update
date " +[%F %T-%4N] Rename $logfile to be $logfile .succeed " >> " $logfile " 2>& 1
mv -fv " $logfile " " $logfile .succeed " >> " $logfile " 2>& 1
# restart interactive runner if needed
if [ $restartinteractiverunner -ne 0 ]
then
date "+[%F %T-%4N] Restarting interactive runner" >> " $logfile .succeed " 2>& 1
" $rootfolder /run.sh " &
fi