1use std::net::Ipv4Addr;
2
3use serde::{Deserialize, Serialize};
4
5mod utils;
6pub use utils::{Error, XnodeDeployerError};
7
8#[cfg(feature = "hivelocity")]
9pub mod hivelocity;
10#[cfg(feature = "hyperstack")]
11pub mod hyperstack;
12
13#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
14pub struct DeployInput {
15 pub xnode_owner: Option<String>,
16 pub domain: Option<String>,
17 pub acme_email: Option<String>,
18 pub user_passwd: Option<String>,
19 pub encrypted: Option<String>,
20 pub initial_config: Option<String>,
21}
22
23#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
24pub enum OptionalSupport<T> {
25 NotSupported,
26 Supported(T),
27}
28
29pub trait XnodeDeployer: Send + Sync {
30 type ProviderOutput;
31
32 fn deploy(
34 &self,
35 input: DeployInput,
36 ) -> impl Future<Output = Result<Self::ProviderOutput, Error>> + Send;
37
38 fn undeploy(
40 &self,
41 xnode: Self::ProviderOutput,
42 ) -> impl Future<Output = Result<(), Error>> + Send;
43
44 fn ipv4(
46 &self,
47 xnode: &Self::ProviderOutput,
48 ) -> impl Future<Output = Result<OptionalSupport<Option<Ipv4Addr>>, Error>> + Send;
49}
50
51impl DeployInput {
52 pub fn cloud_init(&self) -> String {
53 let mut env = vec![];
54 for (name, content) in [
55 ("VERSION", &Some("v1.0.0".to_string())),
56 ("XNODE_OWNER", &self.xnode_owner),
57 ("DOMAIN", &self.domain),
58 ("ACME_EMAIL", &self.acme_email),
59 ("USER_PASSWD", &self.user_passwd),
60 ("ENCRYPTED", &self.encrypted),
61 ("INITIAL_CONFIG", &self.initial_config),
62 ] {
63 if let Some(content) = content {
64 env.push(format!("export {name}=\"{content}\" && "));
65 }
66 }
67
68 let env = env.join("");
69 format!(
70 "#cloud-config\nruncmd:\n - |\n {env} curl https://raw.githubusercontent.com/Openmesh-Network/xnodeos/main/install.sh | bash 2>&1 | tee /tmp/xnodeos.log"
71 )
72 }
73}