diff --git a/runner_manager/bin/startup.sh b/runner_manager/bin/startup.sh index 88ca7c76..01b7c151 100755 --- a/runner_manager/bin/startup.sh +++ b/runner_manager/bin/startup.sh @@ -54,11 +54,15 @@ function job_started { sleep 5 done fi + # Run bash injected through runner group config + bash /opt/runner/job_started_script.sh echo "Done" } function job_completed { # This function is called when the job is completed + # Run bash injected through runner group config + bash /opt/runner/job_completed_script.sh echo "Job completed" } @@ -126,6 +130,14 @@ function setup_runner { sudo -H -u actions bash -c "nohup /home/actions/actions-runner/run.sh --jitconfig \"${JIT_CONFIG}\" 2>/home/actions/actions-runner/logs &" fi + cat </opt/runner/job_started_script.sh +${RUNNER_JOB_STARTED_SCRIPT} +EOF + + cat </opt/runner/job_completed_script.sh +${RUNNER_JOB_COMPLETED_SCRIPT} +EOF + } function install_docker { diff --git a/runner_manager/models/backend.py b/runner_manager/models/backend.py index 6a7c56dc..5cd411df 100644 --- a/runner_manager/models/backend.py +++ b/runner_manager/models/backend.py @@ -42,6 +42,8 @@ class RunnerEnv(BaseModel): RUNNER_GROUP: Optional[str] = None RUNNER_REDHAT_USERNAME: Optional[str] = None RUNNER_REDHAT_PASSWORD: Optional[str] = None + RUNNER_JOB_STARTED_SCRIPT: Optional[str] = "" + RUNNER_JOB_COMPLETED_SCRIPT: Optional[str] = "" class InstanceConfig(BaseSettings): @@ -63,6 +65,8 @@ def runner_env(self, runner: Runner) -> RunnerEnv: RUNNER_REDHAT_PASSWORD=( self.redhat_password if self.redhat_password else None ), + RUNNER_JOB_STARTED_SCRIPT=runner.job_started_script, + RUNNER_JOB_COMPLETED_SCRIPT=runner.job_completed_script, ) def template_startup(self, runner: Runner) -> str: diff --git a/runner_manager/models/runner.py b/runner_manager/models/runner.py index 8d4d241a..9892f86e 100644 --- a/runner_manager/models/runner.py +++ b/runner_manager/models/runner.py @@ -70,6 +70,8 @@ class Runner(BaseModel): organization: str = Field(default=None, index=True, description="Organization name") created_at: Optional[datetime] started_at: Optional[datetime] + job_started_script: Optional[str] = "" + job_completed_script: Optional[str] = "" def __str__(self): return f"{self.name} (status: {self.status}, busy: {self.busy})" diff --git a/runner_manager/models/runner_group.py b/runner_manager/models/runner_group.py index f84e78ff..f8172772 100644 --- a/runner_manager/models/runner_group.py +++ b/runner_manager/models/runner_group.py @@ -44,6 +44,8 @@ class BaseRunnerGroup(PydanticBaseModel): max: Optional[int] = Field(ge=1, default=20) min: Optional[int] = Field(ge=0, default=0) labels: List[str] + job_started_script: Optional[str] = "" + job_completed_script: Optional[str] = "" backend: Annotated[ Union[BaseBackend, DockerBackend, GCPBackend, AWSBackend, VsphereBackend], @@ -62,6 +64,8 @@ class RunnerGroup(BaseModel, BaseRunnerGroup): queued: int = Field(default=0, ge=0) os: str = Field(default="linux") arch: str = Field(default="x64") + job_started_script: Optional[str] = Field(default="") + job_completed_script: Optional[str] = Field(default="") def __str__(self) -> str: return ( @@ -149,6 +153,8 @@ def create_runner(self, github: GitHub) -> Runner | None: labels=self.runner_labels, manager=self.manager, download_url=self.download_url(github), + job_started_script=self.job_started_script, + job_completed_script=self.job_completed_script, ) runner.save() runner.generate_jit_config(github) diff --git a/tests/unit/backend/test_base.py b/tests/unit/backend/test_base.py index 969b5458..bce19772 100644 --- a/tests/unit/backend/test_base.py +++ b/tests/unit/backend/test_base.py @@ -65,3 +65,12 @@ def test_setup_redhat_credentials(runner, monkeypatch): template = runner_group.backend.instance_config.template_startup(runner) assert 'REDHAT_USERNAME="username"' in template assert 'REDHAT_PASSWORD="password"' in template + + +def test_job_scripts(runner_group, runner): + runner.job_started_script = 'echo "job started"' + runner.job_completed_script = 'echo "job completed"' + # Ensure that the template is rendered correctly + template = runner_group.backend.instance_config.template_startup(runner) + assert 'echo "job started"' in template + assert 'echo "job completed"' in template diff --git a/tests/unit/models/test_runner_group.py b/tests/unit/models/test_runner_group.py index 0ad2a528..46837df1 100644 --- a/tests/unit/models/test_runner_group.py +++ b/tests/unit/models/test_runner_group.py @@ -59,6 +59,8 @@ def test_create_runner_from_group(runner_group: RunnerGroup, github: GitHub): assert runner.encoded_jit_config is not None assert runner.created_at is not None assert runner.created_at.tzinfo == timezone.utc + assert runner.job_started_script == "" + assert runner.job_completed_script == "" def test_list_runners_from_group(runner_group: RunnerGroup, github: GitHub): @@ -163,6 +165,15 @@ def test_runner_group_name(): ) +def test_job_scripts(runner_group: RunnerGroup, github: GitHub): + runner_group.job_started_script = "Hello" + runner_group.min = 1 + runner_group.save() + runner = runner_group.create_runner(github) + assert runner.job_completed_script == "" + assert runner.job_started_script == runner_group.job_started_script + + def test_need_new_runner(runner_group: RunnerGroup, github: GitHub): runner_group.max = 2 runner_group.min = 1