Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 79a1db6

Browse files
committedOct 18, 2024·
githubrunner: update
1 parent 7522845 commit 79a1db6

File tree

10 files changed

+464
-329
lines changed

10 files changed

+464
-329
lines changed
 

‎Makefile

+7-3
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,9 @@ try_docker_integration_test:
4545
./integration_tests.sh \
4646
'
4747

48+
export PATH := $(PATH):$(HOME)/.local/bin/
4849
run_githubrunner_locally:
49-
. ./.env && nomaddtools githubrunner -c ./deploy/githubrunner.yml $(ARGS) run
50+
. ./.env && nomadtools githubrunner -c ./deploy/githubrunner.yml $(ARGS) run
5051

5152
run_githubrunner:
5253
. ./.env && nomadtools watch run \
@@ -56,6 +57,9 @@ run_githubrunner:
5657
-var VERBOSE=$(VERBOSE) \
5758
./deploy/nomadtools-githubrunner.nomad.hcl
5859

60+
remote_run_githubrunner_locally:
61+
. ~/.env_nomad && $(MAKE) run_githubrunner_locally
62+
5963
weles_run_githubrunner:
60-
,rsync --delete $(CURDIR)/ kamil@weles:./myprojects/nomad-tools/
61-
ssh kamil@weles make -C ./myprojects/nomad-tools/ run_githubrunner
64+
,rsync --no-group --no-owner $(CURDIR)/ kamil@weles:./myprojects/nomad-tools/
65+
ssh -t kamil@weles make -C ./myprojects/nomad-tools/ "ARGS=$(ARGS)" run_githubrunner_locally

‎deploy/githubrunner.yml

+4-1
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,13 @@ repos:
55
- Kamilcuk/runnertest
66
nomad:
77
namespace: github
8+
# purge: false
9+
purge: true
810
runner_inactivity_timeout: 1w
911
loop: 10
1012
# loop: 60
1113
template_context:
12-
docker: host
14+
# docker: host
15+
docker: dind
1316
cachedir: /home/kamil/myprojects/nomad-tools/deploy/cachedir
1417

‎src/nomad_tools/common_base.py

+14-4
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import shlex
66
import subprocess
77
import sys
8-
from typing import Any, Callable, Generic, Iterable, List, TypeVar
8+
from typing import Any, Callable, Generic, Iterable, List, TypeVar, cast
99

1010
NOMAD_NAMESPACE = "NOMAD_NAMESPACE"
1111

@@ -97,9 +97,6 @@ def print():
9797
print(f" {line}")
9898

9999

100-
###############################################################################
101-
102-
103100
T = TypeVar("T")
104101
R = TypeVar("R")
105102

@@ -125,3 +122,16 @@ def __get__(self, instance: T, owner) -> R:
125122
setattr(instance, self._attr_name, attr)
126123

127124
return attr
125+
126+
127+
def dict_remove_none(data: T) -> T:
128+
"""Remove all elements that are set to None"""
129+
if isinstance(data, dict):
130+
ret = {
131+
k: dict_remove_none(v) for k, v in data.items() if v is not None and v != {}
132+
}
133+
elif isinstance(data, list):
134+
ret = [dict_remove_none(e) for e in data if e is not None]
135+
else:
136+
ret = data
137+
return cast(T, ret)

‎src/nomad_tools/entry_githubrunner/default.nomad.hcl

+26-20
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
job "{{ param.JOB_NAME }}" {
2+
{{ param.extra_job }}
3+
24
type = "batch"
35
meta {
46
INFO = <<EOF
@@ -18,6 +20,8 @@ EOF
1820
{% endif %}
1921
}
2022
group "{{ param.JOB_NAME }}" {
23+
{{ param.extra_group }}
24+
2125
reschedule {
2226
attempts = 0
2327
unlimited = false
@@ -28,12 +32,16 @@ EOF
2832
}
2933

3034
task "{{ param.JOB_NAME }}" {
35+
{{ param.extra_task }}
36+
3137
driver = "docker"
3238
kill_timeout = "5m"
3339
config {
40+
{{ param.extra_config }}
41+
3442
image = "{{ param.image | default('myoung34/github-runner:latest') }}"
3543
init = true
36-
entrypoint = ["bash", "/local/startscript.sh"]
44+
entrypoint = ["bash", "/local/nomadtools_startscript.sh"]
3745

3846
{% if param.cachedir %}
3947
mount {
@@ -53,18 +61,6 @@ EOF
5361
target = "/var/run/docker.sock"
5462
}
5563
{% endif %}
56-
57-
{{ param.extra_config }}
58-
}
59-
template {
60-
destination = "local/startscript.sh"
61-
change_mode = "noop"
62-
left_delimiter = "QWEQWEQEWQEEQ"
63-
right_delimiter = "ASDASDADSADSA"
64-
data = <<EOF
65-
{% if not param.startscript %}{{ 1/0 }}{% endif %}
66-
{{ escape(param.startscript) }}
67-
EOF
6864
}
6965
env {
7066
ACCESS_TOKEN = "{{ CONFIG.github.token }}"
@@ -73,18 +69,20 @@ EOF
7369
LABELS = "{{ param.LABELS }}"
7470
RUNNER_SCOPE = "repo"
7571
DISABLE_AUTO_UPDATE = "true"
76-
# RUN_AS_ROOT = "false"
77-
78-
{% if param.ephemeral == "true" %}
72+
{% if not param.RUN_AS_ROOT %}
73+
RUN_AS_ROOT = "false"
74+
{% endif %}
75+
{% if param.ephemeral %}
7976
EPHEMERAL = "true"
8077
{% endif %}
8178
{% if param.docker == "dind" %}
8279
START_DOCKER_SERVICE = "true"
8380
{% endif %}
8481
{% if param.debug %}
85-
DEBUG = "true"
82+
DEBUG_OUTPUT = "true"
8683
{% endif %}
8784
}
85+
{% if param.cpu or param.mem or param.maxmem %}
8886
resources {
8987
{% if param.cpu %}
9088
cpu = {{ param.cpu }}
@@ -96,9 +94,17 @@ EOF
9694
memory_max = {{ param.maxmem }}
9795
{% endif %}
9896
}
99-
{{ param.extra_task }}
97+
{% endif %}
98+
template {
99+
destination = "local/nomadtools_startscript.sh"
100+
change_mode = "noop"
101+
left_delimiter = "QWEQWEQEWQEEQ"
102+
right_delimiter = "ASDASDADSADSA"
103+
data = <<EOF
104+
{% if not param.startscript %}{{ 1/0 }}{% endif %}
105+
{{ escape(param.startscript) }}
106+
EOF
107+
}
100108
}
101-
{{ param.extra_group }}
102109
}
103-
{{ param.extra_job }}
104110
}

‎src/nomad_tools/entry_githubrunner/entry_githubrunner.py

+350-229
Large diffs are not rendered by default.

‎src/nomad_tools/entry_githubrunner/startscript.sh

+37-50
Original file line numberDiff line numberDiff line change
@@ -23,36 +23,36 @@ r() {
2323
"$@"
2424
}
2525

26-
choosedirin() {
26+
choose_cachedir() {
2727
local dir
2828
dir="$1"
2929
shift
30-
if ((!$#)); then fatal "missing arguments"; fi
30+
if (($#)); then fatal "too many arguments"; fi
3131
#
32-
local i ret=0
32+
info "Picking cache directory inside $dir"
33+
declare -g CACHEDIR
34+
local i
3335
for ((i = 0; ; i++)); do
3436
r mkdir -vp "$dir/$i"
35-
{
36-
if flock -n 249; then
37-
info "Using $dir/$i directory"
38-
info "+ $* $dir/$i"
39-
r "$@" "$dir/$i" || ret=$?
40-
return "$ret"
41-
fi
42-
} 249>"$dir/$i/lockfile"
37+
exec 249>"$dir/$i/lockfile"
38+
if flock --verbose -n 249; then
39+
info "Using $dir/$i as cache directory"
40+
# When was the directory last used? See timestamp of lockfile.
41+
touch "$dir/$i/lockfile"
42+
CACHEDIR="$dir/$i"
43+
break
44+
fi
45+
exec 249>&-
4346
done
4447
}
4548

46-
dir_is_empty() {
47-
[[ -n "$(ls -A "$1")" ]]
48-
}
49-
50-
configure_dockerd() {
49+
dockerd_use_dir() {
5150
local dir
5251
dir="$1"
5352
shift
5453
if (($#)); then fatal "too many args"; fi
5554
#
55+
info "Configuring docker daemon to use $dir/docker directory"
5656
dir=$(readlink -f "$dir/docker")
5757
local dockersock
5858
dockersock=/var/run/docker.sock
@@ -68,55 +68,42 @@ configure_dockerd() {
6868
fi
6969
}
7070

71-
configure_runner() {
71+
github_runner_use_dir() {
7272
local dir
7373
dir="$1"
7474
shift
7575
if (($#)); then fatal "too many args"; fi
7676
#
7777
local tmp
78-
tmp=$(readlink -f "$dir/configure")
79-
r mkdir -vp "$tmp"
80-
r export RUNNER_WORKDIR="$tmp"
81-
info "RUNNER_WORKDIR=$RUNNER_WORKDIR"
82-
#
78+
info "Moving Github runner cache to $dir/hostedtoolscache"
8379
tmp=$(readlink -f "$dir/hostedtoolcache")
8480
if [[ -e /opt/hostedtoolcache/ ]]; then
8581
r rmdir -v /opt/hostedtoolcache/
8682
fi
8783
r mkdir -vp "$tmp"
8884
r ln -nvfs "$tmp" /opt/hostedtoolcache
8985
r export AGENT_TOOLSDIRECTORY="$tmp"
90-
info "AGENT_TOOLSDIRECTORY=$tmp | /opt/hostedtoolcache -> $tmp"
91-
}
92-
93-
configure() {
94-
local dir
95-
dir="$1"
96-
shift
97-
if (($#)); then fatal "too many args"; fi
9886
#
99-
configure_dockerd "$dir"
100-
configure_runner "$dir"
87+
info "Moving Github runner workdir to $dir/configure"
88+
tmp=$(readlink -f "$dir/configure")
89+
r mkdir -vp "$tmp"
90+
r export RUNNER_WORKDIR="$tmp"
10191
}
10292

103-
save_stdout_in_fd3_and_redirect_stdout_stderr() {
104-
exec 3>&1 1>&2
105-
}
93+
###############################################################################
94+
# main
10695

107-
restore_stdout_from_fd3() {
108-
exec 1>&3 3>&-
109-
}
110-
111-
save_stdout_in_fd3_and_redirect_stdout_stderr
112-
if (($#)); then fatal "too many args"; fi
113-
if [[ ! -e /.dockerenv ]]; then fatal "Not in docker"; fi
114-
if mountpoint /_work; then
115-
choosedirin /_work configure
116-
else
117-
info "/_work is not a mountpoint"
118-
fi
119-
info 'start github runner'
120-
restore_stdout_from_fd3
96+
{
97+
if (($#)); then fatal "too many args"; fi
98+
if [[ ! -e /.dockerenv ]]; then fatal "Not in docker"; fi
99+
if mountpoint /_work; then
100+
choose_cachedir /_work
101+
dockerd_use_dir "$CACHEDIR"
102+
github_runner_use_dir "$CACHEDIR"
103+
else
104+
info "/_work is not a mountpoint"
105+
fi
106+
info 'start github runner'
107+
} 2>&1
121108
# synchronize with https://github.com/myoung34/docker-github-actions-runner/blob/master/Dockerfile#L25
122-
r exec /entrypoint.sh ./bin/Runner.Listener run --startuptype service
109+
r exec /entrypoint.sh ./bin/Runner.Listener run --startuptype service "$@"

‎src/nomad_tools/entry_go.py

+1-14
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
import dotenv
2323

2424
from . import entry_watch, taskexec
25-
from .common_base import NOMAD_NAMESPACE, quotearr
25+
from .common_base import NOMAD_NAMESPACE, quotearr, dict_remove_none
2626
from .common_click import EPILOG, help_h_option
2727
from .common_nomad import namespace_option
2828

@@ -35,19 +35,6 @@ def trueornone(x: Optional[T]) -> Optional[T]:
3535
return x if x else None
3636

3737

38-
def dict_remove_none(data: T) -> T:
39-
"""Remove all elements that are set to None"""
40-
if isinstance(data, dict):
41-
ret = {
42-
k: dict_remove_none(v) for k, v in data.items() if v is not None and v != {}
43-
}
44-
elif isinstance(data, list):
45-
ret = [dict_remove_none(e) for e in data if e is not None]
46-
else:
47-
ret = data
48-
return cast(T, ret)
49-
50-
5138
@contextlib.contextmanager
5239
def tempfile_with(txt: str):
5340
with tempfile.NamedTemporaryFile("w") as f:

‎src/nomad_tools/mytabulate.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
from typing import List
22

33

4-
def mytabulate(data: List[List[str]]) -> str:
4+
def mytabulate(data: List[List[str]], transpose: bool = False) -> str:
55
"""Print list of list of strings in tabulated form in columns"""
66
if not data:
77
return ""
8+
if transpose:
9+
data = list(map(list, zip(*data)))
810
lens: List[int] = [max(len(str(x)) for x in y) for y in data]
911
if not lens:
1012
return ""

‎src/nomad_tools/nomadlib/datadict.py

+7-5
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,14 @@ def all_annotations(cls) -> ChainMap[str, Type]:
2525

2626

2727
def _init_value(classname: str, dstname: str, dsttype: Any, srcval: Any):
28-
# print(f"Constructing {aname} with type {atype} from {val}")
29-
dstorigin = get_origin(dsttype)
30-
31-
def msg() -> str:
28+
def msg(prefix: str = "Error when ") -> str:
3229
return (
33-
f"Error when constructing class {classname!r} expected type {dsttype!r} with origin {dstorigin!r}"
30+
f"{prefix}constructing class {classname!r} expected type {dsttype!r} with origin {dstorigin!r}"
3431
f" for field {dstname!r}, but received {type(srcval)} with value: {srcval!r}"
3532
)
3633

34+
dstorigin = get_origin(dsttype)
35+
# print(msg("DATADICT INFO "))
3736
try:
3837
if dstorigin is list:
3938
assert type(srcval) is dstorigin, msg()
@@ -58,10 +57,13 @@ def msg() -> str:
5857
return dsttype(srcval)
5958
elif issubclass(dsttype, enum.Enum):
6059
return dsttype(srcval)
60+
# elif callable(dsttype):
61+
# return dsttype(srcval)
6162
except Exception:
6263
log.exception(f"DATADICT:ERROR: {msg()}")
6364
if strict:
6465
raise
66+
raise
6567
return srcval
6668

6769

‎src/nomad_tools/nomadlib/types.py

+15-2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
import dateutil.parser
1010

11+
from .tools import ns2dt
1112
from .datadict import DataDict
1213

1314
log = logging.getLogger(__name__)
@@ -125,6 +126,9 @@ class Job(_BothJobAndJobsJob):
125126
TaskGroups: List[JobTaskGroup]
126127
SubmitTime: int
127128

129+
def SubmitTime_dt(self):
130+
return ns2dt(self.SubmitTime)
131+
128132
def description(self):
129133
return f"{self.ID}#{self.Version}@{self.Namespace}"
130134

@@ -234,6 +238,9 @@ class Eval(DataDict):
234238
"""May be missing. No idea when"""
235239
TriggeredBy: Optional[str] = None
236240

241+
def ModifyTime_dt(self):
242+
return ns2dt(self.ModifyTime)
243+
237244
def is_pending_or_blocked(self):
238245
return self.Status in [EvalStatus.pending, EvalStatus.blocked]
239246

@@ -381,6 +388,9 @@ class Alloc(DataDict):
381388
def strshort(self):
382389
return f"{self.__class__.__name__}({self.ID[:6]} {strdict(JobVersion=self.JobVersion)})"
383390

391+
def ModifyTime_dt(self):
392+
return ns2dt(self.ModifyTime)
393+
384394
def get_taskstates(self) -> Dict[str, AllocTaskState]:
385395
"""The same as TaskStates but returns an empty dict in case the field is None"""
386396
return self.get("TaskStates") or {}
@@ -403,11 +413,14 @@ def is_pending(self):
403413
def is_running(self):
404414
return self.ClientStatus == AllocClientStatus.running
405415

406-
def is_running_started(self):
407-
return self.is_running() and any(
416+
def any_was_started(self):
417+
return any(
408418
taskstate.was_started() for taskstate in self.get_taskstates().values()
409419
)
410420

421+
def is_running_started(self):
422+
return self.is_running() and self.any_was_started()
423+
411424
def is_finished(self):
412425
return not self.is_pending_or_running()
413426

0 commit comments

Comments
 (0)
Please sign in to comment.