4 use handlebars
::{Handlebars, Helper, Context, RenderError, RenderContext, Output, HelperResult}
;
6 use proxmox
::tools
::email
::sendmail
;
9 config
::verify
::VerificationJobConfig
,
12 GarbageCollectionStatus
,
14 tools
::format
::HumanByte
,
17 const GC_OK_TEMPLATE
: &str = r
###"
19 Datastore: {{datastore}}
20 Task ID: {{status.upid}}
21 Index file count: {{status.index-file-count}}
23 Removed garbage: {{human-bytes status.removed-bytes}}
24 Removed chunks: {{status.removed-chunks}}
25 Remove bad files: {{status.removed-bad}}
27 Bad files: {{status.still-bad}}
28 Pending removals: {{human-bytes status.pending-bytes}} (in {{status.pending-chunks}} chunks)
30 Original Data usage: {{human-bytes status.index-data-bytes}}
31 On Disk usage: {{human-bytes status.disk-bytes}} ({{relative-percentage status.disk-bytes status.index-data-bytes}})
32 On Disk chunks: {{status.disk-chunks}}
34 Deduplication Factor: {{deduplication-factor}}
36 Garbage collection successful.
41 const GC_ERR_TEMPLATE
: &str = r
###"
43 Datastore: {{datastore}}
45 Garbage collection failed: {{error}}
49 const VERIFY_OK_TEMPLATE
: &str = r
###"
52 Datastore: {{job.store}}
54 Verification successful.
58 const VERIFY_ERR_TEMPLATE
: &str = r
###"
61 Datastore: {{job.store}}
63 Verification failed on these snapshots:
71 lazy_static
::lazy_static
!{
73 static ref HANDLEBARS
: Handlebars
<'
static> = {
74 let mut hb
= Handlebars
::new();
76 hb
.set_strict_mode(true);
78 hb
.register_helper("human-bytes", Box
::new(handlebars_humam_bytes_helper
));
79 hb
.register_helper("relative-percentage", Box
::new(handlebars_relative_percentage_helper
));
81 hb
.register_template_string("gc_ok_template", GC_OK_TEMPLATE
).unwrap();
82 hb
.register_template_string("gc_err_template", GC_ERR_TEMPLATE
).unwrap();
84 hb
.register_template_string("verify_ok_template", VERIFY_OK_TEMPLATE
).unwrap();
85 hb
.register_template_string("verify_err_template", VERIFY_ERR_TEMPLATE
).unwrap();
91 fn send_job_status_mail(
95 ) -> Result
<(), Error
> {
97 // Note: OX has serious problems displaying text mails,
98 // so we include html as well
99 let html
= format
!("<html><body><pre>\n{}\n<pre>", text
);
101 let nodename
= proxmox
::tools
::nodename();
103 let author
= format
!("Proxmox Backup Server - {}", nodename
);
117 pub fn send_gc_status(
120 status
: &GarbageCollectionStatus
,
121 result
: &Result
<(), Error
>,
122 ) -> Result
<(), Error
> {
124 let text
= match result
{
126 let deduplication_factor
= if status
.disk_bytes
> 0 {
127 (status
.index_data_bytes
as f64)/(status
.disk_bytes
as f64)
134 "datastore": datastore
,
135 "deduplication-factor": format
!("{:.2}", deduplication_factor
),
138 HANDLEBARS
.render("gc_ok_template", &data
)?
142 "error": err
.to_string(),
143 "datastore": datastore
,
145 HANDLEBARS
.render("gc_err_template", &data
)?
149 let subject
= match result
{
151 "Garbage Collect Datastore '{}' successful",
155 "Garbage Collect Datastore '{}' failed",
160 send_job_status_mail(email
, &subject
, &text
)?
;
165 pub fn send_verify_status(
167 job
: VerificationJobConfig
,
168 result
: &Result
<Vec
<String
>, Error
>,
169 ) -> Result
<(), Error
> {
172 let text
= match result
{
173 Ok(errors
) if errors
.is_empty() => {
174 let data
= json
!({ "job": job }
);
175 HANDLEBARS
.render("verify_ok_template", &data
)?
178 let data
= json
!({ "job": job, "errors": errors }
);
179 HANDLEBARS
.render("verify_err_template", &data
)?
182 // aboreted job - do not send any email
187 let subject
= match result
{
188 Ok(errors
) if errors
.is_empty() => format
!(
189 "Verify Datastore '{}' successful",
193 "Verify Datastore '{}' failed",
198 send_job_status_mail(email
, &subject
, &text
)?
;
203 /// Lookup users email address
205 /// For "backup@pam", this returns the address from "root@pam".
206 pub fn lookup_user_email(userid
: &Userid
) -> Option
<String
> {
208 use crate::config
::user
::{self, User}
;
210 if userid
== Userid
::backup_userid() {
211 return lookup_user_email(Userid
::root_userid());
214 if let Ok(user_config
) = user
::cached_config() {
215 if let Ok(user
) = user_config
.lookup
::<User
>("user", userid
.as_str()) {
216 return user
.email
.clone();
223 // Handlerbar helper functions
225 fn handlebars_humam_bytes_helper(
229 _rc
: &mut RenderContext
,
232 let param
= h
.param(0).map(|v
| v
.value().as_u64())
234 .ok_or(RenderError
::new("human-bytes: param not found"))?
;
236 out
.write(&HumanByte
::from(param
).to_string())?
;
241 fn handlebars_relative_percentage_helper(
245 _rc
: &mut RenderContext
,
248 let param0
= h
.param(0).map(|v
| v
.value().as_f64())
250 .ok_or(RenderError
::new("relative-percentage: param0 not found"))?
;
251 let param1
= h
.param(1).map(|v
| v
.value().as_f64())
253 .ok_or(RenderError
::new("relative-percentage: param1 not found"))?
;
258 out
.write(&format
!("{:.2}%", (param0
*100.0)/param1
))?
;