1use crate::config::{Config, HostConfig, OverviewSection};
5use crate::demo::DemoHost;
6use crate::remote::{DEFAULT_REMOTE_COMMAND, RemoteTarget};
7
8pub const LOCAL_NAME: &str = "local";
10
11#[derive(Debug, Clone, PartialEq, Eq)]
13pub enum HostKind {
14 Local,
16 Remote(RemoteTarget),
18 Demo(DemoHost),
20}
21
22#[derive(Debug, Clone, PartialEq, Eq)]
24pub struct HostSpec {
25 pub name: String,
27 pub kind: HostKind,
28 pub sections: Vec<OverviewSection>,
30}
31
32impl HostSpec {
33 pub fn is_local(&self) -> bool {
35 self.kind == HostKind::Local
36 }
37}
38
39pub fn host_specs(
43 config: &Config,
44 extra_destinations: &[String],
45 remote_command: Option<&str>,
46) -> Vec<HostSpec> {
47 let default_sections = config.overview.sections.clone();
48 let mut specs = vec![HostSpec {
49 name: LOCAL_NAME.to_owned(),
50 kind: HostKind::Local,
51 sections: default_sections.clone(),
52 }];
53 let mut hosts: Vec<HostConfig> = config.hosts.clone();
54 for destination in extra_destinations {
55 let known = hosts
56 .iter()
57 .any(|h| h.name == *destination || h.destination() == destination);
58 if !known {
59 let mut host = HostConfig::from_destination(destination);
60 host.command = remote_command.map(str::to_owned);
61 hosts.push(host);
62 }
63 }
64 for host in hosts {
65 let command = host.command.as_deref().unwrap_or(DEFAULT_REMOTE_COMMAND);
66 let mut target = RemoteTarget::ssh(host.destination(), command);
67 target.name = host.name.clone();
68 specs.push(HostSpec {
69 sections: host
70 .sections
71 .clone()
72 .unwrap_or_else(|| default_sections.clone()),
73 name: host.name,
74 kind: HostKind::Remote(target),
75 });
76 }
77 specs
78}
79
80#[cfg(test)]
81mod tests {
82 use super::*;
83
84 #[test]
85 fn local_first_then_config_then_new_command_line_hosts() {
86 let mut config = Config::default();
87 config.hosts.push(HostConfig {
88 name: "nas".to_owned(),
89 ssh: Some("admin@nas.local".to_owned()),
90 command: Some("/opt/rigtop --agent".to_owned()),
91 sections: Some(vec![OverviewSection::Storage]),
92 });
93 let extra = vec!["admin@nas.local".to_owned(), "zefat".to_owned()];
94 let specs = host_specs(&config, &extra, Some("~/bin/rigtop --agent"));
95 let names: Vec<&str> = specs.iter().map(|s| s.name.as_str()).collect();
96 assert_eq!(names, vec!["local", "nas", "zefat"]);
98 assert!(specs[0].is_local());
99 assert_eq!(specs[1].sections, vec![OverviewSection::Storage]);
100 assert_eq!(specs[2].sections, OverviewSection::ALL.to_vec());
101 match (&specs[1].kind, &specs[2].kind) {
102 (HostKind::Remote(nas), HostKind::Remote(zefat)) => {
103 assert_eq!(nas.name, "nas");
104 assert!(nas.args.ends_with(&[
105 "admin@nas.local".to_owned(),
106 "/opt/rigtop --agent".to_owned()
107 ]));
108 assert!(
110 zefat
111 .args
112 .ends_with(&["zefat".to_owned(), "~/bin/rigtop --agent".to_owned()])
113 );
114 }
115 other => panic!("unexpected {other:?}"),
116 }
117 }
118}