use std::error::Error; use std::fmt; use std::io; use std::ops::Deref; use command_runner::CommandRunner; use symbols::Symbol; use symbols::file::File as FileSymbol; use resources::Resource; #[derive(Debug)] pub enum NginxServerError { ExecError(E), GenericError } impl From for NginxServerError { fn from(err: io::Error) -> NginxServerError { NginxServerError::ExecError(err) } } impl Error for NginxServerError { fn description(&self) -> &str { match self { &NginxServerError::ExecError(ref e) => e.description(), &NginxServerError::GenericError => "Generic error" } } fn cause(&self) -> Option<&Error> { match self { &NginxServerError::ExecError(ref e) => Some(e), _ => None } } } impl fmt::Display for NginxServerError { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { write!(f, "{}", self.description()) } } pub struct NginxServer<'a, C> where C: Deref { command_runner: &'a CommandRunner, file: FileSymbol>, } use std::borrow::Cow; impl<'a> NginxServer<'a, String> { pub fn new(socket_path: Option<&'a str>, domain: &'a str, static_path: &'a str, redir_domains: &[&'a str], command_runner: &'a CommandRunner) -> Self { let file_path: Cow = Cow::from(String::from("/etc/nginx/sites-enabled/") + domain); let redir_content = redir_domains.iter().map(|redir_domain| format!("server {{ listen 80; server_name {}; return 302 $scheme://{}$request_uri; }} ", redir_domain, domain)).fold(String::new(), |s, v| s + &v); let proxy_content = if let Some(socket) = socket_path { format!("location / {{ try_files $uri @proxy; }} location @proxy {{ include fastcgi_params; proxy_pass http://unix:{}:; proxy_redirect off; }}", socket) } else { "\ntry_files $uri $uri/ $uri.html =404;".to_string() }; // FIXME: This is a crude hack let content = String::from(redir_content) + &format!("server {{ listen 80; listen 443 ssl; ssl_certificate /etc/ssl/local_certs/{0}.crt; ssl_certificate_key /etc/ssl/private/{0}.key; server_name {}; root {}; include \"snippets/acme-challenge.conf\"; {} }} ", domain, static_path, proxy_content); NginxServer::new_generic(FileSymbol::new(file_path, content), command_runner) } pub fn new_generic(file: FileSymbol>, command_runner: &'a CommandRunner) -> Self { NginxServer { command_runner: command_runner, file: file } } } impl<'a, C> Symbol for NginxServer<'a, C> where C: Deref { fn target_reached(&self) -> Result> { if !try!(self.file.target_reached()) { return Ok(false); } // TODO: Could try to find out if the server is in the live config Ok(true) } fn execute(&self) -> Result<(), Box> { try!(self.file.execute()); try!(self.command_runner.run_with_args("systemctl", &["reload-or-restart", "nginx"])); Ok(()) } fn get_prerequisites(&self) -> Vec> { self.file.get_prerequisites() } } impl<'a, C> fmt::Display for NginxServer<'a, C> where C: Deref { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(),fmt::Error>{ write!(f, "Nginx server config") } }