1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
use anyhow::Result;
use clap::Parser;

use super::types::{Env, RamSizes, ScalingStrategy};
use crate::commands::containers::types::ContainerType;
use crate::commands::containers::utils::create_containers;
use crate::commands::ignite::types::Deployment;
use crate::commands::ignite::util::{create_deployment, update_deployment_config};
use crate::state::State;
use crate::utils::urlify;

pub const WEB_DEPLOYMENTS_URL: &str = "https://console.hop.io/ignite/deployment/";

#[derive(Debug, Parser, Default, PartialEq, Clone)]
pub struct DeploymentConfig {
    #[clap(short = 'n', long = "name", help = "Name of the deployment")]
    pub name: Option<String>,

    #[clap(
        short = 't',
        long = "type",
        help = "Type of the container, defaults to `persistent`"
    )]
    pub container_type: Option<ContainerType>,

    #[clap(
        short = 's',
        long = "strategy",
        help = "Scaling strategy, defaults to `autoscaled`"
    )]
    pub scaling_strategy: Option<ScalingStrategy>,

    #[clap(
        short = 'c',
        long = "cpu",
        help = "The number of CPUs to use between 1 to 32, defaults to 1"
    )]
    pub cpu: Option<f64>,

    #[clap(
        short = 'r',
        long = "ram",
        help = "Amount of RAM to use between 128MB to 64GB, defaults to 512MB"
    )]
    pub ram: Option<RamSizes>,

    #[clap(
        short = 'd',
        long = "containers",
        help = "Amount of containers to deploy if `scaling` is manual, defaults to 1"
    )]
    pub containers: Option<u64>,

    #[clap(
        long = "min-containers",
        help = "Minimum amount of containers to use if `scaling` is autoscale, defaults to 1"
    )]
    pub min_containers: Option<u64>,

    #[clap(
        long = "max-containers",
        help = "Maximum amount of containers to use if `scaling` is autoscale, defaults to 10"
    )]
    pub max_containers: Option<u64>,

    #[clap(
        short = 'e',
        long = "env",
        help = "Environment variables to set, in the form of `key=value`",
        min_values = 0
    )]
    pub env: Option<Vec<Env>>,
}

#[derive(Debug, Parser, Default, PartialEq, Clone)]
#[clap(about = "Create a new deployment")]
pub struct Options {
    #[clap(flatten)]
    pub config: DeploymentConfig,

    #[clap(short = 'i', long = "image", help = "Image url")]
    pub image: Option<String>,
}

pub async fn handle(options: Options, state: State) -> Result<()> {
    let project = state.ctx.current_project_error();

    log::info!(
        "Deploying to project {} /{} ({})",
        project.name,
        project.namespace,
        project.id
    );

    let is_not_guided = options != Options::default();

    let (deployment_config, container_options) =
        update_deployment_config(options, is_not_guided, &Deployment::default(), &None);

    let deployment = create_deployment(&state.http, &project.id, &deployment_config).await?;

    log::info!(
        "Deployment `{}` ({}) created",
        deployment.name,
        deployment.id
    );

    if let Some(count) = container_options.containers {
        if count > 0 {
            log::info!("Creating {} containers", count);

            create_containers(&state.http, &deployment.id, count).await?;
        }
    }

    log::info!(
        "Deployed successfuly, you can find it at: {}",
        urlify(&format!(
            "{}{}?project={}",
            WEB_DEPLOYMENTS_URL, deployment.id, project.namespace
        ))
    );

    Ok(())
}