Command runner args, Paths and AsRef

This commit is contained in:
Adrian Heine 2019-09-24 22:53:15 +02:00
parent 5d5e9dfcb4
commit 3ccf64fac1
32 changed files with 696 additions and 721 deletions

View file

@ -26,7 +26,7 @@ impl<'a, C: CommandRunner> Symbol for ReloadService<'a, C> {
fn execute(&self) -> Result<(), Box<dyn Error>> {
self
.command_runner
.run_successfully("systemctl", &["reload-or-restart", self.service])
.run_successfully("systemctl", args!["reload-or-restart", self.service])
}
fn as_action<'b>(&'b self, runner: &'b dyn SymbolRunner) -> Box<dyn Action + 'b> {

View file

@ -1,8 +1,12 @@
use std::borrow::Cow;
use std::error::Error;
use std::ffi::OsStr;
use std::fmt;
use std::fs;
use std::io;
use std::ops::Deref;
use std::path::Path;
use std::path::PathBuf;
use std::process::Output;
use std::thread::sleep;
use std::time::Duration;
@ -51,29 +55,23 @@ impl<E: Error> fmt::Display for UserServiceError<E> {
}
}
pub struct UserService<'a, C, R>
where
C: Deref<Target = str>,
R: CommandRunner,
{
pub struct UserService<'a, C: AsRef<str>, R: CommandRunner> {
socket_path: Cow<'a, Path>,
service_name: &'a str,
user_name: &'a str,
user_name: Cow<'a, str>,
command_runner: R,
file: FileSymbol<C, String>,
config: FileSymbol<C, PathBuf>,
}
impl<'a, R> UserService<'a, String, SetuidCommandRunner<'a, R>>
where
R: CommandRunner,
{
pub fn new_nodejs(
home: &'a str,
user_name: &'a str,
impl<'a, R: CommandRunner> UserService<'a, String, SetuidCommandRunner<'a, R>> {
pub fn new_nodejs<'b: 'a>(
home: Cow<'a, Path>,
user_name: Cow<'a, str>,
service_name: &'a str,
path: &'a str,
path: Cow<'a, Path>,
command_runner: &'a R,
socket_path: Cow<'a, Path>,
) -> Self {
let port = format!("/var/tmp/{}-{}.socket", user_name, service_name);
let content = format!(
"[Service]
Environment=NODE_ENV=production
@ -91,39 +89,46 @@ Restart=always
[Install]
WantedBy=default.target
",
path, port
path.to_str().unwrap(),
socket_path.to_str().unwrap()
);
UserService::new(home, user_name, service_name, command_runner, content)
UserService::new(
socket_path,
home,
user_name,
service_name,
command_runner,
content,
)
}
pub fn new(
home: &'a str,
user_name: &'a str,
socket_path: Cow<'a, Path>,
home: Cow<'a, Path>,
user_name: Cow<'a, str>,
service_name: &'a str,
command_runner: &'a R,
content: String,
) -> Self {
let file_path = format!(
"{}/.config/systemd/user/{}.service",
home.trim_end(),
service_name
);
let config_path: PathBuf = [
home.as_ref(),
format!(".config/systemd/user/{}.service", service_name).as_ref(),
]
.iter()
.collect();
UserService {
socket_path,
service_name,
user_name,
user_name: user_name.clone(),
command_runner: SetuidCommandRunner::new(user_name, command_runner),
file: FileSymbol::new(file_path, content),
config: FileSymbol::new(config_path, content),
}
}
}
impl<'a, C, R> UserService<'a, C, R>
where
C: Deref<Target = str>,
R: CommandRunner,
{
fn systemctl_wait_for_dbus(&self, args: &[&str]) -> Result<String, Box<dyn Error>> {
impl<'a, C: AsRef<str>, R: CommandRunner> UserService<'a, C, R> {
fn systemctl_wait_for_dbus(&self, args: &[&OsStr]) -> Result<String, Box<dyn Error>> {
let mut tries = 5;
loop {
let result = self.command_runner.run_with_args("systemctl", args)?;
@ -146,7 +151,7 @@ where
fn check_if_service(&self) -> Result<bool, Box<dyn Error>> {
loop {
let active_state = self.systemctl_wait_for_dbus(&[
let active_state = self.systemctl_wait_for_dbus(args![
"--user",
"show",
"--property",
@ -160,7 +165,7 @@ where
return Err(Box::new(
UserServiceError::ActivationFailed(self.command_runner.run_with_args(
"journalctl",
&["--user", &format!("--user-unit={}", self.service_name)],
args!["--user", format!("--user-unit={}", self.service_name)],
)) as UserServiceError<io::Error>,
))
}
@ -170,22 +175,18 @@ where
}
}
impl<'a, C, R> Symbol for UserService<'a, C, R>
where
C: Deref<Target = str>,
R: CommandRunner,
{
impl<'a, C: AsRef<str>, R: CommandRunner> Symbol for UserService<'a, C, R> {
fn target_reached(&self) -> Result<bool, Box<dyn Error>> {
if !(self.file.target_reached()?) {
if !(self.config.target_reached()?) {
return Ok(false);
}
self.check_if_service()
}
fn execute(&self) -> Result<(), Box<dyn Error>> {
self.file.execute()?;
self.systemctl_wait_for_dbus(&["--user", "enable", self.service_name])?;
self.systemctl_wait_for_dbus(&["--user", "restart", self.service_name])?;
self.config.execute()?;
self.systemctl_wait_for_dbus(args!["--user", "enable", self.service_name])?;
self.systemctl_wait_for_dbus(args!["--user", "restart", self.service_name])?;
if !(self.check_if_service()?) {
return Err(Box::new(
@ -193,8 +194,7 @@ where
));
}
let file_name = format!("/var/tmp/{}-{}.socket", self.user_name, self.service_name);
fs::metadata(&file_name)
fs::metadata(&self.socket_path)
.map(|_| ())
.map_err(|e| Box::new(e) as Box<dyn Error>)
}
@ -204,7 +204,7 @@ where
"file",
format!("/var/lib/systemd/linger/{}", self.user_name),
)];
r.extend(self.file.get_prerequisites().into_iter());
r.extend(self.config.get_prerequisites().into_iter());
r
}
@ -220,11 +220,7 @@ where
}
}
impl<'a, C, R> fmt::Display for UserService<'a, C, R>
where
C: Deref<Target = str>,
R: CommandRunner,
{
impl<'a, C: AsRef<str>, R: CommandRunner> fmt::Display for UserService<'a, C, R> {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(f, "Systemd user service unit for {}", self.service_name)
}

View file

@ -1,4 +1,3 @@
use std::borrow::{Borrow, Cow};
use std::error::Error;
use std::fmt;
use std::path::PathBuf;
@ -33,13 +32,13 @@ impl<E: Error> fmt::Display for SystemdUserSessionError<E> {
}
}
pub struct SystemdUserSession<'a, C: 'a + CommandRunner> {
user_name: Cow<'a, str>,
pub struct SystemdUserSession<'a, U: AsRef<str>, C: CommandRunner> {
user_name: U,
command_runner: &'a C,
}
impl<'a, C: CommandRunner> SystemdUserSession<'a, C> {
pub fn new(user_name: Cow<'a, str>, command_runner: &'a C) -> Self {
impl<'a, U: AsRef<str>, C: CommandRunner> SystemdUserSession<'a, U, C> {
pub fn new(user_name: U, command_runner: &'a C) -> Self {
SystemdUserSession {
user_name,
command_runner,
@ -47,10 +46,10 @@ impl<'a, C: CommandRunner> SystemdUserSession<'a, C> {
}
}
impl<'a, C: CommandRunner> Symbol for SystemdUserSession<'a, C> {
impl<'a, U: AsRef<str>, C: CommandRunner> Symbol for SystemdUserSession<'a, U, C> {
fn target_reached(&self) -> Result<bool, Box<dyn Error>> {
let mut path = PathBuf::from("/var/lib/systemd/linger");
path.push(self.user_name.borrow() as &str);
path.push(self.user_name.as_ref());
Ok(path.exists())
// Could also do `loginctl show-user ${self.user_name} | grep -F 'Linger=yes`
}
@ -58,7 +57,7 @@ impl<'a, C: CommandRunner> Symbol for SystemdUserSession<'a, C> {
fn execute(&self) -> Result<(), Box<dyn Error>> {
self
.command_runner
.run_successfully("loginctl", &["enable-linger", self.user_name.borrow()])
.run_successfully("loginctl", args!["enable-linger", self.user_name.as_ref()])
}
fn as_action<'b>(&'b self, runner: &'b dyn SymbolRunner) -> Box<dyn Action + 'b> {
@ -73,8 +72,8 @@ impl<'a, C: CommandRunner> Symbol for SystemdUserSession<'a, C> {
}
}
impl<'a, C: CommandRunner> fmt::Display for SystemdUserSession<'a, C> {
impl<'a, U: AsRef<str>, C: CommandRunner> fmt::Display for SystemdUserSession<'a, U, C> {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(f, "Systemd user session for {}", self.user_name)
write!(f, "Systemd user session for {}", self.user_name.as_ref())
}
}