meerschaum.jobs.systemd

Manage meerschaum.jobs.Job via systemd.

SystemdExecutor is a façade over the native executor (crate meerschaum-jobs, bound as meerschaum._core.Executor): the unit files, the systemctl --user calls and the job state are Rust.

  1#! /usr/bin/env python3
  2# vim:fenc=utf-8
  3
  4"""
  5Manage `meerschaum.jobs.Job` via `systemd`.
  6
  7`SystemdExecutor` is a façade over the native executor (crate `meerschaum-jobs`, bound as
  8`meerschaum._core.Executor`): the unit files, the `systemctl --user` calls and the job state are
  9Rust.
 10"""
 11
 12import asyncio
 13import pathlib
 14import shlex
 15from datetime import datetime
 16from functools import partial
 17
 18import meerschaum as mrsm
 19from meerschaum.jobs import Job, Executor, make_executor, _native
 20from meerschaum.utils.typing import Dict, Any, List, SuccessTuple, Union, Optional
 21from meerschaum._internal.static import STATIC_CONFIG
 22from meerschaum.utils.warnings import warn, dprint
 23
 24JOB_METADATA_CACHE_SECONDS: int = STATIC_CONFIG['api']['jobs']['metadata_cache_seconds']
 25
 26
 27@make_executor
 28class SystemdExecutor(Executor):
 29    """
 30    Execute Meerschaum jobs via `systemd`.
 31    """
 32
 33    @property
 34    def _native_executor(self):
 35        """The native executor (built once per object)."""
 36        executor = self.__dict__.get('_native_executor_object', None)
 37        if executor is None:
 38            executor = _native.core().Executor('systemd')
 39            self.__dict__['_native_executor_object'] = executor
 40        return executor
 41
 42    def _warn(self) -> None:
 43        _native.emit_warnings(self._native_executor.take_warnings())
 44
 45    def get_job_names(self, debug: bool = False) -> List[str]:
 46        """
 47        Return a list of existing jobs, including hidden ones.
 48        """
 49        return self._native_executor.get_job_names()
 50
 51    def get_job_exists(self, name: str, debug: bool = False) -> bool:
 52        """
 53        Return whether a job exists.
 54        """
 55        return self._native_executor.get_job_exists(name)
 56
 57    def get_jobs(self, debug: bool = False) -> Dict[str, Job]:
 58        """
 59        Return a dictionary of `systemd` Jobs (including hidden jobs).
 60        """
 61        return {
 62            name: Job(name, executor_keys=str(self))
 63            for name in self.get_job_names(debug=debug)
 64        }
 65
 66    def get_service_name(self, name: str, debug: bool = False) -> str:
 67        """
 68        Return a job's service name.
 69        """
 70        return self._native_executor.get_service_name(name)
 71
 72    def get_service_job_path(self, name: str, debug: bool = False) -> pathlib.Path:
 73        """
 74        Return the path to the job's service directory.
 75        """
 76        return pathlib.Path(self._native_executor.get_service_job_path(name))
 77
 78    def get_service_symlink_file_path(self, name: str, debug: bool = False) -> pathlib.Path:
 79        """
 80        Return the path to where to create the service symlink.
 81        """
 82        return pathlib.Path(self._native_executor.get_service_symlink_file_path(name))
 83
 84    def get_service_file_path(self, name: str, debug: bool = False) -> pathlib.Path:
 85        """
 86        Return the path to a job's service file.
 87        """
 88        return pathlib.Path(self._native_executor.get_service_file_path(name))
 89
 90    def get_service_logs_path(self, name: str, debug: bool = False) -> pathlib.Path:
 91        """
 92        Return the path to direct service logs to.
 93        """
 94        return pathlib.Path(self._native_executor.get_service_logs_path(name))
 95
 96    def get_socket_path(self, name: str, debug: bool = False) -> pathlib.Path:
 97        """
 98        Return the path to the FIFO file.
 99        """
100        return pathlib.Path(self._native_executor.get_socket_path(name))
101
102    def get_result_path(self, name: str, debug: bool = False) -> pathlib.Path:
103        """
104        Return the path to the result file.
105        """
106        return pathlib.Path(self._native_executor.get_result_path(name))
107
108    def get_service_file_text(self, name: str, sysargs: List[str], debug: bool = False) -> str:
109        """
110        Return the contents of the unit file.
111        """
112        return self._native_executor.get_service_file_text(name, sysargs)
113
114    def get_socket_file_text(self, name: str, debug: bool = False) -> str:
115        """
116        Return the contents of the socket file.
117        """
118        return self._native_executor.get_socket_file_text(name)
119
120    def get_hidden_job(
121        self,
122        name: str,
123        sysargs: Optional[List[str]] = None,
124        properties: Optional[Dict[str, Any]] = None,
125        debug: bool = False,
126    ):
127        """
128        Return the hidden "sister" job to store a job's parameters.
129        """
130        job = Job(
131            name,
132            sysargs,
133            executor_keys='local',
134            _properties=properties,
135            _status_hook=partial(self.get_job_status, name),
136            _result_hook=partial(self.get_job_result, name),
137            _externally_managed=True,
138        )
139        return job
140
141    def get_job_metadata(self, name: str, debug: bool = False) -> Dict[str, Any]:
142        """
143        Return metadata about a job.
144        """
145        return self._native_executor.get_job_metadata(name)
146
147    def get_job_restart(self, name: str, debug: bool = False) -> bool:
148        """
149        Return whether a job restarts.
150        """
151        return self._native_executor.get_job_restart(name)
152
153    def get_job_properties(self, name: str, debug: bool = False) -> Dict[str, Any]:
154        """
155        Return the properties for a job.
156        """
157        return self._native_executor.get_job_properties(name)
158
159    def get_job_status(self, name: str, debug: bool = False) -> str:
160        """
161        Return the job's service status.
162        """
163        return self._native_executor.get_job_status(name)
164
165    def get_job_pid(self, name: str, debug: bool = False) -> Union[int, None]:
166        """
167        Return the job's service PID.
168        """
169        return self._native_executor.get_job_pid(name)
170
171    def get_job_began(self, name: str, debug: bool = False) -> Union[str, None]:
172        """
173        Return when a job began running.
174        """
175        return self._native_executor.get_job_began(name)
176
177    def get_job_ended(self, name: str, debug: bool = False) -> Union[str, None]:
178        """
179        Return when a job stopped running.
180        """
181        return self._native_executor.get_job_ended(name)
182
183    def get_job_paused(self, name: str, debug: bool = False) -> Union[str, None]:
184        """
185        Return when a job was paused.
186        """
187        return self._native_executor.get_job_paused(name)
188
189    def get_job_result(self, name: str, debug: bool = False) -> SuccessTuple:
190        """
191        Return the job's result SuccessTuple.
192        """
193        result = self._native_executor.get_job_result(name)
194        if result is None:
195            return False, "No result available."
196        return result
197
198    def get_job_sysargs(self, name: str, debug: bool = False) -> Union[List[str], None]:
199        """
200        Return the sysargs from the service file.
201        """
202        return self._native_executor.get_job_sysargs(name)
203
204    def run_command(
205        self,
206        command_args: List[str],
207        as_output: bool = False,
208        debug: bool = False,
209    ) -> Union[SuccessTuple, str]:
210        """
211        Run a `systemd` command and return success.
212
213        Parameters
214        ----------
215        command_args: List[str]
216            The command to pass to `systemctl --user`.
217
218        as_output: bool, default False
219            If `True`, return the process stdout output.
220            Defaults to a `SuccessTuple`.
221
222        Returns
223        -------
224        A `SuccessTuple` indicating success or a str for the process output.
225        """
226        if command_args[:2] != ['systemctl', '--user']:
227            command_args = ['systemctl', '--user'] + command_args
228
229        if debug:
230            dprint(shlex.join(command_args))
231
232        return self._native_executor.run_command(list(command_args[2:]), as_output)
233
234    def get_job_stdin_file(self, name: str, debug: bool = False):
235        """
236        Return a `StdinFile` for the job.
237        """
238        from meerschaum.utils.daemon import StdinFile
239        if '_stdin_files' not in self.__dict__:
240            self._stdin_files: Dict[str, StdinFile] = {}
241
242        if name not in self._stdin_files:
243            socket_path = self.get_socket_path(name, debug=debug)
244            socket_path.parent.mkdir(parents=True, exist_ok=True)
245            self._stdin_files[name] = StdinFile(socket_path)
246
247        return self._stdin_files[name]
248
249    def create_job(
250        self,
251        name: str,
252        sysargs: List[str],
253        properties: Optional[Dict[str, Any]] = None,
254        debug: bool = False,
255    ) -> SuccessTuple:
256        """
257        Create a job as a service to be run by `systemd`.
258        """
259        result = self._native_executor.create_job(name, sysargs, properties)
260        self._warn()
261        return result
262
263    def start_job(self, name: str, debug: bool = False) -> SuccessTuple:
264        """
265        Start a job.
266        """
267        result = self._native_executor.start_job(name)
268        self._warn()
269        return result
270
271    def stop_job(self, name: str, debug: bool = False) -> SuccessTuple:
272        """
273        Stop a job.
274        """
275        result = self._native_executor.stop_job(name)
276        self._warn()
277        return result
278
279    def pause_job(self, name: str, debug: bool = False) -> SuccessTuple:
280        """
281        Pause a job.
282        """
283        result = self._native_executor.pause_job(name)
284        self._warn()
285        return result
286
287    def delete_job(self, name: str, debug: bool = False) -> SuccessTuple:
288        """
289        Delete a job's service.
290        """
291        result = self._native_executor.delete_job(name)
292        self._warn()
293        return result
294
295    def get_logs(self, name: str, debug: bool = False) -> str:
296        """
297        Return a job's journal logs.
298        """
299        return self._native_executor.get_logs(name) or ''
300
301    def get_job_stop_time(self, name: str, debug: bool = False) -> Union[datetime, None]:
302        """
303        Return a job's stop time.
304        """
305        stop_time = self._native_executor.get_job_stop_time(name)
306        return datetime.fromisoformat(stop_time) if stop_time else None
307
308    def get_job_is_blocking_on_stdin(self, name: str, debug: bool = False) -> bool:
309        """
310        Return whether a job is blocking on stdin.
311        """
312        return self._native_executor.get_job_is_blocking_on_stdin(name)
313
314    def get_job_prompt_kwargs(self, name: str, debug: bool = False) -> Dict[str, Any]:
315        """
316        Return the kwargs to the blocking prompt.
317        """
318        return self._native_executor.get_job_prompt_kwargs(name)
319
320    def get_job_rotating_file(self, name: str, debug: bool = False):
321        """
322        Return a `RotatingFile` for the job's log output.
323        """
324        from meerschaum.utils.daemon import RotatingFile
325        service_logs_path = self.get_service_logs_path(name, debug=debug)
326        return RotatingFile(service_logs_path)
327
328    async def monitor_logs_async(
329        self,
330        name: str,
331        *args,
332        debug: bool = False,
333        **kwargs
334    ):
335        """
336        Monitor a job's output.
337        """
338        job = Job(name, executor_keys=str(self))
339        kwargs.update({'debug': debug})
340        await job.monitor_logs_async(*args, **kwargs)
341
342    def monitor_logs(self, *args, **kwargs):
343        """
344        Monitor a job's output.
345        """
346        asyncio.run(self.monitor_logs_async(*args, **kwargs))
JOB_METADATA_CACHE_SECONDS: int = 5
@make_executor
class SystemdExecutor(meerschaum.jobs._Executor.Executor):
 28@make_executor
 29class SystemdExecutor(Executor):
 30    """
 31    Execute Meerschaum jobs via `systemd`.
 32    """
 33
 34    @property
 35    def _native_executor(self):
 36        """The native executor (built once per object)."""
 37        executor = self.__dict__.get('_native_executor_object', None)
 38        if executor is None:
 39            executor = _native.core().Executor('systemd')
 40            self.__dict__['_native_executor_object'] = executor
 41        return executor
 42
 43    def _warn(self) -> None:
 44        _native.emit_warnings(self._native_executor.take_warnings())
 45
 46    def get_job_names(self, debug: bool = False) -> List[str]:
 47        """
 48        Return a list of existing jobs, including hidden ones.
 49        """
 50        return self._native_executor.get_job_names()
 51
 52    def get_job_exists(self, name: str, debug: bool = False) -> bool:
 53        """
 54        Return whether a job exists.
 55        """
 56        return self._native_executor.get_job_exists(name)
 57
 58    def get_jobs(self, debug: bool = False) -> Dict[str, Job]:
 59        """
 60        Return a dictionary of `systemd` Jobs (including hidden jobs).
 61        """
 62        return {
 63            name: Job(name, executor_keys=str(self))
 64            for name in self.get_job_names(debug=debug)
 65        }
 66
 67    def get_service_name(self, name: str, debug: bool = False) -> str:
 68        """
 69        Return a job's service name.
 70        """
 71        return self._native_executor.get_service_name(name)
 72
 73    def get_service_job_path(self, name: str, debug: bool = False) -> pathlib.Path:
 74        """
 75        Return the path to the job's service directory.
 76        """
 77        return pathlib.Path(self._native_executor.get_service_job_path(name))
 78
 79    def get_service_symlink_file_path(self, name: str, debug: bool = False) -> pathlib.Path:
 80        """
 81        Return the path to where to create the service symlink.
 82        """
 83        return pathlib.Path(self._native_executor.get_service_symlink_file_path(name))
 84
 85    def get_service_file_path(self, name: str, debug: bool = False) -> pathlib.Path:
 86        """
 87        Return the path to a job's service file.
 88        """
 89        return pathlib.Path(self._native_executor.get_service_file_path(name))
 90
 91    def get_service_logs_path(self, name: str, debug: bool = False) -> pathlib.Path:
 92        """
 93        Return the path to direct service logs to.
 94        """
 95        return pathlib.Path(self._native_executor.get_service_logs_path(name))
 96
 97    def get_socket_path(self, name: str, debug: bool = False) -> pathlib.Path:
 98        """
 99        Return the path to the FIFO file.
100        """
101        return pathlib.Path(self._native_executor.get_socket_path(name))
102
103    def get_result_path(self, name: str, debug: bool = False) -> pathlib.Path:
104        """
105        Return the path to the result file.
106        """
107        return pathlib.Path(self._native_executor.get_result_path(name))
108
109    def get_service_file_text(self, name: str, sysargs: List[str], debug: bool = False) -> str:
110        """
111        Return the contents of the unit file.
112        """
113        return self._native_executor.get_service_file_text(name, sysargs)
114
115    def get_socket_file_text(self, name: str, debug: bool = False) -> str:
116        """
117        Return the contents of the socket file.
118        """
119        return self._native_executor.get_socket_file_text(name)
120
121    def get_hidden_job(
122        self,
123        name: str,
124        sysargs: Optional[List[str]] = None,
125        properties: Optional[Dict[str, Any]] = None,
126        debug: bool = False,
127    ):
128        """
129        Return the hidden "sister" job to store a job's parameters.
130        """
131        job = Job(
132            name,
133            sysargs,
134            executor_keys='local',
135            _properties=properties,
136            _status_hook=partial(self.get_job_status, name),
137            _result_hook=partial(self.get_job_result, name),
138            _externally_managed=True,
139        )
140        return job
141
142    def get_job_metadata(self, name: str, debug: bool = False) -> Dict[str, Any]:
143        """
144        Return metadata about a job.
145        """
146        return self._native_executor.get_job_metadata(name)
147
148    def get_job_restart(self, name: str, debug: bool = False) -> bool:
149        """
150        Return whether a job restarts.
151        """
152        return self._native_executor.get_job_restart(name)
153
154    def get_job_properties(self, name: str, debug: bool = False) -> Dict[str, Any]:
155        """
156        Return the properties for a job.
157        """
158        return self._native_executor.get_job_properties(name)
159
160    def get_job_status(self, name: str, debug: bool = False) -> str:
161        """
162        Return the job's service status.
163        """
164        return self._native_executor.get_job_status(name)
165
166    def get_job_pid(self, name: str, debug: bool = False) -> Union[int, None]:
167        """
168        Return the job's service PID.
169        """
170        return self._native_executor.get_job_pid(name)
171
172    def get_job_began(self, name: str, debug: bool = False) -> Union[str, None]:
173        """
174        Return when a job began running.
175        """
176        return self._native_executor.get_job_began(name)
177
178    def get_job_ended(self, name: str, debug: bool = False) -> Union[str, None]:
179        """
180        Return when a job stopped running.
181        """
182        return self._native_executor.get_job_ended(name)
183
184    def get_job_paused(self, name: str, debug: bool = False) -> Union[str, None]:
185        """
186        Return when a job was paused.
187        """
188        return self._native_executor.get_job_paused(name)
189
190    def get_job_result(self, name: str, debug: bool = False) -> SuccessTuple:
191        """
192        Return the job's result SuccessTuple.
193        """
194        result = self._native_executor.get_job_result(name)
195        if result is None:
196            return False, "No result available."
197        return result
198
199    def get_job_sysargs(self, name: str, debug: bool = False) -> Union[List[str], None]:
200        """
201        Return the sysargs from the service file.
202        """
203        return self._native_executor.get_job_sysargs(name)
204
205    def run_command(
206        self,
207        command_args: List[str],
208        as_output: bool = False,
209        debug: bool = False,
210    ) -> Union[SuccessTuple, str]:
211        """
212        Run a `systemd` command and return success.
213
214        Parameters
215        ----------
216        command_args: List[str]
217            The command to pass to `systemctl --user`.
218
219        as_output: bool, default False
220            If `True`, return the process stdout output.
221            Defaults to a `SuccessTuple`.
222
223        Returns
224        -------
225        A `SuccessTuple` indicating success or a str for the process output.
226        """
227        if command_args[:2] != ['systemctl', '--user']:
228            command_args = ['systemctl', '--user'] + command_args
229
230        if debug:
231            dprint(shlex.join(command_args))
232
233        return self._native_executor.run_command(list(command_args[2:]), as_output)
234
235    def get_job_stdin_file(self, name: str, debug: bool = False):
236        """
237        Return a `StdinFile` for the job.
238        """
239        from meerschaum.utils.daemon import StdinFile
240        if '_stdin_files' not in self.__dict__:
241            self._stdin_files: Dict[str, StdinFile] = {}
242
243        if name not in self._stdin_files:
244            socket_path = self.get_socket_path(name, debug=debug)
245            socket_path.parent.mkdir(parents=True, exist_ok=True)
246            self._stdin_files[name] = StdinFile(socket_path)
247
248        return self._stdin_files[name]
249
250    def create_job(
251        self,
252        name: str,
253        sysargs: List[str],
254        properties: Optional[Dict[str, Any]] = None,
255        debug: bool = False,
256    ) -> SuccessTuple:
257        """
258        Create a job as a service to be run by `systemd`.
259        """
260        result = self._native_executor.create_job(name, sysargs, properties)
261        self._warn()
262        return result
263
264    def start_job(self, name: str, debug: bool = False) -> SuccessTuple:
265        """
266        Start a job.
267        """
268        result = self._native_executor.start_job(name)
269        self._warn()
270        return result
271
272    def stop_job(self, name: str, debug: bool = False) -> SuccessTuple:
273        """
274        Stop a job.
275        """
276        result = self._native_executor.stop_job(name)
277        self._warn()
278        return result
279
280    def pause_job(self, name: str, debug: bool = False) -> SuccessTuple:
281        """
282        Pause a job.
283        """
284        result = self._native_executor.pause_job(name)
285        self._warn()
286        return result
287
288    def delete_job(self, name: str, debug: bool = False) -> SuccessTuple:
289        """
290        Delete a job's service.
291        """
292        result = self._native_executor.delete_job(name)
293        self._warn()
294        return result
295
296    def get_logs(self, name: str, debug: bool = False) -> str:
297        """
298        Return a job's journal logs.
299        """
300        return self._native_executor.get_logs(name) or ''
301
302    def get_job_stop_time(self, name: str, debug: bool = False) -> Union[datetime, None]:
303        """
304        Return a job's stop time.
305        """
306        stop_time = self._native_executor.get_job_stop_time(name)
307        return datetime.fromisoformat(stop_time) if stop_time else None
308
309    def get_job_is_blocking_on_stdin(self, name: str, debug: bool = False) -> bool:
310        """
311        Return whether a job is blocking on stdin.
312        """
313        return self._native_executor.get_job_is_blocking_on_stdin(name)
314
315    def get_job_prompt_kwargs(self, name: str, debug: bool = False) -> Dict[str, Any]:
316        """
317        Return the kwargs to the blocking prompt.
318        """
319        return self._native_executor.get_job_prompt_kwargs(name)
320
321    def get_job_rotating_file(self, name: str, debug: bool = False):
322        """
323        Return a `RotatingFile` for the job's log output.
324        """
325        from meerschaum.utils.daemon import RotatingFile
326        service_logs_path = self.get_service_logs_path(name, debug=debug)
327        return RotatingFile(service_logs_path)
328
329    async def monitor_logs_async(
330        self,
331        name: str,
332        *args,
333        debug: bool = False,
334        **kwargs
335    ):
336        """
337        Monitor a job's output.
338        """
339        job = Job(name, executor_keys=str(self))
340        kwargs.update({'debug': debug})
341        await job.monitor_logs_async(*args, **kwargs)
342
343    def monitor_logs(self, *args, **kwargs):
344        """
345        Monitor a job's output.
346        """
347        asyncio.run(self.monitor_logs_async(*args, **kwargs))

Execute Meerschaum jobs via systemd.

def get_job_names(self, debug: bool = False) -> List[str]:
46    def get_job_names(self, debug: bool = False) -> List[str]:
47        """
48        Return a list of existing jobs, including hidden ones.
49        """
50        return self._native_executor.get_job_names()

Return a list of existing jobs, including hidden ones.

def get_job_exists(self, name: str, debug: bool = False) -> bool:
52    def get_job_exists(self, name: str, debug: bool = False) -> bool:
53        """
54        Return whether a job exists.
55        """
56        return self._native_executor.get_job_exists(name)

Return whether a job exists.

def get_jobs(self, debug: bool = False) -> Dict[str, meerschaum.Job]:
58    def get_jobs(self, debug: bool = False) -> Dict[str, Job]:
59        """
60        Return a dictionary of `systemd` Jobs (including hidden jobs).
61        """
62        return {
63            name: Job(name, executor_keys=str(self))
64            for name in self.get_job_names(debug=debug)
65        }

Return a dictionary of systemd Jobs (including hidden jobs).

def get_service_name(self, name: str, debug: bool = False) -> str:
67    def get_service_name(self, name: str, debug: bool = False) -> str:
68        """
69        Return a job's service name.
70        """
71        return self._native_executor.get_service_name(name)

Return a job's service name.

def get_service_job_path(self, name: str, debug: bool = False) -> pathlib.Path:
73    def get_service_job_path(self, name: str, debug: bool = False) -> pathlib.Path:
74        """
75        Return the path to the job's service directory.
76        """
77        return pathlib.Path(self._native_executor.get_service_job_path(name))

Return the path to the job's service directory.

def get_service_file_path(self, name: str, debug: bool = False) -> pathlib.Path:
85    def get_service_file_path(self, name: str, debug: bool = False) -> pathlib.Path:
86        """
87        Return the path to a job's service file.
88        """
89        return pathlib.Path(self._native_executor.get_service_file_path(name))

Return the path to a job's service file.

def get_service_logs_path(self, name: str, debug: bool = False) -> pathlib.Path:
91    def get_service_logs_path(self, name: str, debug: bool = False) -> pathlib.Path:
92        """
93        Return the path to direct service logs to.
94        """
95        return pathlib.Path(self._native_executor.get_service_logs_path(name))

Return the path to direct service logs to.

def get_socket_path(self, name: str, debug: bool = False) -> pathlib.Path:
 97    def get_socket_path(self, name: str, debug: bool = False) -> pathlib.Path:
 98        """
 99        Return the path to the FIFO file.
100        """
101        return pathlib.Path(self._native_executor.get_socket_path(name))

Return the path to the FIFO file.

def get_result_path(self, name: str, debug: bool = False) -> pathlib.Path:
103    def get_result_path(self, name: str, debug: bool = False) -> pathlib.Path:
104        """
105        Return the path to the result file.
106        """
107        return pathlib.Path(self._native_executor.get_result_path(name))

Return the path to the result file.

def get_service_file_text(self, name: str, sysargs: List[str], debug: bool = False) -> str:
109    def get_service_file_text(self, name: str, sysargs: List[str], debug: bool = False) -> str:
110        """
111        Return the contents of the unit file.
112        """
113        return self._native_executor.get_service_file_text(name, sysargs)

Return the contents of the unit file.

def get_socket_file_text(self, name: str, debug: bool = False) -> str:
115    def get_socket_file_text(self, name: str, debug: bool = False) -> str:
116        """
117        Return the contents of the socket file.
118        """
119        return self._native_executor.get_socket_file_text(name)

Return the contents of the socket file.

def get_hidden_job( self, name: str, sysargs: List[str] | None = None, properties: Dict[str, Any] | None = None, debug: bool = False):
121    def get_hidden_job(
122        self,
123        name: str,
124        sysargs: Optional[List[str]] = None,
125        properties: Optional[Dict[str, Any]] = None,
126        debug: bool = False,
127    ):
128        """
129        Return the hidden "sister" job to store a job's parameters.
130        """
131        job = Job(
132            name,
133            sysargs,
134            executor_keys='local',
135            _properties=properties,
136            _status_hook=partial(self.get_job_status, name),
137            _result_hook=partial(self.get_job_result, name),
138            _externally_managed=True,
139        )
140        return job

Return the hidden "sister" job to store a job's parameters.

def get_job_metadata(self, name: str, debug: bool = False) -> Dict[str, Any]:
142    def get_job_metadata(self, name: str, debug: bool = False) -> Dict[str, Any]:
143        """
144        Return metadata about a job.
145        """
146        return self._native_executor.get_job_metadata(name)

Return metadata about a job.

def get_job_restart(self, name: str, debug: bool = False) -> bool:
148    def get_job_restart(self, name: str, debug: bool = False) -> bool:
149        """
150        Return whether a job restarts.
151        """
152        return self._native_executor.get_job_restart(name)

Return whether a job restarts.

def get_job_properties(self, name: str, debug: bool = False) -> Dict[str, Any]:
154    def get_job_properties(self, name: str, debug: bool = False) -> Dict[str, Any]:
155        """
156        Return the properties for a job.
157        """
158        return self._native_executor.get_job_properties(name)

Return the properties for a job.

def get_job_status(self, name: str, debug: bool = False) -> str:
160    def get_job_status(self, name: str, debug: bool = False) -> str:
161        """
162        Return the job's service status.
163        """
164        return self._native_executor.get_job_status(name)

Return the job's service status.

def get_job_pid(self, name: str, debug: bool = False) -> int | None:
166    def get_job_pid(self, name: str, debug: bool = False) -> Union[int, None]:
167        """
168        Return the job's service PID.
169        """
170        return self._native_executor.get_job_pid(name)

Return the job's service PID.

def get_job_began(self, name: str, debug: bool = False) -> str | None:
172    def get_job_began(self, name: str, debug: bool = False) -> Union[str, None]:
173        """
174        Return when a job began running.
175        """
176        return self._native_executor.get_job_began(name)

Return when a job began running.

def get_job_ended(self, name: str, debug: bool = False) -> str | None:
178    def get_job_ended(self, name: str, debug: bool = False) -> Union[str, None]:
179        """
180        Return when a job stopped running.
181        """
182        return self._native_executor.get_job_ended(name)

Return when a job stopped running.

def get_job_paused(self, name: str, debug: bool = False) -> str | None:
184    def get_job_paused(self, name: str, debug: bool = False) -> Union[str, None]:
185        """
186        Return when a job was paused.
187        """
188        return self._native_executor.get_job_paused(name)

Return when a job was paused.

def get_job_result(self, name: str, debug: bool = False) -> Tuple[bool, str]:
190    def get_job_result(self, name: str, debug: bool = False) -> SuccessTuple:
191        """
192        Return the job's result SuccessTuple.
193        """
194        result = self._native_executor.get_job_result(name)
195        if result is None:
196            return False, "No result available."
197        return result

Return the job's result SuccessTuple.

def get_job_sysargs(self, name: str, debug: bool = False) -> List[str] | None:
199    def get_job_sysargs(self, name: str, debug: bool = False) -> Union[List[str], None]:
200        """
201        Return the sysargs from the service file.
202        """
203        return self._native_executor.get_job_sysargs(name)

Return the sysargs from the service file.

def run_command( self, command_args: List[str], as_output: bool = False, debug: bool = False) -> Tuple[bool, str] | str:
205    def run_command(
206        self,
207        command_args: List[str],
208        as_output: bool = False,
209        debug: bool = False,
210    ) -> Union[SuccessTuple, str]:
211        """
212        Run a `systemd` command and return success.
213
214        Parameters
215        ----------
216        command_args: List[str]
217            The command to pass to `systemctl --user`.
218
219        as_output: bool, default False
220            If `True`, return the process stdout output.
221            Defaults to a `SuccessTuple`.
222
223        Returns
224        -------
225        A `SuccessTuple` indicating success or a str for the process output.
226        """
227        if command_args[:2] != ['systemctl', '--user']:
228            command_args = ['systemctl', '--user'] + command_args
229
230        if debug:
231            dprint(shlex.join(command_args))
232
233        return self._native_executor.run_command(list(command_args[2:]), as_output)

Run a systemd command and return success.

Parameters
  • command_args (List[str]): The command to pass to systemctl --user.
  • as_output (bool, default False): If True, return the process stdout output. Defaults to a SuccessTuple.
Returns
  • A SuccessTuple indicating success or a str for the process output.
def get_job_stdin_file(self, name: str, debug: bool = False):
235    def get_job_stdin_file(self, name: str, debug: bool = False):
236        """
237        Return a `StdinFile` for the job.
238        """
239        from meerschaum.utils.daemon import StdinFile
240        if '_stdin_files' not in self.__dict__:
241            self._stdin_files: Dict[str, StdinFile] = {}
242
243        if name not in self._stdin_files:
244            socket_path = self.get_socket_path(name, debug=debug)
245            socket_path.parent.mkdir(parents=True, exist_ok=True)
246            self._stdin_files[name] = StdinFile(socket_path)
247
248        return self._stdin_files[name]

Return a StdinFile for the job.

def create_job( self, name: str, sysargs: List[str], properties: Dict[str, Any] | None = None, debug: bool = False) -> Tuple[bool, str]:
250    def create_job(
251        self,
252        name: str,
253        sysargs: List[str],
254        properties: Optional[Dict[str, Any]] = None,
255        debug: bool = False,
256    ) -> SuccessTuple:
257        """
258        Create a job as a service to be run by `systemd`.
259        """
260        result = self._native_executor.create_job(name, sysargs, properties)
261        self._warn()
262        return result

Create a job as a service to be run by systemd.

def start_job(self, name: str, debug: bool = False) -> Tuple[bool, str]:
264    def start_job(self, name: str, debug: bool = False) -> SuccessTuple:
265        """
266        Start a job.
267        """
268        result = self._native_executor.start_job(name)
269        self._warn()
270        return result

Start a job.

def stop_job(self, name: str, debug: bool = False) -> Tuple[bool, str]:
272    def stop_job(self, name: str, debug: bool = False) -> SuccessTuple:
273        """
274        Stop a job.
275        """
276        result = self._native_executor.stop_job(name)
277        self._warn()
278        return result

Stop a job.

def pause_job(self, name: str, debug: bool = False) -> Tuple[bool, str]:
280    def pause_job(self, name: str, debug: bool = False) -> SuccessTuple:
281        """
282        Pause a job.
283        """
284        result = self._native_executor.pause_job(name)
285        self._warn()
286        return result

Pause a job.

def delete_job(self, name: str, debug: bool = False) -> Tuple[bool, str]:
288    def delete_job(self, name: str, debug: bool = False) -> SuccessTuple:
289        """
290        Delete a job's service.
291        """
292        result = self._native_executor.delete_job(name)
293        self._warn()
294        return result

Delete a job's service.

def get_logs(self, name: str, debug: bool = False) -> str:
296    def get_logs(self, name: str, debug: bool = False) -> str:
297        """
298        Return a job's journal logs.
299        """
300        return self._native_executor.get_logs(name) or ''

Return a job's journal logs.

def get_job_stop_time(self, name: str, debug: bool = False) -> datetime.datetime | None:
302    def get_job_stop_time(self, name: str, debug: bool = False) -> Union[datetime, None]:
303        """
304        Return a job's stop time.
305        """
306        stop_time = self._native_executor.get_job_stop_time(name)
307        return datetime.fromisoformat(stop_time) if stop_time else None

Return a job's stop time.

def get_job_is_blocking_on_stdin(self, name: str, debug: bool = False) -> bool:
309    def get_job_is_blocking_on_stdin(self, name: str, debug: bool = False) -> bool:
310        """
311        Return whether a job is blocking on stdin.
312        """
313        return self._native_executor.get_job_is_blocking_on_stdin(name)

Return whether a job is blocking on stdin.

def get_job_prompt_kwargs(self, name: str, debug: bool = False) -> Dict[str, Any]:
315    def get_job_prompt_kwargs(self, name: str, debug: bool = False) -> Dict[str, Any]:
316        """
317        Return the kwargs to the blocking prompt.
318        """
319        return self._native_executor.get_job_prompt_kwargs(name)

Return the kwargs to the blocking prompt.

def get_job_rotating_file(self, name: str, debug: bool = False):
321    def get_job_rotating_file(self, name: str, debug: bool = False):
322        """
323        Return a `RotatingFile` for the job's log output.
324        """
325        from meerschaum.utils.daemon import RotatingFile
326        service_logs_path = self.get_service_logs_path(name, debug=debug)
327        return RotatingFile(service_logs_path)

Return a RotatingFile for the job's log output.

async def monitor_logs_async(self, name: str, *args, debug: bool = False, **kwargs):
329    async def monitor_logs_async(
330        self,
331        name: str,
332        *args,
333        debug: bool = False,
334        **kwargs
335    ):
336        """
337        Monitor a job's output.
338        """
339        job = Job(name, executor_keys=str(self))
340        kwargs.update({'debug': debug})
341        await job.monitor_logs_async(*args, **kwargs)

Monitor a job's output.

def monitor_logs(self, *args, **kwargs):
343    def monitor_logs(self, *args, **kwargs):
344        """
345        Monitor a job's output.
346        """
347        asyncio.run(self.monitor_logs_async(*args, **kwargs))

Monitor a job's output.