Skip to main content

qemu_command_builder/args/
iscsi.rs

1use bon::Builder;
2use proptest_derive::Arbitrary;
3use std::str::FromStr;
4
5use crate::parsers::{ARG_ISCSI, DELIM_COMMA};
6use crate::to_command::ToCommand;
7
8/// Configure iSCSI session parameters.
9#[derive(Debug, Clone, Hash, Ord, PartialOrd, Eq, PartialEq, Default, Builder, Arbitrary)]
10pub struct Iscsi {
11    /// CHAP username.
12    user: Option<String>,
13    /// CHAP password.
14    password: Option<String>,
15    /// Secret object id containing the password.
16    password_secret: Option<String>,
17    /// Header digest mode.
18    header_digest: Option<String>,
19    /// iSCSI initiator name.
20    initiator_name: Option<String>,
21    /// Optional initiator id.
22    id: Option<String>,
23    /// Timeout in seconds.
24    timeout: Option<usize>,
25}
26
27impl ToCommand for Iscsi {
28    fn command(&self) -> String {
29        ARG_ISCSI.to_string()
30    }
31    fn to_args(&self) -> Vec<String> {
32        let mut args = vec![];
33
34        if let Some(user) = &self.user {
35            args.push(format!("user={}", user));
36        }
37        if let Some(password) = &self.password {
38            args.push(format!("password={}", password));
39        }
40        if let Some(password_secret) = &self.password_secret {
41            args.push(format!("password-secret={}", password_secret));
42        }
43        if let Some(header_digest) = &self.header_digest {
44            args.push(format!("header-digest={}", header_digest));
45        }
46        if let Some(initiator_name) = &self.initiator_name {
47            args.push(format!("initiator-name={}", initiator_name));
48        }
49        if let Some(id) = &self.id {
50            args.push(format!("id={}", id));
51        }
52        if let Some(timeout) = self.timeout {
53            args.push(format!("timeout={}", timeout));
54        }
55
56        vec![args.join(DELIM_COMMA)]
57    }
58}
59
60impl FromStr for Iscsi {
61    type Err = String;
62
63    fn from_str(s: &str) -> Result<Self, Self::Err> {
64        let mut user = None;
65        let mut password = None;
66        let mut password_secret = None;
67        let mut header_digest = None;
68        let mut initiator_name = None;
69        let mut id = None;
70        let mut timeout = None;
71
72        for part in s.split(DELIM_COMMA).filter(|part| !part.is_empty()) {
73            let (key, value) = part.split_once('=').ok_or_else(|| format!("invalid -iscsi option: {part}"))?;
74            match key {
75                "user" => user = Some(value.to_string()),
76                "password" => password = Some(value.to_string()),
77                "password-secret" => password_secret = Some(value.to_string()),
78                "header-digest" => header_digest = Some(value.to_string()),
79                "initiator-name" => initiator_name = Some(value.to_string()),
80                "id" => id = Some(value.to_string()),
81                "timeout" => timeout = Some(value.parse::<usize>().map_err(|e| e.to_string())?),
82                other => return Err(format!("unsupported -iscsi option: {other}")),
83            }
84        }
85
86        Ok(Self {
87            user,
88            password,
89            password_secret,
90            header_digest,
91            initiator_name,
92            id,
93            timeout,
94        })
95    }
96}