python3-cyberfusion-systemd-support 2.4.0__tar.gz → 2.5.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (16) hide show
  1. {python3_cyberfusion_systemd_support-2.4.0 → python3_cyberfusion_systemd_support-2.5.0}/PKG-INFO +10 -1
  2. {python3_cyberfusion_systemd_support-2.4.0 → python3_cyberfusion_systemd_support-2.5.0}/README.md +9 -0
  3. {python3_cyberfusion_systemd_support-2.4.0 → python3_cyberfusion_systemd_support-2.5.0}/pyproject.toml +1 -1
  4. python3_cyberfusion_systemd_support-2.5.0/src/cyberfusion/SystemdSupport/enums.py +69 -0
  5. python3_cyberfusion_systemd_support-2.5.0/src/cyberfusion/SystemdSupport/exceptions.py +25 -0
  6. {python3_cyberfusion_systemd_support-2.4.0 → python3_cyberfusion_systemd_support-2.5.0}/src/cyberfusion/SystemdSupport/units.py +56 -1
  7. {python3_cyberfusion_systemd_support-2.4.0 → python3_cyberfusion_systemd_support-2.5.0}/src/python3_cyberfusion_systemd_support.egg-info/PKG-INFO +10 -1
  8. {python3_cyberfusion_systemd_support-2.4.0 → python3_cyberfusion_systemd_support-2.5.0}/src/python3_cyberfusion_systemd_support.egg-info/SOURCES.txt +2 -0
  9. {python3_cyberfusion_systemd_support-2.4.0 → python3_cyberfusion_systemd_support-2.5.0}/setup.cfg +0 -0
  10. {python3_cyberfusion_systemd_support-2.4.0 → python3_cyberfusion_systemd_support-2.5.0}/src/cyberfusion/SystemdSupport/__init__.py +0 -0
  11. {python3_cyberfusion_systemd_support-2.4.0 → python3_cyberfusion_systemd_support-2.5.0}/src/cyberfusion/SystemdSupport/_constants.py +0 -0
  12. {python3_cyberfusion_systemd_support-2.4.0 → python3_cyberfusion_systemd_support-2.5.0}/src/cyberfusion/SystemdSupport/manager.py +0 -0
  13. {python3_cyberfusion_systemd_support-2.4.0 → python3_cyberfusion_systemd_support-2.5.0}/src/cyberfusion/SystemdSupport/tmp_files.py +0 -0
  14. {python3_cyberfusion_systemd_support-2.4.0 → python3_cyberfusion_systemd_support-2.5.0}/src/python3_cyberfusion_systemd_support.egg-info/dependency_links.txt +0 -0
  15. {python3_cyberfusion_systemd_support-2.4.0 → python3_cyberfusion_systemd_support-2.5.0}/src/python3_cyberfusion_systemd_support.egg-info/requires.txt +0 -0
  16. {python3_cyberfusion_systemd_support-2.4.0 → python3_cyberfusion_systemd_support-2.5.0}/src/python3_cyberfusion_systemd_support.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python3-cyberfusion-systemd-support
3
- Version: 2.4.0
3
+ Version: 2.5.0
4
4
  Summary: Library for systemd.
5
5
  Author-email: Cyberfusion <support@cyberfusion.io>
6
6
  Project-URL: Source, https://github.com/CyberfusionIO/python3-cyberfusion-systemd-support
@@ -52,6 +52,15 @@ print(unit.is_enabled)
52
52
  print(unit.is_failed)
53
53
  ```
54
54
 
55
+ ## Transient units
56
+
57
+ ```python
58
+ from cyberfusion.SystemdSupport.units import TransientUnit
59
+
60
+ transient_unit = TransientUnit.run(name="cf-apt-upgrade", command=["apt-get", "upgrade", "-y"])
61
+ transient_unit.clean_up()
62
+ ```
63
+
55
64
  ## Tmp files
56
65
 
57
66
  ```python
@@ -43,6 +43,15 @@ print(unit.is_enabled)
43
43
  print(unit.is_failed)
44
44
  ```
45
45
 
46
+ ## Transient units
47
+
48
+ ```python
49
+ from cyberfusion.SystemdSupport.units import TransientUnit
50
+
51
+ transient_unit = TransientUnit.run(name="cf-apt-upgrade", command=["apt-get", "upgrade", "-y"])
52
+ transient_unit.clean_up()
53
+ ```
54
+
46
55
  ## Tmp files
47
56
 
48
57
  ```python
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "python3-cyberfusion-systemd-support"
7
- version = "2.4.0"
7
+ version = "2.5.0"
8
8
  description = "Library for systemd."
9
9
  readme = "README.md"
10
10
  authors = [
@@ -0,0 +1,69 @@
1
+ """Unit state enums.
2
+
3
+ See: https://www.freedesktop.org/software/systemd/man/latest/systemctl.html#is-active%20PATTERN%E2%80%A6
4
+ """
5
+
6
+ from enum import StrEnum
7
+
8
+
9
+ class ActiveState(StrEnum):
10
+ """Possible values of a unit's ActiveState property."""
11
+
12
+ ACTIVE = "active"
13
+ RELOADING = "reloading"
14
+ INACTIVE = "inactive"
15
+ FAILED = "failed"
16
+ ACTIVATING = "activating"
17
+ DEACTIVATING = "deactivating"
18
+ MAINTENANCE = "maintenance"
19
+
20
+
21
+ class SubState(StrEnum):
22
+ """Possible values of a unit's SubState property.
23
+
24
+ Union of sub-states across all unit types (service, socket, mount, device,
25
+ target, automount, timer, path, slice, scope).
26
+ """
27
+
28
+ ABANDONED = "abandoned"
29
+ ACTIVE = "active"
30
+ AUTO_RESTART = "auto-restart"
31
+ CLEANING = "cleaning"
32
+ CONDITION = "condition"
33
+ DEAD = "dead"
34
+ ELAPSED = "elapsed"
35
+ EXITED = "exited"
36
+ FAILED = "failed"
37
+ FINAL_SIGKILL = "final-sigkill"
38
+ FINAL_SIGTERM = "final-sigterm"
39
+ FINAL_WATCHDOG = "final-watchdog"
40
+ LISTENING = "listening"
41
+ MOUNTED = "mounted"
42
+ MOUNTING = "mounting"
43
+ MOUNTING_DONE = "mounting-done"
44
+ PLUGGED = "plugged"
45
+ REFRESH_EXTENSIONS = "refresh-extensions"
46
+ RELOAD = "reload"
47
+ RELOAD_NOTIFY = "reload-notify"
48
+ RELOAD_SIGNAL = "reload-signal"
49
+ REMOUNTING = "remounting"
50
+ REMOUNTING_SIGKILL = "remounting-sigkill"
51
+ REMOUNTING_SIGTERM = "remounting-sigterm"
52
+ RUNNING = "running"
53
+ START = "start"
54
+ START_CHOWN = "start-chown"
55
+ START_POST = "start-post"
56
+ START_PRE = "start-pre"
57
+ STOP = "stop"
58
+ STOP_POST = "stop-post"
59
+ STOP_PRE = "stop-pre"
60
+ STOP_PRE_SIGKILL = "stop-pre-sigkill"
61
+ STOP_PRE_SIGTERM = "stop-pre-sigterm"
62
+ STOP_SIGKILL = "stop-sigkill"
63
+ STOP_SIGTERM = "stop-sigterm"
64
+ STOP_WATCHDOG = "stop-watchdog"
65
+ TENTATIVE = "tentative"
66
+ UNMOUNTING = "unmounting"
67
+ UNMOUNTING_SIGKILL = "unmounting-sigkill"
68
+ UNMOUNTING_SIGTERM = "unmounting-sigterm"
69
+ WAITING = "waiting"
@@ -0,0 +1,25 @@
1
+ """Exceptions."""
2
+
3
+ from typing import Optional
4
+
5
+
6
+ class UnexpectedSubStateError(Exception):
7
+ """Unit is in a SubState we don't know how to handle."""
8
+
9
+ def __init__(self, unit_name: str, sub_state: Optional[str]) -> None:
10
+ """Set attributes."""
11
+ self.unit_name = unit_name
12
+ self.sub_state = sub_state
13
+
14
+ super().__init__(f"Unit {unit_name} has unexpected SubState: {sub_state}")
15
+
16
+
17
+ class UnexpectedActiveStateError(Exception):
18
+ """Unit is in an ActiveState we don't know how to handle."""
19
+
20
+ def __init__(self, unit_name: str, active_state: Optional[str]) -> None:
21
+ """Set attributes."""
22
+ self.unit_name = unit_name
23
+ self.active_state = active_state
24
+
25
+ super().__init__(f"Unit {unit_name} has unexpected ActiveState: {active_state}")
@@ -1,19 +1,27 @@
1
1
  """Classes for systemd units."""
2
2
 
3
3
  import glob
4
+ import json
4
5
  import os
5
6
  import subprocess
6
7
  from functools import wraps
7
- from typing import Callable, Optional, TypeVar, cast
8
+ from typing import Callable, List, Optional, TypeVar, cast
8
9
 
9
10
  from cyberfusion.SystemdSupport._constants import SYSTEMCTL_BIN
11
+ from cyberfusion.SystemdSupport.exceptions import (
12
+ UnexpectedActiveStateError,
13
+ UnexpectedSubStateError,
14
+ )
10
15
  from cyberfusion.SystemdSupport.manager import SystemdManager
16
+ from cyberfusion.SystemdSupport.enums import ActiveState, SubState
11
17
 
12
18
  F = TypeVar("F", bound=Callable[..., None])
13
19
 
14
20
 
15
21
  BASE_DIRECTORY_SYSTEMD_UNITS = os.path.join(os.path.sep, "etc", "systemd", "system")
16
22
 
23
+ SYSTEMD_RUN_BIN = os.path.join(os.path.sep, "bin", "systemd-run")
24
+
17
25
 
18
26
  def reload_manager(f: F) -> F:
19
27
  """Reload manager configuration if needed.."""
@@ -182,3 +190,50 @@ class Unit:
182
190
  E.g.: `firewall` -> `firewall.service`
183
191
  """
184
192
  return unit_name + "." + unit_type
193
+
194
+
195
+ class TransientUnit:
196
+ """Represents transient unit created via systemd-run."""
197
+
198
+ def __init__(self, unit: Unit) -> None:
199
+ """Set attributes."""
200
+ self.unit = unit
201
+
202
+ @classmethod
203
+ def run(cls, name: str, command: List[str]) -> "TransientUnit":
204
+ """Start transient unit and return an instance wrapping the created unit."""
205
+ output = subprocess.run(
206
+ [
207
+ SYSTEMD_RUN_BIN,
208
+ "--json=short",
209
+ f"--unit={name}",
210
+ "--remain-after-exit",
211
+ *command,
212
+ ],
213
+ check=True,
214
+ stdout=subprocess.PIPE,
215
+ text=True,
216
+ ).stdout
217
+
218
+ return cls(Unit(json.loads(output)["unit"]))
219
+
220
+ def clean_up(self) -> None:
221
+ """Stop unit if active, or reset it if failed."""
222
+ sub_state = self.unit.get_property("SubState")
223
+
224
+ # A finished --remain-after-exit unit is either `exited` (success) or
225
+ # `failed`. Any other value means the unit is still `running`, or in
226
+ # some other state we don't handle — bail out so it can be debugged
227
+ # manually rather than silently tearing it down.
228
+
229
+ if sub_state not in (SubState.EXITED, SubState.FAILED):
230
+ raise UnexpectedSubStateError(self.unit.name, sub_state)
231
+
232
+ active_state = self.unit.get_property("ActiveState")
233
+
234
+ if active_state == ActiveState.ACTIVE:
235
+ subprocess.run([SYSTEMCTL_BIN, "stop", self.unit.name], check=True)
236
+ elif active_state == ActiveState.FAILED:
237
+ subprocess.run([SYSTEMCTL_BIN, "reset-failed", self.unit.name], check=True)
238
+ else:
239
+ raise UnexpectedActiveStateError(self.unit.name, active_state)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python3-cyberfusion-systemd-support
3
- Version: 2.4.0
3
+ Version: 2.5.0
4
4
  Summary: Library for systemd.
5
5
  Author-email: Cyberfusion <support@cyberfusion.io>
6
6
  Project-URL: Source, https://github.com/CyberfusionIO/python3-cyberfusion-systemd-support
@@ -52,6 +52,15 @@ print(unit.is_enabled)
52
52
  print(unit.is_failed)
53
53
  ```
54
54
 
55
+ ## Transient units
56
+
57
+ ```python
58
+ from cyberfusion.SystemdSupport.units import TransientUnit
59
+
60
+ transient_unit = TransientUnit.run(name="cf-apt-upgrade", command=["apt-get", "upgrade", "-y"])
61
+ transient_unit.clean_up()
62
+ ```
63
+
55
64
  ## Tmp files
56
65
 
57
66
  ```python
@@ -3,6 +3,8 @@ pyproject.toml
3
3
  setup.cfg
4
4
  src/cyberfusion/SystemdSupport/__init__.py
5
5
  src/cyberfusion/SystemdSupport/_constants.py
6
+ src/cyberfusion/SystemdSupport/enums.py
7
+ src/cyberfusion/SystemdSupport/exceptions.py
6
8
  src/cyberfusion/SystemdSupport/manager.py
7
9
  src/cyberfusion/SystemdSupport/tmp_files.py
8
10
  src/cyberfusion/SystemdSupport/units.py