Skip to main content

xianyun_deploy/deployer/
mod.rs

1//! Interfaces for deploying applications to the caproni cluster.
2//!
3//! Ported from `internal/deployer/deployer.go` and `internal/deployer/errors.go`.
4
5use thiserror::Error;
6use xianyun_core::config::latest::{CaproniConfig, DeployerConfig};
7
8pub mod helm;
9pub mod kustomize;
10pub mod namespace;
11pub mod nix;
12pub mod registry;
13
14/// The current state of a deployment.
15#[derive(Debug, Clone, Copy, PartialEq, Eq)]
16pub enum State {
17    /// The deployer has not been deployed to the cluster.
18    NotDeployed,
19    /// The deployer is being deployed.
20    Deploying,
21    /// The deployer is deployed to the cluster.
22    Deployed,
23    /// The deployment failed.
24    Failed,
25}
26
27impl State {
28    /// The string form used in Go (`"not-deployed"`, etc.), for display
29    /// and any serialization boundary.
30    #[must_use]
31    pub fn as_str(&self) -> &'static str {
32        match self {
33            State::NotDeployed => "not-deployed",
34            State::Deploying => "deploying",
35            State::Deployed => "deployed",
36            State::Failed => "failed",
37        }
38    }
39}
40
41/// The current status of a deployment.
42#[derive(Debug, Clone, PartialEq, Eq)]
43pub struct Status {
44    /// The current state of the deployment.
45    pub state: State,
46    /// The deployer type (e.g. `"helm"`).
47    pub deployer_type: String,
48}
49
50/// Errors common across deployer managers.
51#[derive(Debug, Error)]
52pub enum DeployerError {
53    /// Trying to create a deployer with an unknown type.
54    #[error("unknown deployer type")]
55    UnknownType,
56    /// A deployment operation failed.
57    #[error("deployment failed")]
58    DeployFailed,
59    /// An undeploy operation failed.
60    #[error("undeploy failed")]
61    UndeployFailed,
62    /// Unable to determine deployment status.
63    #[error("failed to get deployment status")]
64    StatusFailed,
65}
66
67/// The interface for managing deployment lifecycle. Implementations are
68/// responsible for deploying and managing applications using specific
69/// deployment strategies (e.g. Helm charts).
70pub trait Manager {
71    /// The deployer type that this manager handles (e.g. `"helm"`).
72    fn deployer_type(&self) -> String;
73
74    /// Deploys the application to the cluster. If the application is
75    /// already deployed, this updates it to match the current
76    /// configuration.
77    fn deploy(
78        &self,
79        deployer_config: &DeployerConfig,
80        cfg: Option<&xianyun_core::config::container::Container>,
81    ) -> Result<(), Box<dyn std::error::Error + Send + Sync>>;
82
83    /// Removes this deployment from the cluster.
84    fn undeploy(
85        &self,
86        deployer_config: &DeployerConfig,
87        caproni_config: &CaproniConfig,
88    ) -> Result<(), Box<dyn std::error::Error + Send + Sync>>;
89
90    /// Returns the current status of the deployment. Returns an error
91    /// if unable to determine deployment state.
92    fn status(
93        &self,
94        deployer_config: &DeployerConfig,
95        caproni_config: &CaproniConfig,
96    ) -> Result<Status, Box<dyn std::error::Error + Send + Sync>>;
97
98    /// Validates the deployer configuration and referenced files.
99    /// Returns `Ok(())` if valid, or an error describing validation
100    /// failures. Files in uncloned repository directories should not
101    /// cause validation to fail.
102    fn validate(
103        &self,
104        deployer_config: &DeployerConfig,
105        caproni_config: &CaproniConfig,
106    ) -> Result<(), Box<dyn std::error::Error + Send + Sync>>;
107}
108
109#[cfg(test)]
110mod tests {
111    use super::*;
112
113    /// `State` has no Go counterpart to port a test from: Go's `State` is a
114    /// typed `string` constant (`StateNotDeployed State = "not-deployed"`),
115    /// so there's no conversion function to call. `as_str()` only exists
116    /// because Rust's `State` is a real enum; this is new coverage for it.
117    #[test]
118    fn state_as_str_matches_go_string_values() {
119        assert_eq!(State::NotDeployed.as_str(), "not-deployed");
120        assert_eq!(State::Deploying.as_str(), "deploying");
121        assert_eq!(State::Deployed.as_str(), "deployed");
122        assert_eq!(State::Failed.as_str(), "failed");
123    }
124}