-
Notifications
You must be signed in to change notification settings - Fork 0
[tem-1559] instance deploy #30
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,5 @@ | ||
// Objects representing a user created local instance of a stack | ||
// (a local container that runs with certain attributes and properties) | ||
|
||
use crate::cli::config::Config; | ||
use crate::cli::database::Database; | ||
use crate::cli::docker::DockerError; | ||
|
@@ -9,8 +8,12 @@ use crate::cli::stacks; | |
use crate::cli::stacks::{Stack, TrunkInstall}; | ||
use chrono::prelude::*; | ||
use clap::ArgMatches; | ||
use hyper::header; | ||
use reqwest::header::HeaderMap; | ||
use reqwest::StatusCode; | ||
use serde::Deserialize; | ||
use serde::Serialize; | ||
use serde_json::json; | ||
use simplelog::*; | ||
use spinners::{Spinner, Spinners}; | ||
use std::cmp::PartialEq; | ||
|
@@ -241,4 +244,77 @@ impl Instance { | |
name: name.to_string(), | ||
}) | ||
} | ||
|
||
pub fn deploy(&self, args: &ArgMatches) -> Result<String, Box<dyn Error>> { | ||
let name = args | ||
.try_get_one::<String>("name") | ||
.clone() | ||
.unwrap() | ||
.unwrap() | ||
.as_str(); | ||
info!("finding config for instance {name}"); | ||
|
||
let config = Config::new(args, &Config::full_path(args)); | ||
if config.cloud_account.is_none() || config.jwt.is_none() { | ||
return Err(Box::new(DockerError::new( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does this only run in Docker? If not that Docker error could maybe be confusing. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That is a good point, this isn't running in Docker (rather locally) and could use its own error object, maybe ConfigError? Thoughts? |
||
format!( | ||
"You need to run {} before deploying instances", | ||
"`auth login`" | ||
) | ||
.as_str(), | ||
))); | ||
} | ||
|
||
let binding = config.cloud_account.unwrap(); | ||
let org_id = binding.organizations.first().unwrap().replace('\"', ""); | ||
let jwt = config.jwt.unwrap(); | ||
|
||
let client = reqwest::blocking::Client::new(); | ||
let request_url = format!("https://api.tembo.io/api/v1/orgs/{org_id}/instances"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Will this be configurable in the future? I could definitely see the need to run our cli against our lower environments. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. that's a good thought, I don't know, the current thinking was to go through the API for everything, what did you have in mind? |
||
|
||
let headers: HeaderMap = { | ||
vec![( | ||
header::AUTHORIZATION, | ||
format!("Bearer {}", jwt).parse().unwrap(), | ||
)] | ||
.into_iter() | ||
.collect() | ||
}; | ||
|
||
let payload = json!({ | ||
"instance_name": name, | ||
"stack_type": "Standard", | ||
"cpu": "1", | ||
"environment": "dev", | ||
"memory": "1Gi", | ||
"storage": "10Gi", | ||
"replicas": 1, | ||
//"extensions": [], | ||
//"trunk_installs": [], | ||
//"app_services": {}, | ||
//"connection_pooler": {}, | ||
//"extra_domains_rw": [], | ||
//"ip_allow_list": [], | ||
//"postgres_configs": [], | ||
}); | ||
|
||
let res = client | ||
.post(request_url) | ||
.headers(headers) | ||
.json(&payload) | ||
.send()?; | ||
|
||
match res.status() { | ||
StatusCode::ACCEPTED => { | ||
info!("provisioning: https://cloud.tembo.io/orgs/{org_id}/clusters"); | ||
|
||
Ok(String::from("accepted")) | ||
} | ||
status_code if status_code.is_client_error() => { | ||
info!("{}", status_code); | ||
Err(From::from(format!("Client error: {status_code}"))) | ||
} | ||
_ => Err(From::from("Client error")), | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
// instance deploy command | ||
use crate::cli::config::Config; | ||
use anyhow::anyhow; | ||
use clap::{Arg, ArgAction, ArgMatches, Command}; | ||
use simplelog::*; | ||
use std::error::Error; | ||
|
||
// example usage: tembo instance deploy -n my_local_instance | ||
pub fn make_subcommand() -> Command { | ||
Command::new("deploy") | ||
.about("Command used to deploy a local instance to the Tembo cloud") | ||
.arg( | ||
Arg::new("name") | ||
.short('n') | ||
.long("name") | ||
.action(ArgAction::Set) | ||
.required(true) | ||
.help("The name you want to use for this instance"), | ||
) | ||
} | ||
|
||
pub fn execute(args: &ArgMatches) -> Result<(), Box<dyn Error>> { | ||
let config = Config::new(args, &Config::full_path(args)); | ||
let name = args | ||
.get_one::<String>("name") | ||
.ok_or_else(|| anyhow!("Name is missing."))?; | ||
|
||
if config.instances.is_empty() { | ||
info!("No instances have been configured"); | ||
} else { | ||
for instance in &config.instances { | ||
if instance.name.clone().unwrap().to_lowercase() == name.to_lowercase() { | ||
match instance.deploy(args) { | ||
Ok(_) => info!(" instance deployed"), | ||
Err(e) => warn!(" there was an error deploying the instance: {}", e), | ||
} | ||
} | ||
} | ||
} | ||
|
||
Ok(()) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this local only?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, the only command that hits the cloud is the instance deploy command at this point