Update
This commit is contained in:
parent
d5a3a85e9a
commit
1bb22db692
10 changed files with 248 additions and 16 deletions
|
|
@ -1,11 +1,7 @@
|
||||||
use std::borrow::Cow;
|
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::io::{Read, Write};
|
|
||||||
use std::ops::Deref;
|
|
||||||
use std::path::Path;
|
|
||||||
|
|
||||||
use symbols::Symbol;
|
use symbols::Symbol;
|
||||||
|
|
||||||
|
|
|
||||||
49
src/symbols/dir_for.rs
Normal file
49
src/symbols/dir_for.rs
Normal file
|
|
@ -0,0 +1,49 @@
|
||||||
|
use std::error::Error;
|
||||||
|
use std::fmt;
|
||||||
|
use std::fs;
|
||||||
|
use std::os::unix::fs::MetadataExt;
|
||||||
|
|
||||||
|
use users::get_user_by_name;
|
||||||
|
|
||||||
|
use symbols::Symbol;
|
||||||
|
use symbols::dir::Dir;
|
||||||
|
use command_runner::CommandRunner;
|
||||||
|
|
||||||
|
|
||||||
|
pub struct DirFor<'a, D> where D: AsRef<str> + fmt::Display {
|
||||||
|
dir: Dir<D>,
|
||||||
|
path: D,
|
||||||
|
user_name: &'a str,
|
||||||
|
command_runner: &'a CommandRunner
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, D> DirFor<'a, D> where D: AsRef<str> + fmt::Display + Clone {
|
||||||
|
pub fn new(path: D, user_name: &'a str, command_runner: &'a CommandRunner) -> Self {
|
||||||
|
DirFor { dir: Dir::new(path.clone()), path: path, user_name: user_name, command_runner: command_runner }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, D> Symbol for DirFor<'a, D> where D: AsRef<str> + fmt::Display {
|
||||||
|
fn target_reached(&self) -> Result<bool, Box<Error>> {
|
||||||
|
match self.dir.target_reached() {
|
||||||
|
Ok(true) => {
|
||||||
|
let actual_uid = fs::metadata(self.path.as_ref()).unwrap().uid();
|
||||||
|
let target_uid = get_user_by_name(self.user_name).unwrap().uid();
|
||||||
|
Ok(actual_uid == target_uid)
|
||||||
|
},
|
||||||
|
res => res
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn execute(&self) -> Result<(), Box<Error>> {
|
||||||
|
try!(self.dir.execute());
|
||||||
|
try!(self.command_runner.run_with_args("chown", &[self.user_name, self.path.as_ref()]));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, D> fmt::Display for DirFor<'a, D> where D: AsRef<str> + fmt::Display {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error>{
|
||||||
|
write!(f, "Dir {} for {}", self.path, self.user_name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
use std::borrow::Cow;
|
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::fs::File as FsFile;
|
use std::fs::File as FsFile;
|
||||||
|
|
|
||||||
2
src/symbols/git/mod.rs
Normal file
2
src/symbols/git/mod.rs
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
pub mod checkout;
|
||||||
|
pub mod submodules;
|
||||||
50
src/symbols/git/submodules.rs
Normal file
50
src/symbols/git/submodules.rs
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
use std::error::Error;
|
||||||
|
use std::fmt;
|
||||||
|
use std::io;
|
||||||
|
|
||||||
|
use command_runner::CommandRunner;
|
||||||
|
use symbols::Symbol;
|
||||||
|
|
||||||
|
pub struct GitSubmodules<'a> {
|
||||||
|
target: &'a str,
|
||||||
|
command_runner: &'a CommandRunner
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> GitSubmodules<'a> {
|
||||||
|
pub fn new(target: &'a str, command_runner: &'a CommandRunner) -> GitSubmodules<'a> {
|
||||||
|
GitSubmodules {
|
||||||
|
target: target,
|
||||||
|
command_runner: command_runner
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> fmt::Display for GitSubmodules<'a> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "Submodules for {}", self.target)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> GitSubmodules<'a> {
|
||||||
|
fn _run_in_target_repo(&self, args: &[&str]) -> Result<Vec<u8>, io::Error> {
|
||||||
|
let mut new_args = vec!["-C", self.target];
|
||||||
|
new_args.extend_from_slice(args);
|
||||||
|
self.command_runner.run_with_args("git", &new_args).map(|res| res.stdout)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Symbol for GitSubmodules<'a> {
|
||||||
|
fn target_reached(&self) -> Result<bool, Box<Error>> {
|
||||||
|
let output = try!(self._run_in_target_repo(&["submodule", "status"]));
|
||||||
|
Ok(String::from_utf8(output).unwrap().lines().all(|line| line.len() == 0 || line.starts_with(' ')))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn execute(&self) -> Result<(), Box<Error>> {
|
||||||
|
try!(self._run_in_target_repo(&["submodule", "update", "--init"]));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
}
|
||||||
117
src/symbols/list.rs
Normal file
117
src/symbols/list.rs
Normal file
|
|
@ -0,0 +1,117 @@
|
||||||
|
use std::error::Error;
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
use symbols::Symbol;
|
||||||
|
|
||||||
|
pub struct List<'a> {
|
||||||
|
symbols: Vec<Box<Symbol + 'a>>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> List<'a> {
|
||||||
|
pub fn new(symbols: Vec<Box<Symbol + 'a>>) -> Self {
|
||||||
|
List { symbols: symbols }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Symbol for List<'a> {
|
||||||
|
fn target_reached(&self) -> Result<bool, Box<Error>> {
|
||||||
|
for symbol in &self.symbols {
|
||||||
|
match symbol.target_reached() {
|
||||||
|
Ok(false) => return Ok(false),
|
||||||
|
Err(e) => return Err(e),
|
||||||
|
Ok(true) => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn execute(&self) -> Result<(), Box<Error>> {
|
||||||
|
for symbol in &self.symbols {
|
||||||
|
try!(symbol.execute());
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> fmt::Display for List<'a> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error>{
|
||||||
|
try!(write!(f, "List [ "));
|
||||||
|
for symbol in &self.symbols {
|
||||||
|
try!(write!(f, "{} ", symbol));
|
||||||
|
}
|
||||||
|
write!(f, "]")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use std::error::Error;
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
use symbols::Symbol;
|
||||||
|
use symbols::hook::List;
|
||||||
|
|
||||||
|
struct ErrSymbol(String);
|
||||||
|
impl Symbol for ErrSymbol {
|
||||||
|
fn target_reached(&self) -> Result<bool, Box<Error>> { Err(self.0.clone().into()) }
|
||||||
|
fn execute(&self) -> Result<(), Box<Error>> { Err(self.0.clone().into()) }
|
||||||
|
}
|
||||||
|
impl fmt::Display for ErrSymbol { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error>{ write!(f, "") } }
|
||||||
|
|
||||||
|
struct OkSymbol(bool);
|
||||||
|
impl Symbol for OkSymbol {
|
||||||
|
fn target_reached(&self) -> Result<bool, Box<Error>> { Ok(self.0) }
|
||||||
|
fn execute(&self) -> Result<(), Box<Error>> { Ok(()) }
|
||||||
|
}
|
||||||
|
impl fmt::Display for OkSymbol { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error>{ write!(f, "") } }
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn first_target_reached_fails() {
|
||||||
|
let res = List::new(ErrSymbol("first".into()), ErrSymbol("second".into())).target_reached();
|
||||||
|
assert_eq!(res.unwrap_err().description(), "first");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn first_target_not_reached() {
|
||||||
|
let res = List::new(OkSymbol(false), ErrSymbol("second".into())).target_reached();
|
||||||
|
assert_eq!(res.unwrap(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn second_target_reached_fails() {
|
||||||
|
let res = List::new(OkSymbol(true), ErrSymbol("second".into())).target_reached();
|
||||||
|
assert_eq!(res.unwrap_err().description(), "second");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn second_target_not_reached() {
|
||||||
|
let res = List::new(OkSymbol(true), OkSymbol(false)).target_reached();
|
||||||
|
assert_eq!(res.unwrap(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn everything_reached() {
|
||||||
|
let res = List::new(OkSymbol(true), OkSymbol(true)).target_reached();
|
||||||
|
assert_eq!(res.unwrap(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn first_execute_fails() {
|
||||||
|
let res = List::new(ErrSymbol("first".into()), ErrSymbol("second".into())).execute();
|
||||||
|
assert_eq!(res.unwrap_err().description(), "first");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn second_execute_fails() {
|
||||||
|
let res = List::new(OkSymbol(true), ErrSymbol("second".into())).execute();
|
||||||
|
assert_eq!(res.unwrap_err().description(), "second");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn everything_executes() {
|
||||||
|
let res = List::new(OkSymbol(true), OkSymbol(true)).execute();
|
||||||
|
assert_eq!(res.unwrap(), ());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
use std::borrow::Cow;
|
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
use resources::Resource;
|
use resources::Resource;
|
||||||
|
|
@ -12,6 +11,7 @@ pub trait Symbol: Display {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod dir;
|
pub mod dir;
|
||||||
|
pub mod dir_for;
|
||||||
pub mod file;
|
pub mod file;
|
||||||
pub mod git;
|
pub mod git;
|
||||||
pub mod npm;
|
pub mod npm;
|
||||||
|
|
@ -19,3 +19,4 @@ pub mod user;
|
||||||
pub mod systemd;
|
pub mod systemd;
|
||||||
pub mod nginx;
|
pub mod nginx;
|
||||||
pub mod hook;
|
pub mod hook;
|
||||||
|
pub mod list;
|
||||||
|
|
|
||||||
|
|
@ -57,9 +57,9 @@ impl<'a> NginxServer<'a, String> {
|
||||||
|
|
||||||
server_name {};
|
server_name {};
|
||||||
return 302 $scheme://{}$request_uri;
|
return 302 $scheme://{}$request_uri;
|
||||||
}}
|
}}
|
||||||
|
|
||||||
", redir_domain, domain)).fold(String::new(), |s, v| s + &v);
|
", redir_domain, domain)).fold(String::new(), |s, v| s + &v);
|
||||||
|
|
||||||
let proxy_content = if let Some(socket) = socket_path {
|
let proxy_content = if let Some(socket) = socket_path {
|
||||||
format!("location / {{
|
format!("location / {{
|
||||||
|
|
@ -71,7 +71,7 @@ location @proxy {{
|
||||||
proxy_pass http://unix:{}:;
|
proxy_pass http://unix:{}:;
|
||||||
proxy_redirect off;
|
proxy_redirect off;
|
||||||
}}", socket)
|
}}", socket)
|
||||||
} else { "".to_string() };
|
} else { "\ntry_files $uri $uri/ $uri.html =404;".to_string() }; // FIXME: This is a crude hack
|
||||||
|
|
||||||
let content = String::from(redir_content) + &format!("server {{
|
let content = String::from(redir_content) + &format!("server {{
|
||||||
listen 80;
|
listen 80;
|
||||||
|
|
@ -82,7 +82,8 @@ location @proxy {{
|
||||||
|
|
||||||
root {};
|
root {};
|
||||||
{}
|
{}
|
||||||
}}", domain, static_path, proxy_content);
|
}}
|
||||||
|
", domain, static_path, proxy_content);
|
||||||
NginxServer {
|
NginxServer {
|
||||||
command_runner: command_runner,
|
command_runner: command_runner,
|
||||||
file: FileSymbol::new(file_path, content)
|
file: FileSymbol::new(file_path, content)
|
||||||
|
|
|
||||||
|
|
@ -68,6 +68,8 @@ impl<'a> NodeJsSystemdUserService<'a, Cow<'a, str>, String> {
|
||||||
|
|
||||||
let content = format!("[Service]
|
let content = format!("[Service]
|
||||||
ExecStartPre=rm /var/tmp/{1}-{2}.socket
|
ExecStartPre=rm /var/tmp/{1}-{2}.socket
|
||||||
|
# This only works if the path is a directory
|
||||||
|
WorkingDirectory={0}
|
||||||
ExecStart=/usr/bin/nodejs {0}
|
ExecStart=/usr/bin/nodejs {0}
|
||||||
Restart=always
|
Restart=always
|
||||||
Environment=NODE_ENV=production
|
Environment=NODE_ENV=production
|
||||||
|
|
@ -138,12 +140,27 @@ impl<'a, P, C> Symbol for NodeJsSystemdUserService<'a, P, C> where P: AsRef<str>
|
||||||
let file_name = format!("/var/tmp/{}-{}.socket", self.user_name, self.name);
|
let file_name = format!("/var/tmp/{}-{}.socket", self.user_name, self.name);
|
||||||
// try!(self.command_runner.run_with_args("chmod", &["666", &file_name]));
|
// try!(self.command_runner.run_with_args("chmod", &["666", &file_name]));
|
||||||
|
|
||||||
sleep(Duration::from_millis(500));
|
let mut tries = 5;
|
||||||
let metadata = try!(fs::metadata(file_name.clone()));
|
loop {
|
||||||
let mut perms = metadata.permissions();
|
let metadata = fs::metadata(file_name.clone());
|
||||||
perms.set_mode(0o666);
|
match metadata {
|
||||||
try!(fs::set_permissions(file_name, perms));
|
Ok(metadata) => {
|
||||||
|
let mut perms = metadata.permissions();
|
||||||
|
perms.set_mode(0o666);
|
||||||
|
try!(fs::set_permissions(file_name, perms));
|
||||||
|
break;
|
||||||
|
},
|
||||||
|
Err(e) => {
|
||||||
|
if e.kind() == io::ErrorKind::NotFound {
|
||||||
|
tries -= 1;
|
||||||
|
if tries == 0 { return Err("Gave up waiting for socket to appear".to_string().into()); }
|
||||||
|
sleep(Duration::from_millis(500));
|
||||||
|
} else {
|
||||||
|
return Err(Box::new(e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue