1use std::{
2 collections::HashMap,
3 path::{Path, PathBuf},
4 process::ExitStatus,
5};
6
7use configuration::shared::resources::Resources;
8use serde::{Deserialize, Serialize};
9
10pub type Port = u16;
11
12pub type ExecutionResult = Result<String, (ExitStatus, String)>;
13
14#[derive(Debug, Clone, PartialEq)]
15pub struct ProviderCapabilities {
16 pub requires_image: bool,
19 pub has_resources: bool,
21 pub prefix_with_full_path: bool,
23 pub use_default_ports_in_cmd: bool,
26}
27
28#[derive(Debug, Clone, Copy, PartialEq, Eq)]
31pub enum NodeRole {
32 Node,
34 Bootnode,
36 Collator,
38 CumulusCollator,
40 Temp,
42 CustomProcess,
44}
45
46impl NodeRole {
47 pub fn as_label(&self) -> &'static str {
48 match self {
49 NodeRole::Node => "node",
50 NodeRole::Bootnode => "bootnode",
51 NodeRole::Collator => "collator",
52 NodeRole::CumulusCollator => "cumulus-collator",
53 NodeRole::Temp => "temp",
54 NodeRole::CustomProcess => "custom-process",
55 }
56 }
57}
58
59#[derive(Debug, Clone, PartialEq, Eq)]
62pub struct ReadinessProbe {
63 pub target: ReadinessTarget,
64 pub period_secs: u64,
66}
67
68#[derive(Debug, Clone, PartialEq, Eq)]
69pub enum ReadinessTarget {
70 Tcp(Port),
72 Http { port: Port, path: String },
74}
75
76#[derive(Debug, Clone, PartialEq, Eq)]
78pub enum ProcessStatus {
79 Running { ready: Option<bool> },
82 Exited { code: Option<i32> },
85}
86
87#[derive(Debug, Clone)]
88pub struct SpawnNodeOptions {
89 pub name: String,
91 pub image: Option<String>,
93 pub resources: Option<Resources>,
95 pub program: String,
97 pub args: Vec<String>,
99 pub env: Vec<(String, String)>,
101 pub injected_files: Vec<TransferedFile>,
104 pub created_paths: Vec<PathBuf>,
108 pub db_snapshot: Option<PathBuf>,
112 pub port_mapping: Option<HashMap<Port, Port>>,
113 pub ports: Vec<(String, Port)>,
117 pub readiness: Option<ReadinessProbe>,
119 pub node_log_path: Option<PathBuf>,
121 pub role: Option<NodeRole>,
123 pub wrapper: bool,
128}
129
130impl SpawnNodeOptions {
131 pub fn new<S>(name: S, program: S) -> Self
132 where
133 S: AsRef<str>,
134 {
135 Self {
136 name: name.as_ref().to_string(),
137 image: None,
138 resources: None,
139 program: program.as_ref().to_string(),
140 args: vec![],
141 env: vec![],
142 injected_files: vec![],
143 created_paths: vec![],
144 db_snapshot: None,
145 port_mapping: None,
146 ports: vec![],
147 readiness: None,
148 node_log_path: None,
149 role: None,
150 wrapper: true,
151 }
152 }
153
154 pub fn image<S>(mut self, image: S) -> Self
155 where
156 S: AsRef<str>,
157 {
158 self.image = Some(image.as_ref().to_string());
159 self
160 }
161
162 pub fn resources(mut self, resources: Resources) -> Self {
163 self.resources = Some(resources);
164 self
165 }
166
167 pub fn db_snapshot(mut self, db_snap: Option<PathBuf>) -> Self {
168 self.db_snapshot = db_snap;
169 self
170 }
171
172 pub fn args<S, I>(mut self, args: I) -> Self
173 where
174 S: AsRef<str>,
175 I: IntoIterator<Item = S>,
176 {
177 self.args = args.into_iter().map(|s| s.as_ref().to_string()).collect();
178 self
179 }
180
181 pub fn env<S, I>(mut self, env: I) -> Self
182 where
183 S: AsRef<str>,
184 I: IntoIterator<Item = (S, S)>,
185 {
186 self.env = env
187 .into_iter()
188 .map(|(name, value)| (name.as_ref().to_string(), value.as_ref().to_string()))
189 .collect();
190 self
191 }
192
193 pub fn injected_files<I>(mut self, injected_files: I) -> Self
194 where
195 I: IntoIterator<Item = TransferedFile>,
196 {
197 self.injected_files = injected_files.into_iter().collect();
198 self
199 }
200
201 pub fn created_paths<P, I>(mut self, created_paths: I) -> Self
202 where
203 P: AsRef<Path>,
204 I: IntoIterator<Item = P>,
205 {
206 self.created_paths = created_paths
207 .into_iter()
208 .map(|path| path.as_ref().into())
209 .collect();
210 self
211 }
212
213 pub fn port_mapping(mut self, ports: HashMap<Port, Port>) -> Self {
214 self.port_mapping = Some(ports);
215 self
216 }
217
218 pub fn node_log_path(mut self, path: Option<PathBuf>) -> Self {
219 self.node_log_path = path;
220 self
221 }
222
223 pub fn role(mut self, role: NodeRole) -> Self {
224 self.role = Some(role);
225 self
226 }
227
228 pub fn ports<S, I>(mut self, ports: I) -> Self
229 where
230 S: AsRef<str>,
231 I: IntoIterator<Item = (S, Port)>,
232 {
233 self.ports = ports
234 .into_iter()
235 .map(|(name, port)| (name.as_ref().to_string(), port))
236 .collect();
237 self
238 }
239
240 pub fn readiness(mut self, probe: Option<ReadinessProbe>) -> Self {
241 self.readiness = probe;
242 self
243 }
244
245 pub fn without_wrapper(mut self) -> Self {
254 self.wrapper = false;
255 self
256 }
257}
258
259#[derive(Debug)]
260pub struct GenerateFileCommand {
261 pub program: String,
262 pub args: Vec<String>,
263 pub env: Vec<(String, String)>,
264 pub local_output_path: PathBuf,
265}
266
267impl GenerateFileCommand {
268 pub fn new<S, P>(program: S, local_output_path: P) -> Self
269 where
270 S: AsRef<str>,
271 P: AsRef<Path>,
272 {
273 Self {
274 program: program.as_ref().to_string(),
275 args: vec![],
276 env: vec![],
277 local_output_path: local_output_path.as_ref().into(),
278 }
279 }
280
281 pub fn args<S, I>(mut self, args: I) -> Self
282 where
283 S: AsRef<str>,
284 I: IntoIterator<Item = S>,
285 {
286 self.args = args.into_iter().map(|s| s.as_ref().to_string()).collect();
287 self
288 }
289
290 pub fn env<S, I>(mut self, env: I) -> Self
291 where
292 S: AsRef<str>,
293 I: IntoIterator<Item = (S, S)>,
294 {
295 self.env = env
296 .into_iter()
297 .map(|(name, value)| (name.as_ref().to_string(), value.as_ref().to_string()))
298 .collect();
299 self
300 }
301}
302
303#[derive(Debug)]
304pub struct GenerateFilesOptions {
305 pub commands: Vec<GenerateFileCommand>,
306 pub image: Option<String>,
307 pub injected_files: Vec<TransferedFile>,
308 pub temp_name: Option<String>,
310 pub expected_path: Option<PathBuf>,
311}
312
313impl GenerateFilesOptions {
314 pub fn new<I>(commands: I, image: Option<String>, expected_path: Option<PathBuf>) -> Self
315 where
316 I: IntoIterator<Item = GenerateFileCommand>,
317 {
318 Self {
319 commands: commands.into_iter().collect(),
320 injected_files: vec![],
321 image,
322 temp_name: None,
323 expected_path,
324 }
325 }
326
327 pub fn with_files<I>(
328 commands: I,
329 image: Option<String>,
330 injected_files: &[TransferedFile],
331 expected_path: Option<PathBuf>,
332 ) -> Self
333 where
334 I: IntoIterator<Item = GenerateFileCommand>,
335 {
336 Self {
337 commands: commands.into_iter().collect(),
338 injected_files: injected_files.into(),
339 image,
340 temp_name: None,
341 expected_path,
342 }
343 }
344
345 pub fn image<S>(mut self, image: S) -> Self
346 where
347 S: AsRef<str>,
348 {
349 self.image = Some(image.as_ref().to_string());
350 self
351 }
352
353 pub fn injected_files<I>(mut self, injected_files: I) -> Self
354 where
355 I: IntoIterator<Item = TransferedFile>,
356 {
357 self.injected_files = injected_files.into_iter().collect();
358 self
359 }
360
361 pub fn temp_name(mut self, name: impl Into<String>) -> Self {
362 self.temp_name = Some(name.into());
363 self
364 }
365}
366
367#[derive(Debug)]
368pub struct RunCommandOptions {
369 pub program: String,
370 pub args: Vec<String>,
371 pub env: Vec<(String, String)>,
372}
373
374impl RunCommandOptions {
375 pub fn new<S>(program: S) -> Self
376 where
377 S: AsRef<str>,
378 {
379 Self {
380 program: program.as_ref().to_string(),
381 args: vec![],
382 env: vec![],
383 }
384 }
385
386 pub fn args<S, I>(mut self, args: I) -> Self
387 where
388 S: AsRef<str>,
389 I: IntoIterator<Item = S>,
390 {
391 self.args = args.into_iter().map(|s| s.as_ref().to_string()).collect();
392 self
393 }
394
395 pub fn env<S, I>(mut self, env: I) -> Self
396 where
397 S: AsRef<str>,
398 I: IntoIterator<Item = (S, S)>,
399 {
400 self.env = env
401 .into_iter()
402 .map(|(name, value)| (name.as_ref().to_string(), value.as_ref().to_string()))
403 .collect();
404 self
405 }
406}
407
408pub struct RunScriptOptions {
409 pub local_script_path: PathBuf,
410 pub args: Vec<String>,
411 pub env: Vec<(String, String)>,
412}
413
414impl RunScriptOptions {
415 pub fn new<P>(local_script_path: P) -> Self
416 where
417 P: AsRef<Path>,
418 {
419 Self {
420 local_script_path: local_script_path.as_ref().into(),
421 args: vec![],
422 env: vec![],
423 }
424 }
425
426 pub fn args<S, I>(mut self, args: I) -> Self
427 where
428 S: AsRef<str>,
429 I: IntoIterator<Item = S>,
430 {
431 self.args = args.into_iter().map(|s| s.as_ref().to_string()).collect();
432 self
433 }
434
435 pub fn env<S, I>(mut self, env: I) -> Self
436 where
437 S: AsRef<str>,
438 I: IntoIterator<Item = (S, S)>,
439 {
440 self.env = env
441 .into_iter()
442 .map(|(name, value)| (name.as_ref().to_string(), value.as_ref().to_string()))
443 .collect();
444 self
445 }
446}
447
448#[derive(Debug, Clone, Serialize, Deserialize)]
450pub struct TransferedFile {
451 pub local_path: PathBuf,
452 pub remote_path: PathBuf,
453 pub mode: String,
455}
456
457impl TransferedFile {
458 pub fn new<P>(local_path: P, remote_path: P) -> Self
459 where
460 P: AsRef<Path>,
461 {
462 Self {
463 local_path: local_path.as_ref().into(),
464 remote_path: remote_path.as_ref().into(),
465 mode: "0644".to_string(), }
467 }
468
469 pub fn mode<S>(mut self, mode: S) -> Self
470 where
471 S: AsRef<str>,
472 {
473 self.mode = mode.as_ref().to_string();
474 self
475 }
476}
477
478impl std::fmt::Display for TransferedFile {
479 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
480 write!(
481 f,
482 "File to transfer (local: {}, remote: {})",
483 self.local_path.display(),
484 self.remote_path.display()
485 )
486 }
487}
488
489pub struct InnerSnapshotDb {
492 pub filename: String,
494 pub sha256: String,
496 pub size: u64,
498}