Skip to content

Commit

Permalink
Update operations that run system commands to use trio.to_thread.run_…
Browse files Browse the repository at this point in the history
…sync
  • Loading branch information
merlinz01 committed Dec 4, 2024
1 parent 23a5089 commit 38beee4
Show file tree
Hide file tree
Showing 7 changed files with 71 additions and 13 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

This is the changelog for RedPepper.

## [Unreleased]

### Changed

- Update operations that run system commands to use `trio.to_thread.run_sync` for better concurrency.

## [0.3.0]

### Changed
Expand Down
19 changes: 16 additions & 3 deletions src/operations/redpepper/operations/apt.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import functools
import logging
import subprocess

import trio

from redpepper.operations import Operation, Result

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -29,7 +32,9 @@ async def test(self, agent):
logger.debug(
"Testing if apt package %s is installed with command %r", self.name, cmd
)
p = subprocess.run(cmd, capture_output=True, text=True)
p = await trio.to_thread.run_sync(
functools.partial(subprocess.run, cmd, capture_output=True, text=True)
)
if p.returncode == 1:
logger.debug("dpkg-query returned 1")
return False
Expand Down Expand Up @@ -63,7 +68,11 @@ async def run(self, agent):
env["APT_LISTCHANGES_FRONTEND"] = "none" # don't show changelogs
env["APT_LISTBUGS_FRONTEND"] = "none" # don't show bug reports
env["UCF_FORCE_CONFFOLD"] = "1" # keep old config files
p = subprocess.run(cmd, capture_output=True, text=True, env=env)
p = await trio.to_thread.run_sync(
functools.partial(
subprocess.run, cmd, capture_output=True, text=True, env=env
)
)
if result.check_completed_process(p).succeeded:
result.changed = "Setting up" in p.stdout
return result
Expand All @@ -79,7 +88,11 @@ async def run(self, agent):
await Installed("unattended-upgrades").ensure(agent)
).succeeded:
return result
p = subprocess.run(["unattended-upgrades"], capture_output=True, text=True)
p = await trio.to_thread.run_sync(
functools.partial(
subprocess.run, ["unattended-upgrades"], capture_output=True, text=True
)
)
if result.check_completed_process(p).succeeded:
result.changed = result.changed or p.stdout != ""
return result
5 changes: 5 additions & 0 deletions src/operations/redpepper/operations/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
import pwd
import subprocess

import trio

from redpepper.operations import Operation, Result


Expand Down Expand Up @@ -55,6 +57,9 @@ def __str__(self):
return f'Run("{self.command}{"" if self.wait else " &"}"{" as " + self.user if self.user else ""})'

async def run(self, agent):
return await trio.to_thread.run_sync(self._run)

def _run(self):
result = Result(self)
kw = {}
kw["env"] = os.environ.copy()
Expand Down
14 changes: 12 additions & 2 deletions src/operations/redpepper/operations/git.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import functools
import os
import pwd
import subprocess

import trio

from redpepper.operations import Operation, Result


Expand Down Expand Up @@ -72,8 +75,15 @@ async def ensure(self, agent):
if self.identity:
kw["env"]["GIT_SSH_COMMAND"] = f'ssh -i "{self.identity}"'

p = subprocess.run(
git_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, **kw
p = await trio.to_thread.run_sync(
functools.partial(
subprocess.run,
git_cmd,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
**kw,
)
)
if not result.check_completed_process(p).succeeded:
return result
Expand Down
4 changes: 3 additions & 1 deletion src/operations/redpepper/operations/py.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import trio

from redpepper.operations import Operation, Result


Expand All @@ -20,7 +22,7 @@ def __str__(self):
async def ensure(self, agent):
result = Result(self)
try:
exec(self.script, self.env, locals())
await trio.to_thread.run_sync(exec, self.script, self.env, locals())
except Exception:
result.exception()
return result
9 changes: 8 additions & 1 deletion src/operations/redpepper/operations/sysctl.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import functools
import os
import subprocess
import sys

import trio

from redpepper.operations import Operation, Result

if sys.platform != "linux":
Expand Down Expand Up @@ -53,6 +56,10 @@ async def run(self, agent):
f'Added sysctl parameter "{self.name} = {self.value}" to {SYSCTL_CONF_PATH}'
)
result.changed = True
p = subprocess.run(["sysctl", "--system"], capture_output=True, text=True)
p = await trio.to_thread.run_sync(
functools.partial(
subprocess.run, ["sysctl", "--system"], capture_output=True, text=True
)
)
result.check_completed_process(p)
return result
27 changes: 21 additions & 6 deletions src/operations/redpepper/operations/systemd.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import functools
import subprocess

import trio

from redpepper.operations import Operation, Result


Expand All @@ -14,13 +17,17 @@ def __str__(self):

async def test(self, agent):
cmd = ["systemctl", "is-active", self.name]
p = subprocess.run(cmd, stdout=subprocess.DEVNULL)
p = await trio.to_thread.run_sync(
functools.partial(subprocess.run, cmd, stdout=subprocess.DEVNULL)
)
return p.returncode == 0

async def run(self, agent):
result = Result(self)
cmd = ["systemctl", "start", self.name]
p = subprocess.run(cmd, capture_output=True, text=True)
p = await trio.to_thread.run_sync(
functools.partial(subprocess.run, cmd, capture_output=True, text=True)
)
if result.check_completed_process(p).succeeded:
result += f"Service {self.name} started."
result.changed = True
Expand All @@ -38,13 +45,17 @@ def __str__(self):

async def test(self, agent):
cmd = ["systemctl", "is-enabled", self.name]
p = subprocess.run(cmd, stdout=subprocess.DEVNULL)
p = await trio.to_thread.run_sync(
functools.partial(subprocess.run, cmd, stdout=subprocess.DEVNULL)
)
return p.returncode == 0

async def run(self, agent):
result = Result(self)
cmd = ["systemctl", "enable", self.name]
p = subprocess.run(cmd, capture_output=True, text=True)
p = await trio.to_thread.run_sync(
functools.partial(subprocess.run, cmd, capture_output=True, text=True)
)
if result.check_completed_process(p).succeeded:
result += f"Service {self.name} enabled."
result.changed = True
Expand All @@ -61,7 +72,9 @@ def __str__(self):
async def run(self, agent):
result = Result(self)
cmd = ["systemctl", "restart", self.name]
p = subprocess.run(cmd, capture_output=True, text=True)
p = await trio.to_thread.run_sync(
functools.partial(subprocess.run, cmd, capture_output=True, text=True)
)
if result.check_completed_process(p).succeeded:
result += f"Service {self.name} restarted."
result.changed = True
Expand All @@ -78,7 +91,9 @@ def __str__(self):
async def run(self, agent):
result = Result(self)
cmd = ["systemctl", "reload", self.name]
p = subprocess.run(cmd, capture_output=True, text=True)
p = await trio.to_thread.run_sync(
functools.partial(subprocess.run, cmd, capture_output=True, text=True)
)
if result.check_completed_process(p).succeeded:
result += f"Service {self.name} reloaded."
result.changed = True
Expand Down

0 comments on commit 38beee4

Please sign in to comment.