]> git.proxmox.com Git - proxmox-backup.git/blob - src/bin/proxmox-daily-update.rs
api: use if-let pattern for error-only handling
[proxmox-backup.git] / src / bin / proxmox-daily-update.rs
1 use anyhow::Error;
2 use serde_json::json;
3
4 use proxmox_router::{cli::*, ApiHandler, RpcEnvironment};
5 use proxmox_subscription::SubscriptionStatus;
6 use proxmox_sys::fs::CreateOptions;
7
8 use proxmox_backup::api2;
9
10 async fn wait_for_local_worker(upid_str: &str) -> Result<(), Error> {
11 let upid: pbs_api_types::UPID = upid_str.parse()?;
12 let poll_delay = core::time::Duration::from_millis(100);
13
14 loop {
15 if !proxmox_rest_server::worker_is_active_local(&upid) {
16 break;
17 }
18 tokio::time::sleep(poll_delay).await;
19 }
20 Ok(())
21 }
22
23 /// Daily update
24 async fn do_update(rpcenv: &mut dyn RpcEnvironment) -> Result<(), Error> {
25 let param = json!({});
26
27 let method = &api2::node::subscription::API_METHOD_CHECK_SUBSCRIPTION;
28 match method.handler {
29 ApiHandler::Sync(handler) => {
30 if let Err(err) = (handler)(param.clone(), method, rpcenv) {
31 log::error!("Error checking subscription - {err}");
32 }
33 }
34 _ => unreachable!(),
35 }
36 let notify = match api2::node::subscription::get_subscription(param, rpcenv) {
37 Ok(info) => info.status == SubscriptionStatus::Active,
38 Err(err) => {
39 log::error!("Error reading subscription - {err}");
40 false
41 }
42 };
43
44 let param = json!({
45 "notify": notify,
46 });
47 let method = &api2::node::apt::API_METHOD_APT_UPDATE_DATABASE;
48 match method.handler {
49 ApiHandler::Sync(handler) => match (handler)(param, method, rpcenv) {
50 Err(err) => {
51 log::error!("Error triggering apt database update - {err}");
52 }
53 Ok(upid) => wait_for_local_worker(upid.as_str().unwrap()).await?,
54 },
55 _ => unreachable!(),
56 };
57
58 if let Err(err) = check_acme_certificates(rpcenv).await {
59 log::error!("error checking certificates: {err}");
60 }
61
62 // TODO: cleanup tasks like in PVE?
63
64 Ok(())
65 }
66
67 async fn check_acme_certificates(rpcenv: &mut dyn RpcEnvironment) -> Result<(), Error> {
68 let (config, _) = proxmox_backup::config::node::config()?;
69
70 // do we even have any acme domains configures?
71 if config.acme_domains().next().is_none() {
72 return Ok(());
73 }
74
75 if !api2::node::certificates::cert_expires_soon()? {
76 log::info!("Certificate does not expire within the next 30 days, not renewing.");
77 return Ok(());
78 }
79
80 let info = &api2::node::certificates::API_METHOD_RENEW_ACME_CERT;
81 let result = match info.handler {
82 ApiHandler::Sync(handler) => (handler)(json!({}), info, rpcenv)?,
83 _ => unreachable!(),
84 };
85 wait_for_local_worker(result.as_str().unwrap()).await?;
86
87 Ok(())
88 }
89
90 async fn run(rpcenv: &mut dyn RpcEnvironment) -> Result<(), Error> {
91 let backup_user = pbs_config::backup_user()?;
92 let file_opts = CreateOptions::new()
93 .owner(backup_user.uid)
94 .group(backup_user.gid);
95 proxmox_rest_server::init_worker_tasks(
96 pbs_buildcfg::PROXMOX_BACKUP_LOG_DIR_M!().into(),
97 file_opts.clone(),
98 )?;
99
100 let mut command_sock = proxmox_rest_server::CommandSocket::new(
101 proxmox_rest_server::our_ctrl_sock(),
102 backup_user.gid,
103 );
104 proxmox_rest_server::register_task_control_commands(&mut command_sock)?;
105 command_sock.spawn()?;
106
107 do_update(rpcenv).await
108 }
109
110 fn main() {
111 proxmox_backup::tools::setup_safe_path_env();
112
113 if let Err(err) = syslog::init(
114 syslog::Facility::LOG_DAEMON,
115 log::LevelFilter::Info,
116 Some("proxmox-daily-update"),
117 ) {
118 eprintln!("unable to initialize syslog - {err}");
119 }
120
121 let mut rpcenv = CliEnvironment::new();
122 rpcenv.set_auth_id(Some(String::from("root@pam")));
123
124 if let Err(err) = proxmox_async::runtime::main(run(&mut rpcenv)) {
125 log::error!("error during update: {err}");
126 std::process::exit(1);
127 }
128 }