zombienet_provider/kubernetes/
pod_spec_builder.rs1use std::collections::BTreeMap;
2
3use configuration::shared::resources::{ResourceQuantity, Resources};
4use k8s_openapi::{
5 api::core::v1::{
6 ConfigMapVolumeSource, Container, EnvVar, PodSpec, ResourceRequirements, Volume,
7 VolumeMount,
8 },
9 apimachinery::pkg::api::resource::Quantity,
10};
11
12pub(super) struct PodSpecBuilder;
13
14impl PodSpecBuilder {
15 pub(super) fn build(
16 name: &str,
17 image: &str,
18 resources: Option<&Resources>,
19 program: &str,
20 args: &[String],
21 env: &[(String, String)],
22 ) -> PodSpec {
23 PodSpec {
24 hostname: Some(name.to_string()),
25 init_containers: Some(vec![Self::build_helper_binaries_setup_container()]),
26 containers: vec![Self::build_main_container(
27 name, image, resources, program, args, env,
28 )],
29 volumes: Some(Self::build_volumes()),
30 ..Default::default()
31 }
32 }
33
34 fn build_main_container(
35 name: &str,
36 image: &str,
37 resources: Option<&Resources>,
38 program: &str,
39 args: &[String],
40 env: &[(String, String)],
41 ) -> Container {
42 Container {
43 name: name.to_string(),
44 image: Some(image.to_string()),
45 image_pull_policy: Some("Always".to_string()),
46 command: Some(
47 [
48 vec!["/zombie-wrapper.sh".to_string(), program.to_string()],
49 args.to_vec(),
50 ]
51 .concat(),
52 ),
53 env: Some(
54 env.iter()
55 .map(|(name, value)| EnvVar {
56 name: name.clone(),
57 value: Some(value.clone()),
58 value_from: None,
59 })
60 .collect(),
61 ),
62 volume_mounts: Some(Self::build_volume_mounts(vec![VolumeMount {
63 name: "zombie-wrapper-volume".to_string(),
64 mount_path: "/zombie-wrapper.sh".to_string(),
65 sub_path: Some("zombie-wrapper.sh".to_string()),
66 ..Default::default()
67 }])),
68 resources: Self::build_resources_requirements(resources),
69 ..Default::default()
70 }
71 }
72
73 fn build_helper_binaries_setup_container() -> Container {
74 Container {
75 name: "helper-binaries-setup".to_string(),
76 image: Some("europe-west3-docker.pkg.dev/parity-zombienet/zombienet-public-images/alpine:latest".to_string()),
77 image_pull_policy: Some("IfNotPresent".to_string()),
78 volume_mounts: Some(Self::build_volume_mounts(vec![VolumeMount {
79 name: "helper-binaries-downloader-volume".to_string(),
80 mount_path: "/helper-binaries-downloader.sh".to_string(),
81 sub_path: Some("helper-binaries-downloader.sh".to_string()),
82 ..Default::default()
83 }])),
84 command: Some(vec![
85 "ash".to_string(),
86 "/helper-binaries-downloader.sh".to_string(),
87 ]),
88 ..Default::default()
89 }
90 }
91
92 fn build_volumes() -> Vec<Volume> {
93 vec![
94 Volume {
95 name: "cfg".to_string(),
96 ..Default::default()
97 },
98 Volume {
99 name: "data".to_string(),
100 ..Default::default()
101 },
102 Volume {
103 name: "relay-data".to_string(),
104 ..Default::default()
105 },
106 Volume {
107 name: "zombie-wrapper-volume".to_string(),
108 config_map: Some(ConfigMapVolumeSource {
109 name: Some("zombie-wrapper".to_string()),
110 default_mode: Some(0o755),
111 ..Default::default()
112 }),
113 ..Default::default()
114 },
115 Volume {
116 name: "helper-binaries-downloader-volume".to_string(),
117 config_map: Some(ConfigMapVolumeSource {
118 name: Some("helper-binaries-downloader".to_string()),
119 default_mode: Some(0o755),
120 ..Default::default()
121 }),
122 ..Default::default()
123 },
124 ]
125 }
126
127 fn build_volume_mounts(non_default_mounts: Vec<VolumeMount>) -> Vec<VolumeMount> {
128 [
129 vec![
130 VolumeMount {
131 name: "cfg".to_string(),
132 mount_path: "/cfg".to_string(),
133 read_only: Some(false),
134 ..Default::default()
135 },
136 VolumeMount {
137 name: "data".to_string(),
138 mount_path: "/data".to_string(),
139 read_only: Some(false),
140 ..Default::default()
141 },
142 VolumeMount {
143 name: "relay-data".to_string(),
144 mount_path: "/relay-data".to_string(),
145 read_only: Some(false),
146 ..Default::default()
147 },
148 ],
149 non_default_mounts,
150 ]
151 .concat()
152 }
153
154 fn build_resources_requirements(resources: Option<&Resources>) -> Option<ResourceRequirements> {
155 resources.map(|resources| ResourceRequirements {
156 limits: Self::build_resources_requirements_quantities(
157 resources.limit_cpu(),
158 resources.limit_memory(),
159 ),
160 requests: Self::build_resources_requirements_quantities(
161 resources.request_cpu(),
162 resources.request_memory(),
163 ),
164 ..Default::default()
165 })
166 }
167
168 fn build_resources_requirements_quantities(
169 cpu: Option<&ResourceQuantity>,
170 memory: Option<&ResourceQuantity>,
171 ) -> Option<BTreeMap<String, Quantity>> {
172 let mut quantities = BTreeMap::new();
173
174 if let Some(cpu) = cpu {
175 quantities.insert("cpu".to_string(), Quantity(cpu.as_str().to_string()));
176 }
177
178 if let Some(memory) = memory {
179 quantities.insert("memory".to_string(), Quantity(memory.as_str().to_string()));
180 }
181
182 if !quantities.is_empty() {
183 Some(quantities)
184 } else {
185 None
186 }
187 }
188}