@@ -256,74 +256,106 @@ function mr::downloadRunner {
256256# $6: extra labels, optional
257257# $7: group, defaults to `default`
258258# $8: lines to set in runner's '.env' files, optional
259+ # $9: count of runners, optional, defaults to 1
259260# $?: 0 if successful and non-zero otherwise
260261function mr::addRunner {
261- local user=" $1 " enterprise=" $2 " org=" $3 " repo=" $4 " token=" $5 " extraLabels=" $6 " group=" ${7:- default} " dotenv=" $8 " tarpath=' '
262+ local username=" $1 " enterprise=" $2 " org=" $3 " repo=" $4 " token=" $5 " extraLabels=" $6 " group=" ${7:- default} " dotenv=" $8 " tarpath=' '
263+ local -i count=" ${9:- 1} "
262264 str::allVarsNotEmpty enterprise org || return $?
263265
266+ [[ -n " $username " ]] && (( count > 1 )) && {
267+ log::_ ERROR " Count must be 1 when username is given!"
268+ return 1
269+ }
270+
264271 [[ -z " $token " ]] && { token=" $( mr::pat2token " $enterprise " " $org " " $repo " ) " || return $? ; }
265272 tarpath=" $( mr::downloadRunner) " || return $?
266- user=" $( mr::addUser " $user " ) " || return $?
267-
268- local name=" $user @$HOSTNAME "
269-
270- local labels=" controller:${MR_URL# https:// } ,username:$user ,hostname:$HOSTNAME "
271- [[ -r /etc/os-release ]] && labels=" $labels ,os:$( source /etc/os-release && echo " $ID -$VERSION_ID " ) "
272- [[ -n " $extraLabels " ]] && labels=" $labels ,$extraLabels "
273-
274- local url=' '
275- if [[ -n " $enterprise " ]]; then
276- url=" $MR_GITHUB_BASEURL /enterprises/$enterprise "
277- labels=" $labels ,$enterprise "
278- elif [[ -z " $repo " ]]; then
279- url=" $MR_GITHUB_BASEURL /$org "
280- labels=" $labels ,$org "
281- else
282- url=" $MR_GITHUB_BASEURL /$org /$repo "
283- labels=" $labels ,$org /$repo "
284- fi
285273
286- log::_ INFO " Adding runner into local user '$user ' for $url "
287- run::logFailed sudo su --login " $user " -- -eo pipefail << -__
288- mkdir -p runner/mr.d && cd runner/mr.d
289- echo -n '$enterprise ' > enterprise && echo -n '$org ' > org && echo -n '$repo ' > repo && echo -n '$url ' > url
290- echo -n '$name ' > name && echo -n '$labels ' > labels && echo -n '$tarpath ' > tarpath
291- cd .. && tar -xzf "$tarpath "
292- echo "$dotenv " >> .env
293- ./config.sh --unattended --replace --url '$url ' --token '$token ' --name '$name ' --labels '$labels ' --runnergroup '$group '
294- sudo ./svc.sh install '$user '
295- if [[ "$( getenforce 2> /dev/null) " == "Enforcing" ]]; then
296- chcon -t bin_t ./runsvc.sh # https://github.com/vbem/multi-runners/issues/9
274+ local commonLabels=" controller:${MR_URL# https:// } ,hostname:$HOSTNAME "
275+ commonLabels+=" ,createdtime:$( date --iso-8601=sec) "
276+ [[ -r /etc/os-release ]] && commonLabels+=" ,os:$( source /etc/os-release && echo " $ID -$VERSION_ID " ) "
277+ [[ -n " $extraLabels " ]] && commonLabels+=" ,$extraLabels "
278+
279+ for i in $( seq 1 " $count " ) ; do
280+ user=" $( mr::addUser " $username " ) " || return $?
281+ local name=" $user @$HOSTNAME "
282+ local labels=" $commonLabels ,username:$user "
283+ local url=' '
284+ if [[ -n " $enterprise " ]]; then
285+ url=" $MR_GITHUB_BASEURL /enterprises/$enterprise "
286+ labels+=" ,$enterprise "
287+ elif [[ -z " $repo " ]]; then
288+ url=" $MR_GITHUB_BASEURL /$org "
289+ labels+=" ,$org "
290+ else
291+ url=" $MR_GITHUB_BASEURL /$org /$repo "
292+ labels+=" ,$org /$repo "
297293 fi
298- sudo ./svc.sh start
294+
295+ log::_ INFO " Installing runner $i in local user '$user ' for $url "
296+ run::logFailed sudo su --login " $user " -- -eo pipefail << -__
297+ mkdir -p runner/mr.d && cd runner/mr.d
298+ echo -n '$enterprise ' > enterprise && echo -n '$org ' > org && echo -n '$repo ' > repo && echo -n '$url ' > url
299+ echo -n '$name ' > name && echo -n '$labels ' > labels && echo -n '$tarpath ' > tarpath
300+ cd .. && tar -xzf "$tarpath "
301+ echo "$dotenv " >> .env
302+ ./config.sh --unattended --replace --url '$url ' --token '$token ' --name '$name ' --labels '$labels ' --runnergroup '$group '
303+ sudo ./svc.sh install '$user '
304+ if [[ "$( getenforce 2> /dev/null) " == "Enforcing" ]]; then
305+ chcon -t bin_t ./runsvc.sh # https://github.com/vbem/multi-runners/issues/9
306+ fi
307+ sudo ./svc.sh start
299308__
309+ log::failed $? " Failed installing runner $i in local user '$user ' for $url !" || return $?
310+ done
300311}
301312
302313# Delete GitHub Actions Runner by local username
303- # $1: username
314+ # $1: username, option
304315# $2: enterprise, optional
305316# $3: organization, optional
306317# $4: repository, optional
307318# $5: runner registration token, optional
319+ # $6: count of runners, optional, defaults to 0 (all)
308320# $?: 0 if successful and non-zero otherwise
309321function mr::delRunner {
310322 local user=" $1 " enterprise=" $2 " org=" $3 " repo=" $4 " token=" $5 "
311- str::anyVarNotEmpty user || return $?
323+ local -i count= " ${6 :- 0} "
312324
313- if [[ -z " $token " ]]; then
314- [[ -z " $enterprise " ]] && enterprise=" $( run::logFailed sudo -Hiu " $user " -- cat runner/mr.d/enterprise) "
315- [[ -z " $org " ]] && org=" $( run::logFailed sudo -Hiu " $user " -- cat runner/mr.d/org) "
316- [[ -z " $repo " ]] && repo=" $( run::logFailed sudo -Hiu " $user " -- cat runner/mr.d/repo) "
317- token=" $( mr::pat2token " $enterprise " " $org " " $repo " ) "
325+ local -a removals=()
326+ if [[ -n " $user " ]]; then
327+ removals+=(" $user " )
328+ else
329+ existing=" $( run::logFailed getent group ' runners' | cut -d: -f4 | tr ' ,' ' \n' | sort -g) " || return $?
330+ while read -r each; do
331+ [[ -z " $each " ]] && continue
332+ (( count != 0 )) && (( ${# removals[@]} >= count)) && break
333+ each_enterprise=" $( run::logFailed sudo -Hiu " $each " -- cat runner/mr.d/enterprise) "
334+ each_org=" $( run::logFailed sudo -Hiu " $each " -- cat runner/mr.d/org) "
335+ each_repo=" $( run::logFailed sudo -Hiu " $each " -- cat runner/mr.d/repo) "
336+ each_url=" $( run::logFailed sudo -Hiu " $each " -- cat runner/mr.d/url) "
337+ if [[ " $enterprise " == " $each_enterprise " && " $org " == " $each_org " && " $repo " == " $each_repo " ]]; then
338+ log::_ DEBUG " Found local user '$each ' to delete for $each_url "
339+ removals+=(" $each " )
340+ fi
341+ done <<< " $existing"
318342 fi
319343
320- log::_ INFO " Deleting runner and local user '$user ' with enterprise='$enterprise ' org='$org ' repo='$repo '"
321- run::logFailed sudo su --login " $user " -- << -__
322- cd runner
323- sudo ./svc.sh stop && sudo ./svc.sh uninstall
324- ./config.sh remove --token '$token '
344+ for user in " ${removals[@]} " ; do
345+ log::_ INFO " Deleting runner in local user '$user '"
346+ if [[ -z " $token " ]]; then
347+ enterprise=" $( run::logFailed sudo -Hiu " $user " -- cat runner/mr.d/enterprise) "
348+ org=" $( run::logFailed sudo -Hiu " $user " -- cat runner/mr.d/org) "
349+ repo=" $( run::logFailed sudo -Hiu " $user " -- cat runner/mr.d/repo) "
350+ token=" $( mr::pat2token " $enterprise " " $org " " $repo " ) "
351+ fi
352+ run::logFailed sudo su --login " $user " -- << -__
353+ cd runner
354+ sudo ./svc.sh stop && sudo ./svc.sh uninstall
355+ ./config.sh remove --token '$token '
325356__
326- run::log sudo userdel -rf " $user " || return $?
357+ run::log sudo userdel -rf " $user "
358+ done
327359}
328360
329361# List all existing runners
@@ -364,8 +396,10 @@ Environment variables:
364396Sub-commands:
365397 add Add one self-hosted runner on this host
366398 e.g. ${BASH_SOURCE[0]} add --org ORG --repo REPO --labels cloud:ali,region:cn-shanghai
399+ e.g. ${BASH_SOURCE[0]} add --org ORG --count 3
367400 del Delete one self-hosted runner on this host
368401 e.g. ${BASH_SOURCE[0]} del --user runner-1
402+ e.g. ${BASH_SOURCE[0]} del --org ORG --count 3
369403 list List all runners on this host
370404 e.g. ${BASH_SOURCE[0]} list
371405 download Download GitHub Actions Runner release tar to /tmp/
@@ -383,6 +417,7 @@ Options:
383417 --group Runner group for the runner
384418 --token Runner registration token, takes precedence over MR_GITHUB_PAT
385419 --dotenv The lines to set in runner's '.env' files
420+ --count The number to add or del, optional, defaults to 1 for add and all for del
386421 -h --help Show this help.
387422"
388423declare -rg HELP
@@ -391,10 +426,10 @@ declare -rg HELP
391426# $?: 0 if successful and non-zero otherwise
392427function mr::main {
393428 local getopt_output=' ' subCmd=' '
394- local org=' ' repo=' ' user=' ' labels=' ' token=' ' group=' ' dotenv=' '
429+ local org=' ' repo=' ' user=' ' labels=' ' token=' ' group=' ' dotenv=' ' count= ' '
395430
396431 # parse options into variables
397- getopt_output=" $( getopt -o h -l help,enterprise:,org:,repo:,user:,labels:,token:,group:,dotenv: -n " $FILE_THIS " -- " $@ " ) "
432+ getopt_output=" $( getopt -o h -l help,enterprise:,org:,repo:,user:,labels:,token:,group:,dotenv:,count: -n " $FILE_THIS " -- " $@ " ) "
398433 log::failed $? " getopt failed!" || return $?
399434 eval set -- " $getopt_output "
400435
@@ -433,6 +468,10 @@ function mr::main {
433468 dotenv+=" $2 " $' \n '
434469 shift 2
435470 ;;
471+ --count)
472+ count=" $2 "
473+ shift 2
474+ ;;
436475 --)
437476 shift
438477 break
@@ -448,8 +487,8 @@ function mr::main {
448487 subCmd=" $1 "
449488 shift
450489 case " $subCmd " in
451- add) mr::addRunner " $user " " $enterprise " " $org " " $repo " " $token " " $labels " " $group " " $dotenv " ;;
452- del) mr::delRunner " $user " " $enterprise " " $org " " $repo " " $token " ;;
490+ add) mr::addRunner " $user " " $enterprise " " $org " " $repo " " $token " " $labels " " $group " " $dotenv " " $count " ;;
491+ del) mr::delRunner " $user " " $enterprise " " $org " " $repo " " $token " " $count " ;;
453492 list) mr::listRunners ;;
454493 status) mr::statusRunner " $user " ;;
455494 download) mr::downloadRunner ;;
0 commit comments