isoloom_render/container/
host.rs1use isoloom_plan::{Environment, MachineShape};
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7#[non_exhaustive]
8pub struct HostSize {
9 pub cpus: u32,
11 pub memory_mb: u32,
13 pub disk_gb: u32,
15}
16
17impl HostSize {
18 #[must_use]
20 pub fn of(env: &Environment) -> HostSize {
21 let containers = env.machines.values().filter(|m| m.shape == MachineShape::Container);
22 let (cpus, memory_mb, disk_gb) = containers.fold((0_u32, 1024_u32, 0_u32), |(cpus, memory, disk), m| {
23 (
24 cpus.saturating_add(m.size.cpus.unwrap_or(1)),
25 memory.saturating_add(m.size.memory_mb.unwrap_or(512)),
26 disk.saturating_add(m.size.disk_gb.unwrap_or(5)),
27 )
28 });
29 HostSize {
30 cpus: cpus.clamp(2, 16),
31 memory_mb,
32 disk_gb: disk_gb.max(20),
33 }
34 }
35
36 #[must_use]
38 pub fn pick<T: Copy>(&self, [small, medium, large]: [T; 3]) -> T {
39 match self.memory_mb {
40 0..=4096 => small,
41 4097..=8192 => medium,
42 _ => large,
43 }
44 }
45}
46
47#[cfg(test)]
48mod tests {
49 use isoloom_spec::model::Target;
50
51 use super::HostSize;
52 use crate::testing;
53
54 fn host_size(yaml: &str) -> HostSize {
56 HostSize::of(&testing::env(yaml, Target::DockerVm))
57 }
58
59 #[test]
60 fn every_container_counts_and_docker_takes_a_gigabyte() {
61 let size = host_size(
62 "version: 1\nname: t\nnetworks: { lan: { cidr: 10.9.0.0/24 } }\nmachines:\n a: { networks: { lan: 10 }, app: { image: nginx } }\n b: { networks: { lan: 11 }, resources: { cpus: 3, memory_mb: 4096, disk_gb: 30 }, app: { image: nginx } }\n",
63 );
64 assert_eq!(
65 size,
66 HostSize {
67 cpus: 4,
68 memory_mb: 512 + 4096 + 1024,
69 disk_gb: 35
70 }
71 );
72 assert_eq!(size.pick(["small", "medium", "large"]), "medium");
73 }
74
75 #[test]
76 fn a_few_small_containers_take_the_smallest_host() {
77 let size =
78 host_size("version: 1\nname: t\nnetworks: { lan: { cidr: 10.9.0.0/24 } }\nmachines:\n a: { networks: { lan: 10 }, app: { image: nginx } }\n");
79 assert_eq!((size.cpus, size.memory_mb, size.disk_gb), (2, 1536, 20));
80 assert_eq!(size.pick(["small", "medium", "large"]), "small");
81 }
82
83 #[test]
84 fn many_containers_take_at_most_sixteen_cpus_and_the_largest_host() {
85 let machines: String = (0..20)
86 .map(|i| format!(" m{i}: {{ networks: {{ lan: {} }}, app: {{ image: nginx }} }}\n", 10 + i))
87 .collect::<Vec<_>>()
88 .concat();
89 let size = host_size(&format!(
90 "version: 1\nname: t\nnetworks: {{ lan: {{ cidr: 10.9.0.0/24 }} }}\nmachines:\n{machines}"
91 ));
92 assert_eq!((size.cpus, size.memory_mb, size.disk_gb), (16, 20 * 512 + 1024, 100));
93 assert_eq!(size.pick(["small", "medium", "large"]), "large");
94 }
95}