1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
use crate::{
action::{
base::CreateDirectory,
common::{ConfigureInitService, ConfigureNix, ProvisionNix},
StatefulAction,
},
planner::{Planner, PlannerError},
settings::CommonSettings,
settings::{InitSettings, InstallSettingsError},
Action, BuiltinPlanner,
};
use std::{collections::HashMap, path::Path};
use tokio::process::Command;
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
#[cfg_attr(feature = "cli", derive(clap::Parser))]
pub struct Linux {
#[cfg_attr(feature = "cli", clap(flatten))]
pub settings: CommonSettings,
#[cfg_attr(feature = "cli", clap(flatten))]
pub init: InitSettings,
}
#[async_trait::async_trait]
#[typetag::serde(name = "linux")]
impl Planner for Linux {
async fn default() -> Result<Self, PlannerError> {
Ok(Self {
settings: CommonSettings::default().await?,
init: InitSettings::default().await?,
})
}
async fn plan(&self) -> Result<Vec<StatefulAction<Box<dyn Action>>>, PlannerError> {
if Path::new("/etc/NIXOS").exists() {
return Err(PlannerError::NixOs);
}
match Command::new("getenforce").output().await {
Ok(output) => {
let stdout_string = String::from_utf8(output.stdout).map_err(PlannerError::Utf8)?;
tracing::trace!(getenforce_stdout = stdout_string, "SELinux detected");
match stdout_string.trim() {
"Enforcing" => return Err(PlannerError::SelinuxEnforcing),
_ => (),
}
},
Err(e) if e.kind() == std::io::ErrorKind::NotFound => (),
Err(e) => {
tracing::warn!(error = ?e, "Got an error checking for SELinux setting, this install may fail if SELinux is set to `Enforcing`")
},
}
if let Ok(_) = Command::new("nix-env")
.arg("--version")
.stdin(std::process::Stdio::null())
.status()
.await
{
return Err(PlannerError::NixExists);
}
Ok(vec![
CreateDirectory::plan("/nix", None, None, 0o0755, true)
.await
.map_err(PlannerError::Action)?
.boxed(),
ProvisionNix::plan(&self.settings.clone())
.await
.map_err(PlannerError::Action)?
.boxed(),
ConfigureNix::plan(&self.settings)
.await
.map_err(PlannerError::Action)?
.boxed(),
ConfigureInitService::plan(self.init.init, self.init.start_daemon)
.await
.map_err(PlannerError::Action)?
.boxed(),
])
}
fn settings(&self) -> Result<HashMap<String, serde_json::Value>, InstallSettingsError> {
let Self { settings, init } = self;
let mut map = HashMap::default();
map.extend(settings.settings()?.into_iter());
map.extend(init.settings()?.into_iter());
Ok(map)
}
}
impl Into<BuiltinPlanner> for Linux {
fn into(self) -> BuiltinPlanner {
BuiltinPlanner::Linux(self)
}
}