Skip to content

Commit

Permalink
Add cwd to Job, JobConfig, and popen calls
Browse files Browse the repository at this point in the history
  • Loading branch information
A committed Jul 15, 2024
1 parent 962e8bb commit c4257b7
Show file tree
Hide file tree
Showing 23 changed files with 286 additions and 141 deletions.
1 change: 1 addition & 0 deletions config.example.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ jobs:
- name: Sleep 10 Seconds
id: sleep_10
command: sleep 10
cwd: /var/

- name: Sleep 30 Seconds
group: parallel
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "zapusk"
version = "0.1.0"
version = "0.1.1"
description = ""
authors = ["Anton Shuvalov <[email protected]>"]
readme = "README.md"
Expand Down
2 changes: 2 additions & 0 deletions zapusk/client/__main__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import os
from type_docopt import docopt
import importlib.metadata

Expand Down Expand Up @@ -95,6 +96,7 @@ def main():
name=str(args["--name"]) if args["--name"] else None,
schedule=str(args["--schedule"]) if args["--schedule"] else None,
tail=bool(args["--tail"]),
cwd=os.getcwd(),
)
return

Expand Down
1 change: 1 addition & 0 deletions zapusk/client/api_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ class JobCreateFromConfigPayload(TypedDict):

class JobCreateFromCommandPayload(TypedDict):
command: str
cwd: str
name: NotRequired[Optional[str]]
group_id: NotRequired[Optional[str]]

Expand Down
16 changes: 16 additions & 0 deletions zapusk/client/command.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from __future__ import annotations
from typing import TYPE_CHECKING
from requests.exceptions import ConnectionError

from .api_client import ApiClient, ApiClientError
from .output import Output
Expand Down Expand Up @@ -28,3 +29,18 @@ def print_json(self, json_data, one_line=False):

def print_error(self, exception):
self.output.error(exception, colors=self.colors)

def handle_error(self, ex):
if type(ex) ==ApiClientError:
self.print_error(ex)
return

if type(ex) == ConnectionError:
if "Connection refused by Responses" not in str(ex):
self.print_error(ApiClientError("Can not connect to the server. Please start server with `zapusk-server`"))
return

raise ex



8 changes: 6 additions & 2 deletions zapusk/client/command_exec.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import os
from typing import Optional

from zapusk.client.api_client import ApiClientError
Expand All @@ -9,6 +10,7 @@ class CommandExec(Command):
def run(
self,
command: str,
cwd: str,
name: Optional[str] = None,
group_id: Optional[str] = None,
schedule: Optional[str] = None,
Expand All @@ -23,6 +25,7 @@ def run(
"group_id": group_id,
"name": name,
"schedule": schedule,
"cwd": cwd,
}
)

Expand All @@ -35,6 +38,7 @@ def run(
"command": command,
"group_id": group_id,
"name": name,
"cwd": cwd,
}
)

Expand All @@ -44,5 +48,5 @@ def run(

self.print_json(created_job)

except ApiClientError as ex:
self.print_error(ex)
except Exception as ex:
self.handle_error(ex)
30 changes: 26 additions & 4 deletions zapusk/client/command_exec_test.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import json
import os
from unittest.mock import call, patch
import responses
from responses import matchers
Expand All @@ -7,6 +8,7 @@


class TestCommandExec(CommandTestCase):

@responses.activate
def test_should_exec_job(self):
responses.post(
Expand All @@ -19,6 +21,7 @@ def test_should_exec_job(self):
"command": "echo 1",
"group_id": "echo",
"name": "Echo",
"cwd": "/home/anton/",
}
)
],
Expand All @@ -28,6 +31,7 @@ def test_should_exec_job(self):
command="echo 1",
group_id="echo",
name="Echo",
cwd="/home/anton/",
)
json_data = json.loads(self.printer.print.call_args[0][0])

Expand All @@ -45,14 +49,19 @@ def test_should_exec_scheduled_job(self):
"command": "echo 1",
"group_id": "echo",
"name": "Echo",
"cwd": "/home/anton/",
"schedule": "*/1 * * * *",
}
)
],
)

self.command_manager.exec.run(
command="echo 1", group_id="echo", name="Echo", schedule="*/1 * * * *"
command="echo 1",
group_id="echo",
name="Echo",
schedule="*/1 * * * *",
cwd="/home/anton/",
)
json_data = json.loads(self.printer.print.call_args[0][0])

Expand All @@ -66,7 +75,10 @@ def test_should_handle_error(self):
json={"error": "ERROR"},
)

self.command_manager.exec.run(command="echo 1")
self.command_manager.exec.run(
command="echo 1",
cwd="/home/anton/",
)
args = self.printer.print.call_args[0]
message = json.loads(args[0])

Expand All @@ -82,13 +94,23 @@ def test_should_tail_job(self):
responses.get(
"http://example.com/jobs/1",
status=200,
json={"data": {"id": 1, "log": "/var/tail.log"}},
json={
"data": {
"id": 1,
"log": "/var/tail.log",
"cwd": "/home/anton/",
},
},
)

with patch(
"zapusk.client.command_tail.tail", return_value=["log line 1", "log line 2"]
):
self.command_manager.exec.run(command="echo 1", tail=True)
self.command_manager.exec.run(
command="echo 1",
tail=True,
cwd="/home/anton/",
)

log_line1 = self.printer.print.call_args_list[0]
log_line2 = self.printer.print.call_args_list[1]
Expand Down
4 changes: 2 additions & 2 deletions zapusk/client/command_list.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,5 @@ def run(
self.print_json(jobs)
return

except ApiClientError as ex:
self.print_error(ex)
except Exception as ex:
self.handle_error(ex)
7 changes: 7 additions & 0 deletions zapusk/models/job.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from dataclasses import dataclass, field
from datetime import datetime
from enum import Enum
import os
from typing import Optional

from .id_field import IdField
Expand Down Expand Up @@ -64,6 +65,7 @@ def from_config(group_config: JobGroup, config: JobConfig):
name=config.name,
on_finish=config.on_finish,
on_fail=config.on_fail,
cwd=config.cwd,
)

group_config: JobGroup
Expand All @@ -86,6 +88,11 @@ def from_config(group_config: JobGroup, config: JobConfig):
job_group id
"""

cwd: str = field(default_factory=lambda: os.environ["HOME"])
"""
current working dir
"""

job_config_id: Optional[str] = None
"""
job_config id
Expand Down
8 changes: 7 additions & 1 deletion zapusk/models/job_config.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from dataclasses import dataclass
from dataclasses import dataclass, field
import os
from typing import Optional

from .base_model import BaseModel
Expand All @@ -21,6 +22,11 @@ class JobConfig(BaseModel):
shell command for the job
"""

cwd: str = field(default_factory=lambda: os.environ["HOME"])
"""
current working dir
"""

group: str = "default"
"""
Group id to run job in
Expand Down
50 changes: 9 additions & 41 deletions zapusk/server/controller_config_test.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,7 @@
from unittest import TestCase
import json

from flask import json
from testfixtures import TempDirectory
from .controller_testcase import ControllerTestCase

from zapusk.services import (
ConfigService,
SchedulerService,
ExecutorManagerService,
ExecutorManagerKawkaBackend,
)

from .api import create_app

CONFIG_DATA = """
job_groups:
Expand All @@ -25,43 +16,16 @@
- id: test1
name: Test1
command: test1
cwd: /home/
- id: test2
name: Test2
command: test2
"""


class TestConfigController(TestCase):
def setUp(self) -> None:
self.temp_dir = TempDirectory()
config_file = self.temp_dir / "config.yml"
config_file.write_text(CONFIG_DATA)

self.executor_manager_service = ExecutorManagerService(
backend=ExecutorManagerKawkaBackend(),
)
self.config_service = ConfigService(
config_path=f"{self.temp_dir.path}/config.yml"
)
self.scheduler_service = SchedulerService(
config_service=self.config_service,
executor_manager_service=self.executor_manager_service,
)
self.scheduler_service.start()

self.app = create_app(
executor_manager_service=self.executor_manager_service,
config_service=self.config_service,
scheduler_service=self.scheduler_service,
)
self.test_client = self.app.test_client()

def tearDown(self) -> None:
self.executor_manager_service.terminate()
self.scheduler_service.terminate()
self.temp_dir.cleanup()

class TestConfigController(ControllerTestCase):
def test_config_groups_list(self):
self.write_config(CONFIG_DATA)
res = self.test_client.get("/config/groups/")
data = json.loads(res.data)
self.assertEqual(
Expand Down Expand Up @@ -91,6 +55,8 @@ def test_config_groups_list(self):
)

def test_config_jobs_list(self):
self.write_config(CONFIG_DATA)
self.replace_in_environ("HOME", "/home/kanye")
res = self.test_client.get("/config/jobs/")
data = json.loads(res.data)
self.assertEqual(
Expand All @@ -106,6 +72,7 @@ def test_config_jobs_list(self):
"on_fail": None,
"on_finish": None,
"schedule": None,
"cwd": "/home/",
},
{
"args_command": None,
Expand All @@ -116,6 +83,7 @@ def test_config_jobs_list(self):
"on_fail": None,
"on_finish": None,
"schedule": None,
"cwd": "/home/kanye",
},
]
},
Expand Down
3 changes: 3 additions & 0 deletions zapusk/server/controller_jobs.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import os
from flask import Blueprint, Response, abort, request
from zapusk.lib.json_serdes import JsonSerdes
from zapusk.models import Job, JobConfig, IdField
Expand Down Expand Up @@ -27,6 +28,7 @@ def job_add():
body = request.json or {}

job_config_id = body.get("job_config_id", None)
cwd = body.get("cwd", os.environ["HOME"])

# if no config id, let's try to execute it as a command
if not job_config_id:
Expand Down Expand Up @@ -59,6 +61,7 @@ def job_add():
id=cmd_id,
name=name or f"{job_group.id}.{cmd_id}",
command=command,
cwd=cwd,
),
)
executor_manager_service.add(job_item)
Expand Down
Loading

1 comment on commit c4257b7

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Coverage

Coverage Report
FileStmtsMissCoverMissing
zapusk
   logger.py00100% 
zapusk/client
   api_client.py840100% 
   command.py2455 79%
   command_cancel.py130100% 
   command_config_groups.py90100% 
   command_config_jobs.py90100% 
   command_exec.py180100% 
   command_list.py180100% 
   command_manager.py280100% 
   command_run.py90100% 
   command_tail.py160100% 
   command_testcase.py230100% 
   command_waybar.py300100% 
   output.py220100% 
   printer.py30100% 
zapusk/kawka
   consumer.py260100% 
   consumer_group.py330100% 
   linked_list.py100100% 
   producer.py290100% 
   topic.py270100% 
   topic_iterator.py450100% 
zapusk/lib
   create_jobitem.py60100% 
   json_serdes.py70100% 
zapusk/models
   base_model.py220100% 
   config.py100100% 
   id_field.py110100% 
   job.py620100% 
   job_config.py260100% 
   job_group.py120100% 
   scheduled_job.py240100% 
zapusk/server
   api.py100100% 
   controller_config.py110100% 
   controller_jobs.py500100% 
   controller_scheduled_jobs.py370100% 
   controller_testcase.py290100% 
   error_response.py40100% 
zapusk/services/config
   config_parser.py370100% 
   constants.py40100% 
   service.py580100% 
   yaml_filereader.py50100% 
zapusk/services/executor_manager
   service.py200100% 
zapusk/services/executor_manager/backends/kawka
   args_consumer.py280100% 
   backend.py350100% 
   consumer.py460100% 
   executor.py420100% 
   state.py90100% 
zapusk/services/scheduler_service
   service.py560100% 
TOTAL1137599% 

Please sign in to comment.