From 2f874935b5f7787176efb3b3ebd9da23e3958541 Mon Sep 17 00:00:00 2001 From: Hannes Laimer Date: Mon, 25 Nov 2024 17:21:57 +0100 Subject: [PATCH] add auto-mounting for removable datastores If a device houses multiple datastore, none of them will be mounted automatically. If a device only contains a single datastore it will be mounted automatically. The reason for not mounting multiple datastore automatically is that we don't know which is actually wanted, and since mounting all means also all have to be unmounted manually, it made sense to have the user choose which to mount. Signed-off-by: Hannes Laimer --- debian/proxmox-backup-server.install | 1 + debian/proxmox-backup-server.udev | 3 ++ etc/Makefile | 1 + etc/removable-device-attach@.service | 8 ++++ src/bin/proxmox_backup_manager/datastore.rs | 52 ++++++++++++++++++++- 5 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 etc/removable-device-attach@.service diff --git a/debian/proxmox-backup-server.install b/debian/proxmox-backup-server.install index 79757ead..ff581e3d 100644 --- a/debian/proxmox-backup-server.install +++ b/debian/proxmox-backup-server.install @@ -4,6 +4,7 @@ etc/proxmox-backup-daily-update.service /lib/systemd/system/ etc/proxmox-backup-daily-update.timer /lib/systemd/system/ etc/proxmox-backup-proxy.service /lib/systemd/system/ etc/proxmox-backup.service /lib/systemd/system/ +etc/removable-device-attach@.service /lib/systemd/system/ usr/bin/pmt usr/bin/pmtx usr/bin/proxmox-tape diff --git a/debian/proxmox-backup-server.udev b/debian/proxmox-backup-server.udev index afdfb2bc..e21b8bc7 100644 --- a/debian/proxmox-backup-server.udev +++ b/debian/proxmox-backup-server.udev @@ -16,3 +16,6 @@ SUBSYSTEM=="scsi_generic", SUBSYSTEMS=="scsi", ATTRS{type}=="1", ENV{ID_SCSI_SER SYMLINK+="tape/by-id/scsi-$env{ID_SCSI_SERIAL}-sg" LABEL="persistent_storage_tape_end" + +# triggers the mounting of a removable device +ACTION=="add", SUBSYSTEM=="block", ENV{ID_FS_UUID}!="", TAG+="systemd", ENV{SYSTEMD_WANTS}="removable-device-attach@$env{ID_FS_UUID}" \ No newline at end of file diff --git a/etc/Makefile b/etc/Makefile index 42f639f6..26e91684 100644 --- a/etc/Makefile +++ b/etc/Makefile @@ -2,6 +2,7 @@ include ../defines.mk UNITS := \ proxmox-backup-daily-update.timer \ + removable-device-attach@.service DYNAMIC_UNITS := \ proxmox-backup-banner.service \ diff --git a/etc/removable-device-attach@.service b/etc/removable-device-attach@.service new file mode 100644 index 00000000..e10d1ea3 --- /dev/null +++ b/etc/removable-device-attach@.service @@ -0,0 +1,8 @@ +[Unit] +Description=Try to mount the removable device of a datastore with uuid '%i'. +After=proxmox-backup-proxy.service +Requires=proxmox-backup-proxy.service + +[Service] +Type=simple +ExecStart=/usr/sbin/proxmox-backup-manager datastore uuid-mount %i diff --git a/src/bin/proxmox_backup_manager/datastore.rs b/src/bin/proxmox_backup_manager/datastore.rs index 32a55fb9..8711997d 100644 --- a/src/bin/proxmox_backup_manager/datastore.rs +++ b/src/bin/proxmox_backup_manager/datastore.rs @@ -9,7 +9,7 @@ use proxmox_backup::api2; use proxmox_backup::api2::config::datastore::DeletableProperty; use proxmox_backup::client_helpers::connect_to_localhost; -use anyhow::Error; +use anyhow::{format_err, Error}; use serde_json::Value; #[api( @@ -244,6 +244,52 @@ async fn update_datastore(name: String, mut param: Value) -> Result<(), Error> { Ok(()) } +#[api( + protected: true, + input: { + properties: { + uuid: { + type: String, + description: "The UUID of the device that should be mounted", + }, + "output-format": { + schema: OUTPUT_FORMAT, + optional: true, + }, + }, + }, +)] +/// Try mounting a removable datastore given the UUID. +async fn uuid_mount(param: Value, _rpcenv: &mut dyn RpcEnvironment) -> Result { + let uuid = param["uuid"] + .as_str() + .ok_or_else(|| format_err!("uuid has to be specified"))?; + + let (config, _digest) = pbs_config::datastore::config()?; + let list: Vec = config.convert_to_typed_array("datastore")?; + let matching_stores: Vec = list + .into_iter() + .filter(|store: &DataStoreConfig| { + store + .backing_device + .clone() + .map_or(false, |device| device.eq(&uuid)) + }) + .collect(); + + if matching_stores.len() != 1 { + return Ok(Value::Null); + } + + if let Some(store) = matching_stores.get(0) { + api2::admin::datastore::do_mount_device(store.clone())?; + } + + // we don't want to fail for UUIDs that are not associated with datastores, as that produces + // quite some noise in the logs, given this is check for every device that is plugged in. + Ok(Value::Null) +} + pub fn datastore_commands() -> CommandLineInterface { let cmd_def = CliCommandMap::new() .insert("list", CliCommand::new(&API_METHOD_LIST_DATASTORES)) @@ -289,6 +335,10 @@ pub fn datastore_commands() -> CommandLineInterface { pbs_config::datastore::complete_calendar_event, ), ) + .insert( + "uuid-mount", + CliCommand::new(&API_METHOD_UUID_MOUNT).arg_param(&["uuid"]), + ) .insert( "remove", CliCommand::new(&API_METHOD_DELETE_DATASTORE)