]> git.proxmox.com Git - proxmox-backup.git/blame - src/server/config.rs
server/rest: implement request access log
[proxmox-backup.git] / src / server / config.rs
CommitLineData
16b48b81 1use std::collections::HashMap;
2ab5acac
DC
2use std::path::PathBuf;
3use std::time::SystemTime;
4use std::fs::metadata;
8e7e2223 5use std::sync::{Mutex, RwLock};
16b48b81 6
2ab5acac 7use anyhow::{bail, Error, format_err};
16b48b81 8use hyper::Method;
f9e3b110 9use handlebars::Handlebars;
2ab5acac 10use serde::Serialize;
16b48b81 11
a2479cfa 12use proxmox::api::{ApiMethod, Router, RpcEnvironmentType};
8e7e2223
TL
13use proxmox::tools::fs::{create_path, CreateOptions};
14
15use crate::tools::{FileLogger, FileLogOptions};
a2479cfa 16
16b48b81
DM
17pub struct ApiConfig {
18 basedir: PathBuf,
e63e99d6 19 router: &'static Router,
16b48b81 20 aliases: HashMap<String, PathBuf>,
02c7a755 21 env_type: RpcEnvironmentType,
2ab5acac
DC
22 templates: RwLock<Handlebars<'static>>,
23 template_files: RwLock<HashMap<String, (SystemTime, PathBuf)>>,
8e7e2223 24 request_log: Option<Mutex<FileLogger>>,
16b48b81
DM
25}
26
27impl ApiConfig {
28
f9e3b110 29 pub fn new<B: Into<PathBuf>>(basedir: B, router: &'static Router, env_type: RpcEnvironmentType) -> Result<Self, Error> {
f9e3b110 30 Ok(Self {
2ab5acac 31 basedir: basedir.into(),
653b1ca1 32 router,
16b48b81 33 aliases: HashMap::new(),
02c7a755 34 env_type,
2ab5acac
DC
35 templates: RwLock::new(Handlebars::new()),
36 template_files: RwLock::new(HashMap::new()),
8e7e2223 37 request_log: None,
f9e3b110 38 })
16b48b81
DM
39 }
40
255f378a
DM
41 pub fn find_method(
42 &self,
43 components: &[&str],
44 method: Method,
45 uri_param: &mut HashMap<String, String>,
46 ) -> Option<&'static ApiMethod> {
16b48b81 47
01bf3b7b 48 self.router.find_method(components, method, uri_param)
16b48b81
DM
49 }
50
51 pub fn find_alias(&self, components: &[&str]) -> PathBuf {
52
53 let mut prefix = String::new();
54 let mut filename = self.basedir.clone();
55 let comp_len = components.len();
56 if comp_len >= 1 {
57 prefix.push_str(components[0]);
58 if let Some(subdir) = self.aliases.get(&prefix) {
59 filename.push(subdir);
60 for i in 1..comp_len { filename.push(components[i]) }
8adbdb0a
DM
61 } else {
62 for i in 0..comp_len { filename.push(components[i]) }
16b48b81
DM
63 }
64 }
65 filename
66 }
67
68 pub fn add_alias<S, P>(&mut self, alias: S, path: P)
69 where S: Into<String>,
70 P: Into<PathBuf>,
71 {
72 self.aliases.insert(alias.into(), path.into());
73 }
02c7a755
DM
74
75 pub fn env_type(&self) -> RpcEnvironmentType {
76 self.env_type
77 }
2ab5acac
DC
78
79 pub fn register_template<P>(&self, name: &str, path: P) -> Result<(), Error>
80 where
81 P: Into<PathBuf>
82 {
83 if self.template_files.read().unwrap().contains_key(name) {
84 bail!("template already registered");
85 }
86
87 let path: PathBuf = path.into();
88 let metadata = metadata(&path)?;
89 let mtime = metadata.modified()?;
90
91 self.templates.write().unwrap().register_template_file(name, &path)?;
92 self.template_files.write().unwrap().insert(name.to_string(), (mtime, path));
93
94 Ok(())
95 }
96
97 /// Checks if the template was modified since the last rendering
98 /// if yes, it loads a the new version of the template
99 pub fn render_template<T>(&self, name: &str, data: &T) -> Result<String, Error>
100 where
101 T: Serialize,
102 {
103 let path;
104 let mtime;
105 {
106 let template_files = self.template_files.read().unwrap();
107 let (old_mtime, old_path) = template_files.get(name).ok_or_else(|| format_err!("template not found"))?;
108
109 mtime = metadata(old_path)?.modified()?;
110 if mtime <= *old_mtime {
111 return self.templates.read().unwrap().render(name, data).map_err(|err| format_err!("{}", err));
112 }
113 path = old_path.to_path_buf();
114 }
115
116 {
117 let mut template_files = self.template_files.write().unwrap();
118 let mut templates = self.templates.write().unwrap();
119
120 templates.register_template_file(name, &path)?;
121 template_files.insert(name.to_string(), (mtime, path));
122
123 templates.render(name, data).map_err(|err| format_err!("{}", err))
124 }
125 }
8e7e2223
TL
126
127 pub fn enable_file_log<P>(&mut self, path: P) -> Result<(), Error>
128 where
129 P: Into<PathBuf>
130 {
131 let path: PathBuf = path.into();
132 if let Some(base) = path.parent() {
133 if !base.exists() {
134 let backup_user = crate::backup::backup_user()?;
135 let opts = CreateOptions::new().owner(backup_user.uid).group(backup_user.gid);
136 create_path(base, None, Some(opts)).map_err(|err| format_err!("{}", err))?;
137 }
138 }
139
140 let logger_options = FileLogOptions {
141 append: true,
142 ..Default::default()
143 };
144 self.request_log = Some(Mutex::new(FileLogger::new(&path, logger_options)?));
145
146 Ok(())
147 }
148 pub fn get_file_log(&self) -> Option<&Mutex<FileLogger>> {
149 self.request_log.as_ref()
150 }
16b48b81 151}