lab_ops_natmap/
install.rs1use std::process::Command;
4
5use color_eyre::Result;
6use color_eyre::eyre::bail;
7
8pub fn install_systemd(binary: &str, group: &str) -> Result<()> {
18 install_binary(binary)?;
19 create_group(group)?;
20 add_user_to_grp(group);
21 write_service(binary, group)?;
22
23 println!("Reloading systemd...");
25 Command::new("systemctl").arg("daemon-reload").status()?;
26
27 enable_service()?;
28
29 println!("natmap installed and running.");
30 println!("Use `systemctl status natmap` to check.");
31 println!("Use `lab-ops natmap ls` to see mappings (after re-login for group membership).");
32
33 Ok(())
34}
35
36fn install_binary(binary: &str) -> Result<()> {
38 let current_exe = std::env::current_exe()?;
39 let target = std::path::Path::new(binary);
40
41 if std::fs::canonicalize(¤t_exe).ok().as_ref()
42 != std::fs::canonicalize(target).ok().as_ref()
43 {
44 println!(
45 "Installing binary: {} -> {}",
46 current_exe.display(),
47 target.display()
48 );
49 std::fs::copy(¤t_exe, target)?;
50 let _ = Command::new("chmod").args(["755", binary]).status();
51 } else {
52 println!("Binary already at {}, skipping copy.", target.display());
53 }
54
55 Ok(())
56}
57
58fn create_group(group: &str) -> Result<()> {
60 let group_exists = Command::new("getent")
61 .args(["group", group])
62 .output()
63 .map(|o| o.status.success())
64 .unwrap_or(false);
65
66 if !group_exists {
67 println!("Creating group '{group}'...");
68 let status = Command::new("groupadd")
69 .args(["--system", group])
70 .status()?;
71 if !status.success() {
72 bail!("Failed to create group '{group}'");
73 }
74 println!("Group '{group}' created.");
75 }
76
77 Ok(())
78}
79
80fn add_user_to_grp(group: &str) {
82 if let Ok(user) = std::env::var("USER")
83 && !user.is_empty()
84 && user != "root"
85 {
86 println!("Adding user '{user}' to group '{group}'...");
87 let _ = Command::new("usermod")
88 .args(["-a", "-G", group, &user])
89 .status();
90 println!(
91 "User '{user}' added to group '{group}'. You may need to re-login for this to take effect."
92 );
93 }
94}
95
96fn write_service(binary: &str, group: &str) -> Result<()> {
98 let state_dir = "/var/lib/natmap/state.json";
99
100 let rendered = include_str!("../assets/natmap.service")
101 .replace("{binary}", binary)
102 .replace("{state_dir}", state_dir)
103 .replace("{group}", group);
104 let path = std::path::Path::new("/etc/systemd/system/natmap.service");
105 println!("Writing systemd service to {}", path.display());
106 if path.exists() {
107 println!("Service file already exists, overwriting.");
108 }
109 std::fs::write(path, rendered)?;
110
111 Ok(())
112}
113
114fn enable_service() -> Result<()> {
116 println!("Enabling natmap service...");
117 let status = Command::new("systemctl")
118 .args(["enable", "--now", "natmap"])
119 .status()?;
120 if !status.success() {
121 bail!("Failed to enable natmap service");
122 }
123
124 Ok(())
125}