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
106
107
108
109
110
111
112
113
|
use crate::Config;
use crate::NetworkConfig;
use crate::{Error, Result};
use derive_builder::Builder;
use serde::{Deserialize, Serialize};
use serde_ini::de::from_bufread;
use std::fs::File;
use std::io::BufReader;
use std::{collections::HashMap, ffi::OsString, fs, path::PathBuf, process::Command};
#[derive(Builder, Debug, Serialize, Deserialize, Clone)]
#[builder(build_fn(private, name = "build_container"), derive(Debug))]
pub struct Container {
pub machine: OsString,
#[builder(setter(skip))]
pub class: OsString,
#[builder(setter(skip))]
pub service: OsString,
#[builder(setter(skip))]
pub os: OsString,
#[builder(setter(skip))]
pub version: OsString,
#[builder(setter(skip))]
pub addresses: OsString,
#[builder(setter(each = "add_network_config"))]
#[serde(skip_deserializing)]
pub network_configs: HashMap<PathBuf, NetworkConfig>,
#[builder(setter(each = "add_option"))]
#[serde(skip_deserializing)]
pub options: Vec<String>,
}
impl Container {
fn create(&self) -> Result<Container> {
// TODO
// exec systemd-nspawn --settings=trusted --quiet --console=interactive
// --link-journal=no --resolv-conf=off --timezone=off --capability=all
// --boot --directory=${SRVRPATH} --private-users=false --bind-ro=/sys/module
// --bind-ro=/lib/modules --network-zone=${USERNAME}
// --network-veth-extra=vn-${SRVRNAME}:host9
Command::new("systemd-nspawn")
.args(&self.options)
.status()?
.success()
.then(|| self)
.ok_or_else(|| Error::NSpawn(format!("Failed to create container: {:?}", self)))?
.network_configuration()
.map(|_| self.to_owned())
}
fn network_configuration(&self) -> Result<()> {
for (filebuf, network_config) in self.network_configs.iter() {
fs::write(filebuf, serde_ini::ser::to_vec(network_config)?)?;
}
Ok(())
}
}
impl ContainerBuilder {
pub fn build(&self) -> Result<Container> {
self.build_container()?.create()
}
pub fn build_with_config(&mut self, config: &Config) -> Result<Container> {
self.add_network_configs_from_config(config)?
.build_container()?
.create()
}
fn add_network_configs_from_config(&mut self, config: &Config) -> Result<&mut Self> {
let dir = match &config.network_configs_path {
Some(it) => it,
None => {
return Err(Error::FileError(format!(
"Failed to create container: {:?}",
self
)))
}
};
if dir.is_dir() {
for entry in fs::read_dir(dir)? {
if let Ok(entry) = entry {
let filename = entry.file_name();
let file = File::open(entry.path())?;
let file_contents =
match from_bufread(
BufReader::new(file),
) {
Ok(it) => it,
Err(_) => {
return Err(Error::FileError(format!(
"Failed to create container: {:?}",
self
)))
}
};
self.add_network_config((PathBuf::from(filename), file_contents));
}
}
}
Ok(self)
}
}
|