Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions tvc/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ use crate::config::turnkey::{Config, StoredApiKey};
use anyhow::{anyhow, bail, Context, Result};
use tracing::debug;
use turnkey_api_key_stamper::TurnkeyP256ApiKey;
use turnkey_client::generated::external::data::v1::TvcApp;
use turnkey_client::generated::GetTvcAppRequest;
use turnkey_client::TurnkeyClient;

/// Number of *required* auth env vars: org_id, api_key_public, api_key_private.
Expand Down Expand Up @@ -53,6 +55,21 @@ pub async fn build_client() -> Result<AuthenticatedClient> {
build_authed_client(&org_id, &api_base_url, &api_key_public, &api_key_private)
}

pub async fn fetch_tvc_app(auth: &AuthenticatedClient, app_id: &str) -> Result<TvcApp> {
let response = auth
.client
.get_tvc_app(GetTvcAppRequest {
organization_id: auth.org_id.clone(),
tvc_app_id: app_id.to_string(),
})
.await
.context("failed to fetch app")?;

response
.tvc_app
.ok_or_else(|| anyhow!("app not found: {app_id}"))
}

async fn load_credentials_from_config() -> Result<(String, String, String, String)> {
let config = Config::load().await?;

Expand Down
14 changes: 12 additions & 2 deletions tvc/src/commands/app/create.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ fn build_create_tvc_app_intent(app_config: &AppConfig) -> CreateTvcAppIntent {
.map(to_tvc_operator_set_params),
share_set_id: app_config.share_set_id.clone(),
share_set_params: share_set_params.as_ref().map(to_tvc_operator_set_params),
enable_egress: app_config.enable_egress,
enable_egress: app_config.enable_egress.into(),
enable_debug_mode_deployments: app_config.dangerous_enable_debug_mode_deployments.into(),
}
}
Expand Down Expand Up @@ -184,7 +184,7 @@ mod tests {
AppConfig {
name: "test-app".to_string(),
quorum_public_key: KNOWN_QUORUM_KEY.to_string(),
enable_egress: Some(false),
enable_egress: false,
manifest_set_id: None,
manifest_set_params: Some(OperatorSetParams {
name: "manifest-set".to_string(),
Expand Down Expand Up @@ -212,6 +212,16 @@ mod tests {
assert!(share_set_params.existing_operator_ids.is_empty());
}

#[test]
fn build_intent_sends_enable_egress() {
let mut config = valid_config();
config.enable_egress = true;

let intent = build_create_tvc_app_intent(&config);

assert_eq!(intent.enable_egress, Some(true));
}

#[test]
fn build_intent_uses_custom_share_set_params_when_configured() {
let mut config = valid_config();
Expand Down
34 changes: 28 additions & 6 deletions tvc/src/commands/app/list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ use clap::Args as ClapArgs;
use turnkey_client::generated::external::data::v1::TvcApp;
use turnkey_client::generated::GetTvcAppsRequest;

use crate::commands::display::format_egress_enabled;

const SEPARATOR_WIDTH: usize = 40;

/// List apps.
#[derive(Debug, ClapArgs)]
#[command(about, long_about = None)]
Expand Down Expand Up @@ -49,15 +53,22 @@ fn filter_by_name(apps: &mut Vec<TvcApp>, name: Option<&str>) {
}

fn render_app(app: &TvcApp) {
Comment thread
emostov marked this conversation as resolved.
println!("Name: {}", app.name);
println!("ID: {}", app.id);
println!("Quorum Public Key: {}", app.quorum_public_key);
let live = app.live_deployment_id.as_deref().unwrap_or("(none)");
println!("Live Deployment: {live}");
let mut lines = vec![
format!("Name: {}", app.name),
format!("ID: {}", app.id),
format!("Quorum Public Key: {}", app.quorum_public_key),
format!("Live Deployment: {live}"),
format_egress_enabled(app.enable_egress),
];

if !app.public_domain.is_empty() {
println!("Public Domain: {}", app.public_domain);
lines.push(format!("Public Domain: {}", app.public_domain));
}
println!("{}", "─".repeat(40));

lines.push("─".repeat(SEPARATOR_WIDTH));

println!("{}", lines.join("\n"));
}

#[cfg(test)]
Expand Down Expand Up @@ -145,4 +156,15 @@ mod tests {
"(none)"
);
}

#[test]
fn egress_enabled_line_reflects_app_setting() {
let mut app = make_app("my-app");
app.enable_egress = true;

assert_eq!(
format_egress_enabled(app.enable_egress),
"Egress Enabled: yes"
);
}
}
5 changes: 5 additions & 0 deletions tvc/src/commands/app/status.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ use anyhow::{anyhow, Context};
use clap::Args as ClapArgs;
use turnkey_client::generated::GetAppStatusRequest;

use crate::client::fetch_tvc_app;
use crate::commands::display::format_egress_enabled;

/// Get the live status of an app from the cluster.
#[derive(Debug, ClapArgs)]
#[command(about, long_about = None)]
Expand Down Expand Up @@ -33,9 +36,11 @@ pub async fn run(args: Args) -> anyhow::Result<()> {
.app_status
.ok_or_else(|| anyhow!("no status returned for app: {}", args.app_id))?,
);
let app = fetch_tvc_app(&auth, &args.app_id).await?;

println!("App ID: {}", app_status.app_id);
println!("Targeted Deployment: {}", app_status.targeted_deployment_id);
println!("{}", format_egress_enabled(app.enable_egress));

if app_status.deployments.is_empty() {
println!();
Expand Down
5 changes: 5 additions & 0 deletions tvc/src/commands/deploy/get_status.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ use clap::Args as ClapArgs;
use turnkey_client::generated::external::data::v1::{AppStatus, DeploymentStatus};
use turnkey_client::generated::{GetAppStatusRequest, GetTvcDeploymentRequest};

use crate::client::fetch_tvc_app;
use crate::commands::display::format_egress_enabled;

/// Get the live status of a deployment from the app status API.
#[derive(Debug, ClapArgs)]
#[command(about, long_about = None)]
Expand Down Expand Up @@ -49,9 +52,11 @@ pub async fn run(args: Args) -> anyhow::Result<()> {
.app_status
.ok_or_else(|| anyhow!("no status returned for app: {}", deployment.app_id))?,
);
let app = fetch_tvc_app(&auth, &deployment.app_id).await?;

println!("Deployment: {}", deployment.id);
println!("App ID: {}", app_status.app_id);
println!("{}", format_egress_enabled(app.enable_egress));
println!(
"Is Targeted Deployment: {}",
if app_status.targeted_deployment_id == args.deploy_id {
Expand Down
10 changes: 6 additions & 4 deletions tvc/src/commands/deploy/status.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ use clap::Args as ClapArgs;
use turnkey_client::generated::external::data::v1::TvcDeployment;
use turnkey_client::generated::GetTvcDeploymentRequest;

use crate::client::fetch_tvc_app;
use crate::commands::display::{format_egress_enabled, yes_no};

/// Get the status of a deployment.
#[derive(Debug, ClapArgs)]
#[command(about, long_about = None)]
Expand Down Expand Up @@ -37,9 +40,11 @@ pub async fn run(args: Args) -> anyhow::Result<()> {
.manifest
.as_ref()
.ok_or_else(|| anyhow::anyhow!("manifest not found in deployment"))?;
let app = fetch_tvc_app(&auth, &deployment.app_id).await?;

println!("Deployment: {}", deployment.id);
println!("App ID: {}", deployment.app_id);
println!("{}", format_egress_enabled(app.enable_egress));
println!("Manifest ID: {}", manifest.id);
println!("QOS Version: {}", deployment.qos_version);
println!("{}", format_marked_for_deletion(&deployment));
Expand Down Expand Up @@ -67,10 +72,7 @@ pub async fn run(args: Args) -> anyhow::Result<()> {
}

fn format_marked_for_deletion(deployment: &TvcDeployment) -> String {
format!(
"Marked for deletion: {}",
if deployment.delete { "yes" } else { "no" }
)
format!("Marked for deletion: {}", yes_no(deployment.delete))
}

#[cfg(test)]
Expand Down
24 changes: 24 additions & 0 deletions tvc/src/commands/display.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//! Shared display helpers for CLI output.

pub fn yes_no(value: bool) -> &'static str {
if value {
"yes"
} else {
"no"
}
}

pub fn format_egress_enabled(enable_egress: bool) -> String {
format!("Egress Enabled: {}", yes_no(enable_egress))
}

#[cfg(test)]
mod tests {
use super::format_egress_enabled;

#[test]
fn format_egress_enabled_formats_yes_and_no() {
assert_eq!(format_egress_enabled(true), "Egress Enabled: yes");
assert_eq!(format_egress_enabled(false), "Egress Enabled: no");
}
}
1 change: 1 addition & 0 deletions tvc/src/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@ pub mod app;
pub mod app_status;
pub mod confirmation;
pub mod deploy;
pub mod display;
pub mod keys;
pub mod login;
13 changes: 10 additions & 3 deletions tvc/src/config/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ pub struct AppConfig {
pub name: String,
pub quorum_public_key: String,
#[serde(default)]
pub enable_egress: Option<bool>,
pub enable_egress: bool,
#[serde(default)]
pub manifest_set_id: Option<String>,
#[serde(default)]
Expand Down Expand Up @@ -63,7 +63,7 @@ impl AppConfig {
Self {
name: "<FILL_IN_APP_NAME>".to_string(),
quorum_public_key: KNOWN_QUORUM_KEY.to_string(),
enable_egress: Some(false),
enable_egress: false,
manifest_set_id: None,
manifest_set_params: Some(OperatorSetParams {
name: "<FILL_IN_MANIFEST_SET_NAME>".to_string(),
Expand Down Expand Up @@ -224,7 +224,14 @@ mod tests {
json["enableEgress"] = json!(true);
let config: AppConfig = serde_json::from_value(json).unwrap();

assert_eq!(config.enable_egress, Some(true));
assert!(config.enable_egress);
}

#[test]
fn config_defaults_enable_egress_to_false() {
let config: AppConfig = serde_json::from_value(valid_config_json()).unwrap();

assert!(!config.enable_egress);
}

#[test]
Expand Down
Loading