1 use anyhow
::{bail, Error}
;
4 use proxmox_router
::{cli::*, ApiHandler, RpcEnvironment}
;
5 use proxmox_schema
::api
;
6 use proxmox_section_config
::SectionConfigData
;
8 use pbs_config
::drive
::{complete_changer_name, complete_drive_name}
;
10 use pbs_api_types
::CHANGER_NAME_SCHEMA
;
12 use pbs_tape
::linux_list_drives
::complete_changer_path
;
14 use proxmox_backup
::{api2, tape::drive::media_changer}
;
16 pub fn lookup_changer_name(param
: &Value
, config
: &SectionConfigData
) -> Result
<String
, Error
> {
17 if let Some(name
) = param
["name"].as_str() {
18 return Ok(String
::from(name
));
21 let mut empty
= Value
::Null
;
23 if let Ok(drive
) = crate::extract_drive_name(&mut empty
, config
) {
24 if let Ok(Some((_
, name
))) = media_changer(config
, &drive
) {
29 bail
!("unable to get (default) changer name");
32 pub fn changer_commands() -> CommandLineInterface
{
33 let cmd_def
= CliCommandMap
::new()
34 .insert("scan", CliCommand
::new(&API_METHOD_SCAN_FOR_CHANGERS
))
35 .insert("list", CliCommand
::new(&API_METHOD_LIST_CHANGERS
))
38 CliCommand
::new(&API_METHOD_GET_CONFIG
)
40 .completion_cb("name", complete_changer_name
),
44 CliCommand
::new(&api2
::config
::changer
::API_METHOD_DELETE_CHANGER
)
46 .completion_cb("name", complete_changer_name
),
50 CliCommand
::new(&api2
::config
::changer
::API_METHOD_CREATE_CHANGER
)
52 .completion_cb("name", complete_drive_name
)
53 .completion_cb("path", complete_changer_path
),
57 CliCommand
::new(&api2
::config
::changer
::API_METHOD_UPDATE_CHANGER
)
59 .completion_cb("name", complete_changer_name
)
60 .completion_cb("path", complete_changer_path
),
64 CliCommand
::new(&API_METHOD_GET_STATUS
)
66 .completion_cb("name", complete_changer_name
),
70 CliCommand
::new(&API_METHOD_TRANSFER
)
72 .completion_cb("name", complete_changer_name
),
82 schema
: OUTPUT_FORMAT
,
89 fn list_changers(param
: Value
, rpcenv
: &mut dyn RpcEnvironment
) -> Result
<(), Error
> {
90 let output_format
= get_output_format(¶m
);
91 let info
= &api2
::tape
::changer
::API_METHOD_LIST_CHANGERS
;
92 let mut data
= match info
.handler
{
93 ApiHandler
::Sync(handler
) => (handler
)(param
, info
, rpcenv
)?
,
97 let options
= default_table_format_options()
98 .column(ColumnConfig
::new("name"))
99 .column(ColumnConfig
::new("path"))
100 .column(ColumnConfig
::new("vendor"))
101 .column(ColumnConfig
::new("model"))
102 .column(ColumnConfig
::new("serial"));
104 format_and_print_result_full(&mut data
, &info
.returns
, &output_format
, &options
);
113 schema
: OUTPUT_FORMAT
,
119 /// Scan for SCSI tape changers
120 fn scan_for_changers(param
: Value
, rpcenv
: &mut dyn RpcEnvironment
) -> Result
<(), Error
> {
121 let output_format
= get_output_format(¶m
);
122 let info
= &api2
::tape
::API_METHOD_SCAN_CHANGERS
;
123 let mut data
= match info
.handler
{
124 ApiHandler
::Sync(handler
) => (handler
)(param
, info
, rpcenv
)?
,
128 let options
= default_table_format_options()
129 .column(ColumnConfig
::new("path"))
130 .column(ColumnConfig
::new("vendor"))
131 .column(ColumnConfig
::new("model"))
132 .column(ColumnConfig
::new("serial"));
134 format_and_print_result_full(&mut data
, &info
.returns
, &output_format
, &options
);
143 schema
: OUTPUT_FORMAT
,
147 schema
: CHANGER_NAME_SCHEMA
,
152 /// Get tape changer configuration
153 fn get_config(param
: Value
, rpcenv
: &mut dyn RpcEnvironment
) -> Result
<(), Error
> {
154 let output_format
= get_output_format(¶m
);
155 let info
= &api2
::config
::changer
::API_METHOD_GET_CONFIG
;
156 let mut data
= match info
.handler
{
157 ApiHandler
::Sync(handler
) => (handler
)(param
, info
, rpcenv
)?
,
161 let options
= default_table_format_options()
162 .column(ColumnConfig
::new("name"))
163 .column(ColumnConfig
::new("path"))
164 .column(ColumnConfig
::new("options"))
165 .column(ColumnConfig
::new("export-slots"));
167 format_and_print_result_full(&mut data
, &info
.returns
, &output_format
, &options
);
176 schema
: OUTPUT_FORMAT
,
180 schema
: CHANGER_NAME_SCHEMA
,
184 description
: "Use cached value.",
192 /// Get tape changer status
193 async
fn get_status(mut param
: Value
, rpcenv
: &mut dyn RpcEnvironment
) -> Result
<(), Error
> {
194 let (config
, _digest
) = pbs_config
::drive
::config()?
;
196 param
["name"] = lookup_changer_name(¶m
, &config
)?
.into();
198 let output_format
= get_output_format(¶m
);
199 let info
= &api2
::tape
::changer
::API_METHOD_GET_STATUS
;
200 let mut data
= match info
.handler
{
201 ApiHandler
::Async(handler
) => (handler
)(param
, info
, rpcenv
).await?
,
205 let render_label_text
= |value
: &Value
, _record
: &Value
| -> Result
<String
, Error
> {
207 return Ok(String
::new());
209 let text
= value
.as_str().unwrap().to_string();
211 Ok(String
::from("--FULL--"))
217 let options
= default_table_format_options()
218 .sortby("entry-kind", false)
219 .sortby("entry-id", false)
220 .column(ColumnConfig
::new("entry-kind"))
221 .column(ColumnConfig
::new("entry-id"))
222 .column(ColumnConfig
::new("label-text").renderer(render_label_text
))
223 .column(ColumnConfig
::new("loaded-slot"));
225 format_and_print_result_full(&mut data
, &info
.returns
, &output_format
, &options
);
234 schema
: CHANGER_NAME_SCHEMA
,
238 description
: "Source slot number",
243 description
: "Destination slot number",
250 /// Transfers media from one slot to another
251 pub async
fn transfer(mut param
: Value
, rpcenv
: &mut dyn RpcEnvironment
) -> Result
<(), Error
> {
252 let (config
, _digest
) = pbs_config
::drive
::config()?
;
254 param
["name"] = lookup_changer_name(¶m
, &config
)?
.into();
256 let info
= &api2
::tape
::changer
::API_METHOD_TRANSFER
;
258 ApiHandler
::Async(handler
) => (handler
)(param
, info
, rpcenv
).await?
,