1 use std
::collections
::HashMap
;
7 use proxmox_schema
::api
;
8 use proxmox_router
::{list_subdirs_api_method, Permission, Router, RpcEnvironment, SubdirMap}
;
11 Authid
, ChangerListEntry
, LtoTapeDrive
, MtxEntryKind
, MtxStatusEntry
, ScsiTapeChanger
,
12 CHANGER_NAME_SCHEMA
, PRIV_TAPE_AUDIT
, PRIV_TAPE_READ
,
14 use pbs_config
::CachedUserInfo
;
17 linux_list_drives
::{lookup_device_identification, linux_tape_changer_list}
,
27 mtx_status_to_online_set
,
29 drive
::get_tape_device_state
,
38 schema
: CHANGER_NAME_SCHEMA
,
41 description
: "Use cached value.",
48 description
: "A status entry for each drive and slot.",
55 permission
: &Permission
::Privilege(&["tape", "device", "{name}"], PRIV_TAPE_AUDIT
, false),
58 /// Get tape changer status
59 pub async
fn get_status(
62 ) -> Result
<Vec
<MtxStatusEntry
>, Error
> {
64 let (config
, _digest
) = pbs_config
::drive
::config()?
;
66 let mut changer_config
: ScsiTapeChanger
= config
.lookup("changer", &name
)?
;
68 let status
= tokio
::task
::spawn_blocking(move || {
69 changer_config
.status(cache
)
72 let state_path
= Path
::new(TAPE_STATUS_DIR
);
73 let mut inventory
= Inventory
::load(state_path
)?
;
75 let mut map
= OnlineStatusMap
::new(&config
)?
;
76 let online_set
= mtx_status_to_online_set(&status
, &inventory
);
77 map
.update_online_status(&name
, online_set
)?
;
79 inventory
.update_online_status(&map
)?
;
81 let drive_list
: Vec
<LtoTapeDrive
> = config
.convert_to_typed_array("lto")?
;
82 let mut drive_map
: HashMap
<u64, String
> = HashMap
::new();
84 for drive
in drive_list
{
85 if let Some(changer
) = drive
.changer
{
89 let num
= drive
.changer_drivenum
.unwrap_or(0);
90 drive_map
.insert(num
, drive
.name
.clone());
94 let mut list
= Vec
::new();
96 for (id
, drive_status
) in status
.drives
.iter().enumerate() {
98 if let Some(drive
) = drive_map
.get(&(id
as u64)) {
99 state
= get_tape_device_state(&config
, &drive
)?
;
101 let entry
= MtxStatusEntry
{
102 entry_kind
: MtxEntryKind
::Drive
,
104 label_text
: match &drive_status
.status
{
105 ElementStatus
::Empty
=> None
,
106 ElementStatus
::Full
=> Some(String
::new()),
107 ElementStatus
::VolumeTag(tag
) => Some(tag
.to_string()),
109 loaded_slot
: drive_status
.loaded_slot
,
115 for (id
, slot_info
) in status
.slots
.iter().enumerate() {
116 let entry
= MtxStatusEntry
{
117 entry_kind
: if slot_info
.import_export
{
118 MtxEntryKind
::ImportExport
122 entry_id
: id
as u64 + 1,
123 label_text
: match &slot_info
.status
{
124 ElementStatus
::Empty
=> None
,
125 ElementStatus
::Full
=> Some(String
::new()),
126 ElementStatus
::VolumeTag(tag
) => Some(tag
.to_string()),
141 schema
: CHANGER_NAME_SCHEMA
,
144 description
: "Source slot number",
148 description
: "Destination slot number",
154 permission
: &Permission
::Privilege(&["tape", "device", "{name}"], PRIV_TAPE_READ
, false),
157 /// Transfers media from one slot to another
158 pub async
fn transfer(
162 ) -> Result
<(), Error
> {
164 let (config
, _digest
) = pbs_config
::drive
::config()?
;
166 let mut changer_config
: ScsiTapeChanger
= config
.lookup("changer", &name
)?
;
168 tokio
::task
::spawn_blocking(move || {
169 changer_config
.transfer(from
, to
)?
;
179 description
: "The list of configured changers with model information.",
182 type: ChangerListEntry
,
186 description
: "List configured tape changer filtered by Tape.Audit privileges",
187 permission
: &Permission
::Anybody
,
191 pub fn list_changers(
193 rpcenv
: &mut dyn RpcEnvironment
,
194 ) -> Result
<Vec
<ChangerListEntry
>, Error
> {
195 let auth_id
: Authid
= rpcenv
.get_auth_id().unwrap().parse()?
;
196 let user_info
= CachedUserInfo
::new()?
;
198 let (config
, _digest
) = pbs_config
::drive
::config()?
;
200 let linux_changers
= linux_tape_changer_list();
202 let changer_list
: Vec
<ScsiTapeChanger
> = config
.convert_to_typed_array("changer")?
;
204 let mut list
= Vec
::new();
206 for changer
in changer_list
{
207 let privs
= user_info
.lookup_privs(&auth_id
, &["tape", "changer", &changer
.name
]);
208 if (privs
& PRIV_TAPE_AUDIT
) == 0 {
212 let info
= lookup_device_identification(&linux_changers
, &changer
.path
);
213 let entry
= ChangerListEntry { config: changer, info }
;
219 const SUBDIRS
: SubdirMap
= &[
223 .get(&API_METHOD_GET_STATUS
)
228 .post(&API_METHOD_TRANSFER
)
232 const ITEM_ROUTER
: Router
= Router
::new()
233 .get(&list_subdirs_api_method
!(SUBDIRS
))
236 pub const ROUTER
: Router
= Router
::new()
237 .get(&API_METHOD_LIST_CHANGERS
)
238 .match_all("name", &ITEM_ROUTER
);