Skip to content

Commit b2fe1a8

Browse files
committed
2024-12-23T18:31:46Z
1 parent 2036045 commit b2fe1a8

File tree

6 files changed

+271
-62
lines changed

6 files changed

+271
-62
lines changed

ominfra/manage/deploy/systemd.py

Lines changed: 48 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,16 @@
11
# ruff: noqa: UP006 UP007
22
"""
3-
~/.config/systemd/user/
4-
5-
verify - systemd-analyze
6-
7-
sudo loginctl enable-linger "$USER"
8-
9-
cat ~/.config/systemd/user/sleep-infinity.service
10-
[Unit]
11-
Description=User-specific service to run 'sleep infinity'
12-
After=default.target
13-
14-
[Service]
15-
ExecStart=/bin/sleep infinity
16-
Restart=always
17-
RestartSec=5
18-
19-
[Install]
20-
WantedBy=default.target
21-
22-
systemctl --user daemon-reload
23-
24-
systemctl --user enable sleep-infinity.service
25-
systemctl --user start sleep-infinity.service
26-
27-
systemctl --user status sleep-infinity.service
3+
TODO:
4+
- verify - systemd-analyze
5+
- sudo loginctl enable-linger "$USER"
6+
- idemp kill services that shouldn't be running, start ones that should
7+
- ideally only those defined by links to deploy home
288
"""
299
import os.path
10+
import sys
3011
import typing as ta
3112

13+
from omlish.asyncs.asyncio.subprocesses import asyncio_subprocesses
3214
from omlish.lite.check import check
3315
from omlish.os.paths import abs_real_path
3416
from omlish.os.paths import is_path_in_dir
@@ -73,13 +55,17 @@ async def sync_systemd(
7355
if not spec:
7456
return
7557

58+
#
59+
7660
if not (ud := spec.unit_dir):
7761
return
7862

7963
ud = abs_real_path(os.path.expanduser(ud))
8064

8165
os.makedirs(ud, exist_ok=True)
8266

67+
#
68+
8369
uld = {
8470
n: p
8571
for n, p in self._scan_link_dir(ud).items()
@@ -91,8 +77,11 @@ async def sync_systemd(
9177
else:
9278
cld = {}
9379

94-
for n in sorted(set(uld) | set(cld)):
95-
ul = uld.get(n) # noqa
80+
#
81+
82+
ns = sorted(set(uld) | set(cld))
83+
84+
for n in ns:
9685
cl = cld.get(n)
9786
if cl is None:
9887
os.unlink(os.path.join(ud, n))
@@ -108,3 +97,35 @@ async def sync_systemd(
10897
os.path.relpath(cl, os.path.dirname(dst_swap.dst_path)),
10998
dst_swap.tmp_path,
11099
)
100+
101+
#
102+
103+
if sys.platform == 'linux':
104+
async def reload() -> None:
105+
await asyncio_subprocesses.check_call('systemctl', '--user', 'daemon-reload')
106+
107+
await reload()
108+
109+
num_deleted = 0
110+
for n in ns:
111+
if n.endswith('.service'):
112+
cl = cld.get(n)
113+
ul = uld.get(n)
114+
if cl is not None:
115+
if ul is None:
116+
cs = ['enable', 'start']
117+
else:
118+
cs = ['restart']
119+
else: # noqa
120+
if ul is not None:
121+
cs = []
122+
# cs = ['stop']
123+
# num_deleted += 1
124+
else:
125+
cs = []
126+
127+
for c in cs:
128+
await asyncio_subprocesses.check_call('systemctl', '--user', c, n)
129+
130+
if num_deleted:
131+
await reload()

ominfra/manage/deploy/venvs.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
- share more code with pyproject?
66
"""
77
import os.path
8+
import shutil
89

910
from omdev.interp.default import get_default_interp_resolver
1011
from omdev.interp.types import InterpSpecifier
@@ -44,9 +45,12 @@ async def setup_venv(
4445

4546
if os.path.isfile(reqs_txt):
4647
if spec.use_uv:
47-
await asyncio_subprocesses.check_call(venv_exe, '-m', 'pip', 'install', 'uv')
48-
pip_cmd = ['-m', 'uv', 'pip']
48+
if shutil.which('uv') is not None:
49+
pip_cmd = ['uv', 'pip']
50+
else:
51+
await asyncio_subprocesses.check_call(venv_exe, '-m', 'pip', 'install', 'uv')
52+
pip_cmd = [venv_exe, '-m', 'uv', 'pip']
4953
else:
50-
pip_cmd = ['-m', 'pip']
54+
pip_cmd = [venv_exe, '-m', 'pip']
5155

52-
await asyncio_subprocesses.check_call(venv_exe, *pip_cmd,'install', '-r', reqs_txt)
56+
await asyncio_subprocesses.check_call(*pip_cmd, 'install', '-r', reqs_txt, cwd=venv_dir)

ominfra/scripts/manage.py

Lines changed: 53 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -10975,31 +10975,11 @@ def bind_deploy_paths() -> InjectorBindings:
1097510975
########################################
1097610976
# ../deploy/systemd.py
1097710977
"""
10978-
~/.config/systemd/user/
10979-
10980-
verify - systemd-analyze
10981-
10982-
sudo loginctl enable-linger "$USER"
10983-
10984-
cat ~/.config/systemd/user/sleep-infinity.service
10985-
[Unit]
10986-
Description=User-specific service to run 'sleep infinity'
10987-
After=default.target
10988-
10989-
[Service]
10990-
ExecStart=/bin/sleep infinity
10991-
Restart=always
10992-
RestartSec=5
10993-
10994-
[Install]
10995-
WantedBy=default.target
10996-
10997-
systemctl --user daemon-reload
10998-
10999-
systemctl --user enable sleep-infinity.service
11000-
systemctl --user start sleep-infinity.service
11001-
11002-
systemctl --user status sleep-infinity.service
10978+
TODO:
10979+
- verify - systemd-analyze
10980+
- sudo loginctl enable-linger "$USER"
10981+
- idemp kill services that shouldn't be running, start ones that should
10982+
- ideally only those defined by links to deploy home
1100310983
"""
1100410984

1100510985

@@ -11038,13 +11018,17 @@ async def sync_systemd(
1103811018
if not spec:
1103911019
return
1104011020

11021+
#
11022+
1104111023
if not (ud := spec.unit_dir):
1104211024
return
1104311025

1104411026
ud = abs_real_path(os.path.expanduser(ud))
1104511027

1104611028
os.makedirs(ud, exist_ok=True)
1104711029

11030+
#
11031+
1104811032
uld = {
1104911033
n: p
1105011034
for n, p in self._scan_link_dir(ud).items()
@@ -11056,8 +11040,11 @@ async def sync_systemd(
1105611040
else:
1105711041
cld = {}
1105811042

11059-
for n in sorted(set(uld) | set(cld)):
11060-
ul = uld.get(n) # noqa
11043+
#
11044+
11045+
ns = sorted(set(uld) | set(cld))
11046+
11047+
for n in ns:
1106111048
cl = cld.get(n)
1106211049
if cl is None:
1106311050
os.unlink(os.path.join(ud, n))
@@ -11074,6 +11061,38 @@ async def sync_systemd(
1107411061
dst_swap.tmp_path,
1107511062
)
1107611063

11064+
#
11065+
11066+
if sys.platform == 'linux':
11067+
async def reload() -> None:
11068+
await asyncio_subprocesses.check_call('systemctl', '--user', 'daemon-reload')
11069+
11070+
await reload()
11071+
11072+
num_deleted = 0
11073+
for n in ns:
11074+
if n.endswith('.service'):
11075+
cl = cld.get(n)
11076+
ul = uld.get(n)
11077+
if cl is not None:
11078+
if ul is None:
11079+
cs = ['enable', 'start']
11080+
else:
11081+
cs = ['restart']
11082+
else: # noqa
11083+
if ul is not None:
11084+
cs = []
11085+
# cs = ['stop']
11086+
# num_deleted += 1
11087+
else:
11088+
cs = []
11089+
11090+
for c in cs:
11091+
await asyncio_subprocesses.check_call('systemctl', '--user', c, n)
11092+
11093+
if num_deleted:
11094+
await reload()
11095+
1107711096

1107811097
########################################
1107911098
# ../remote/inject.py
@@ -11455,12 +11474,15 @@ async def setup_venv(
1145511474

1145611475
if os.path.isfile(reqs_txt):
1145711476
if spec.use_uv:
11458-
await asyncio_subprocesses.check_call(venv_exe, '-m', 'pip', 'install', 'uv')
11459-
pip_cmd = ['-m', 'uv', 'pip']
11477+
if shutil.which('uv') is not None:
11478+
pip_cmd = ['uv', 'pip']
11479+
else:
11480+
await asyncio_subprocesses.check_call(venv_exe, '-m', 'pip', 'install', 'uv')
11481+
pip_cmd = [venv_exe, '-m', 'uv', 'pip']
1146011482
else:
11461-
pip_cmd = ['-m', 'pip']
11483+
pip_cmd = [venv_exe, '-m', 'pip']
1146211484

11463-
await asyncio_subprocesses.check_call(venv_exe, *pip_cmd,'install', '-r', reqs_txt)
11485+
await asyncio_subprocesses.check_call(*pip_cmd, 'install', '-r', reqs_txt, cwd=venv_dir)
1146411486

1146511487

1146611488
########################################

ominfra/systemd.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# ruff: noqa: UP006 UP007
2+
# @omlish-lite
3+
import dataclasses as dc
4+
import typing as ta
5+
6+
7+
##
8+
9+
10+
@dc.dataclass(frozen=True)
11+
class SystemdListUnit:
12+
unit: str
13+
load: str # loaded, not-found
14+
active: str # active, inactive
15+
sub: str # running, exited, dead
16+
description: str
17+
18+
@classmethod
19+
def parse(cls, s: str) -> 'SystemdListUnit':
20+
return SystemdListUnit(*[p.strip() for p in s.strip().split(None, 4)])
21+
22+
@classmethod
23+
def parse_all(cls, s: str) -> ta.List['SystemdListUnit']:
24+
return [
25+
cls.parse(sl)
26+
for l in s.strip().splitlines()
27+
if (sl := l.strip())
28+
]
29+
30+
31+
32+
PARSABLE_SYSTEMD_LIST_UNIT_ARGS = [
33+
'--all',
34+
'--no-legend',
35+
'--no-pager',
36+
'--plain',
37+
]
38+
39+
40+
##
41+
42+
43+
def parse_systemd_show_output(s: str) -> ta.Mapping[str, str]:
44+
d: ta.Dict[str, str] = {}
45+
for l in s.strip().splitlines():
46+
if not (l := l.strip()):
47+
continue
48+
k, _, v = l.partition('=')
49+
d[k] = v
50+
return d

ominfra/tests/test_systemd.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# ruff: noqa: PT009 UP006 UP007
2+
# @omlish-lite
3+
import unittest
4+
5+
from ..systemd import SystemdListUnit
6+
7+
8+
class TestSystemd(unittest.TestCase):
9+
def test_list_unit(self):
10+
s = """\
11+
sleep-infinity.service loaded active running User-specific service to run 'sleep infinity'
12+
supervisor.service not-found active running supervisor.service
13+
systemd-tmpfiles-setup.service loaded active exited Create User's Volatile Files and Directories
14+
"""
15+
self.assertEqual(
16+
SystemdListUnit.parse_all(s),
17+
[
18+
SystemdListUnit(
19+
unit='sleep-infinity.service',
20+
load='loaded',
21+
active='active',
22+
sub='running',
23+
description="User-specific service to run 'sleep infinity'",
24+
),
25+
SystemdListUnit(
26+
unit='supervisor.service',
27+
load='not-found',
28+
active='active',
29+
sub='running',
30+
description='supervisor.service',
31+
),
32+
SystemdListUnit(
33+
unit='systemd-tmpfiles-setup.service',
34+
load='loaded',
35+
active='active',
36+
sub='exited',
37+
description="Create User's Volatile Files and Directories",
38+
),
39+
],
40+
)

0 commit comments

Comments
 (0)