xnode_deployer/
lib.rs

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
11#[derive(Serialize, Deserialize, Debug)]
12pub struct DeployInput {
13    pub xnode_owner: Option<String>,
14    pub domain: Option<String>,
15    pub acme_email: Option<String>,
16    pub user_passwd: Option<String>,
17    pub encrypted: Option<String>,
18    pub initial_config: Option<String>,
19}
20
21pub enum OptionalSupport<T> {
22    NotSupported,
23    Supported(T),
24}
25
26pub trait XnodeDeployer: Send + Sync {
27    type ProviderOutput;
28
29    /// Provision new hardware with XnodeOS
30    fn deploy(
31        &self,
32        input: DeployInput,
33    ) -> impl Future<Output = Result<Self::ProviderOutput, Error>> + Send;
34
35    /// Cancel renting of hardware
36    fn undeploy(&self, xnode: Self::ProviderOutput) -> impl Future<Output = Option<Error>> + Send;
37
38    /// Get ipv4 address of deployed hardware
39    fn ipv4(
40        &self,
41        xnode: Self::ProviderOutput,
42    ) -> impl Future<Output = Result<OptionalSupport<Option<Ipv4Addr>>, Error>> + Send;
43}
44
45impl DeployInput {
46    pub fn cloud_init(&self) -> String {
47        let mut env = vec![];
48        for (name, content) in [
49            ("XNODE_OWNER", &self.xnode_owner),
50            ("DOMAIN", &self.domain),
51            ("ACME_EMAIL", &self.acme_email),
52            ("USER_PASSWD", &self.user_passwd),
53            ("ENCRYPTED", &self.encrypted),
54            ("INITIAL_CONFIG", &self.initial_config),
55        ] {
56            if let Some(content) = content {
57                env.push(format!("export {name}=\"{content}\" && "));
58            }
59        }
60
61        let env = env.join("");
62        format!(
63            "#cloud-config\nruncmd:\n - {env} curl https://raw.githubusercontent.com/Openmesh-Network/xnode-manager/main/os/install.sh | bash 2>&1 | tee /tmp/xnodeos.log"
64        )
65    }
66}