1 use std
::future
::Future
;
4 use anyhow
::{bail, Error}
;
6 use http
::request
::Parts
;
9 use hyper
::{Body, Method, StatusCode}
;
11 use proxmox_lang
::try_block
;
12 use proxmox_router
::{RpcEnvironmentType, UserInformation}
;
13 use proxmox_sys
::fs
::CreateOptions
;
15 use proxmox_rest_server
::{
16 daemon
, ApiConfig
, AuthError
, RestEnvironment
, RestServer
, ServerAdapter
,
19 use proxmox_backup
::auth_helpers
::*;
20 use proxmox_backup
::config
;
21 use proxmox_backup
::server
::auth
::check_pbs_auth
;
24 pbs_tools
::setup_libc_malloc_opts();
26 proxmox_backup
::tools
::setup_safe_path_env();
28 if let Err(err
) = proxmox_async
::runtime
::main(run()) {
29 eprintln
!("Error: {}", err
);
30 std
::process
::exit(-1);
34 struct ProxmoxBackupApiAdapter
;
36 impl ServerAdapter
for ProxmoxBackupApiAdapter
{
39 _env
: RestEnvironment
,
41 ) -> Pin
<Box
<dyn Future
<Output
= Response
<Body
>> + Send
>> {
43 let index
= "<center><h1>Proxmox Backup API Server</h1></center>";
46 .status(StatusCode
::OK
)
47 .header(hyper
::header
::CONTENT_TYPE
, "text/html")
55 headers
: &'a HeaderMap
,
59 dyn Future
<Output
= Result
<(String
, Box
<dyn UserInformation
+ Sync
+ Send
>), AuthError
>>
64 Box
::pin(async
move { check_pbs_auth(headers, method).await }
)
68 async
fn run() -> Result
<(), Error
> {
69 if let Err(err
) = syslog
::init(
70 syslog
::Facility
::LOG_DAEMON
,
71 log
::LevelFilter
::Info
,
72 Some("proxmox-backup-api"),
74 bail
!("unable to inititialize syslog - {}", err
);
77 config
::create_configdir()?
;
79 config
::update_self_signed_cert(false)?
;
81 proxmox_backup
::server
::create_run_dir()?
;
82 proxmox_backup
::server
::create_state_dir()?
;
83 proxmox_backup
::server
::create_active_operations_dir()?
;
84 proxmox_backup
::server
::jobstate
::create_jobstate_dir()?
;
85 proxmox_backup
::tape
::create_tape_status_dir()?
;
86 proxmox_backup
::tape
::create_drive_state_dir()?
;
87 proxmox_backup
::tape
::create_changer_state_dir()?
;
88 proxmox_backup
::tape
::create_drive_lock_dir()?
;
90 if let Err(err
) = generate_auth_key() {
91 bail
!("unable to generate auth key - {}", err
);
93 let _
= private_auth_key(); // load with lazy_static
95 if let Err(err
) = generate_csrf_key() {
96 bail
!("unable to generate csrf key - {}", err
);
98 let _
= csrf_secret(); // load with lazy_static
100 let mut config
= ApiConfig
::new(
101 pbs_buildcfg
::JS_DIR
,
102 &proxmox_backup
::api2
::ROUTER
,
103 RpcEnvironmentType
::PRIVILEGED
,
104 ProxmoxBackupApiAdapter
,
107 let backup_user
= pbs_config
::backup_user()?
;
108 let mut commando_sock
= proxmox_rest_server
::CommandSocket
::new(
109 proxmox_rest_server
::our_ctrl_sock(),
113 let dir_opts
= CreateOptions
::new()
114 .owner(backup_user
.uid
)
115 .group(backup_user
.gid
);
116 let file_opts
= CreateOptions
::new()
117 .owner(backup_user
.uid
)
118 .group(backup_user
.gid
);
120 config
.enable_access_log(
121 pbs_buildcfg
::API_ACCESS_LOG_FN
,
122 Some(dir_opts
.clone()),
123 Some(file_opts
.clone()),
127 config
.enable_auth_log(
128 pbs_buildcfg
::API_AUTH_LOG_FN
,
129 Some(dir_opts
.clone()),
130 Some(file_opts
.clone()),
134 let rest_server
= RestServer
::new(config
);
135 proxmox_rest_server
::init_worker_tasks(
136 pbs_buildcfg
::PROXMOX_BACKUP_LOG_DIR_M
!().into(),
140 // http server future:
141 let server
= daemon
::create_daemon(
142 ([127, 0, 0, 1], 82).into(),
144 let incoming
= hyper
::server
::conn
::AddrIncoming
::from_listener(listener
)?
;
147 daemon
::systemd_notify(daemon
::SystemdNotify
::Ready
)?
;
149 hyper
::Server
::builder(incoming
)
151 .with_graceful_shutdown(proxmox_rest_server
::shutdown_future())
152 .map_err(Error
::from
)
156 Some(pbs_buildcfg
::PROXMOX_BACKUP_API_PID_FN
),
159 proxmox_rest_server
::write_pid(pbs_buildcfg
::PROXMOX_BACKUP_API_PID_FN
)?
;
161 let init_result
: Result
<(), Error
> = try_block
!({
162 proxmox_rest_server
::register_task_control_commands(&mut commando_sock
)?
;
163 commando_sock
.spawn()?
;
164 proxmox_rest_server
::catch_shutdown_signal()?
;
165 proxmox_rest_server
::catch_reload_signal()?
;
169 if let Err(err
) = init_result
{
170 bail
!("unable to start daemon - {}", err
);
173 // stop gap for https://github.com/tokio-rs/tokio/issues/4730 where the thread holding the
174 // IO-driver may block progress completely if it starts polling its own tasks (blocks).
175 // So, trigger a notify to parked threads, as we're immediately ready the woken up thread will
176 // acquire the IO driver, if blocked, before going to sleep, which allows progress again
177 // TODO: remove once tokio solves this at their level (see proposals in linked comments)
178 let rt_handle
= tokio
::runtime
::Handle
::current();
179 std
::thread
::spawn(move || loop {
180 rt_handle
.spawn(std
::future
::ready(()));
181 std
::thread
::sleep(std
::time
::Duration
::from_secs(3));
185 log
::info
!("server shutting down, waiting for active workers to complete");
186 proxmox_rest_server
::last_worker_future().await?
;
188 log
::info
!("done - exit server");