Skip to content

Commit 142b9c3

Browse files
authored
Merge pull request #1312 from openabdev/fix/oabctl-get-config-cluster
fix(oabctl): read cluster/namespace defaults from config file
2 parents 83fbc89 + a20ee1f commit 142b9c3

3 files changed

Lines changed: 37 additions & 28 deletions

File tree

operator/src/apply.rs

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -543,14 +543,15 @@ async fn apply_ecs(
543543
// Match on the typed error code (InvalidParameterException) rather than
544544
// raw message text to be resilient to SDK/API wording changes.
545545
use aws_sdk_ecs::error::ProvideErrorMetadata;
546-
let mut last_err = None;
547-
for attempt in 0..12 {
546+
const DRAIN_RETRY_ATTEMPTS: u32 = 12;
547+
const DRAIN_RETRY_INTERVAL: std::time::Duration = std::time::Duration::from_secs(5);
548+
549+
for attempt in 0..DRAIN_RETRY_ATTEMPTS {
548550
match create_req.clone().send().await {
549551
Ok(_) => {
550552
if attempt > 0 {
551553
eprintln!(" ok");
552554
}
553-
last_err = None;
554555
break;
555556
}
556557
Err(e) => {
@@ -559,29 +560,28 @@ async fn apply_ecs(
559560
.unwrap_or_default()
560561
.to_lowercase()
561562
.contains("draining");
562-
if is_draining {
563+
let is_last = attempt == DRAIN_RETRY_ATTEMPTS - 1;
564+
if is_draining && !is_last {
563565
if attempt == 0 {
564566
eprint!(" ⏳ Service still draining, retrying...");
565567
} else {
566568
eprint!(".");
567569
}
568-
last_err = Some(e);
569-
if attempt < 11 {
570-
tokio::time::sleep(std::time::Duration::from_secs(5)).await;
571-
}
570+
tokio::time::sleep(DRAIN_RETRY_INTERVAL).await;
572571
} else {
573572
if attempt > 0 {
574573
eprintln!(" failed");
575574
}
576-
return Err(e).context("failed to create ECS service");
575+
let ctx = if is_last && is_draining {
576+
"failed to create ECS service after retries (service still draining)"
577+
} else {
578+
"failed to create ECS service"
579+
};
580+
return Err(e).context(ctx);
577581
}
578582
}
579583
}
580584
}
581-
if let Some(e) = last_err {
582-
eprintln!(" timed out");
583-
return Err(anyhow::anyhow!(e)).context("failed to create ECS service after retries");
584-
}
585585
println!(
586586
" ✓ {} created ({}, {}cpu/{}mem{})",
587587
m.metadata.name,

operator/src/delete.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,11 @@ pub async fn run(
9191
// 2a. Wait for the service to fully drain (INACTIVE status) so that
9292
// a subsequent `apply` doesn't hit "Unable to Start a service that
9393
// is still Draining".
94+
const DRAIN_POLL_ATTEMPTS: u32 = 12;
95+
const DRAIN_POLL_INTERVAL: std::time::Duration = std::time::Duration::from_secs(5);
96+
9497
eprint!(" ⏳ Waiting for drain to complete...");
95-
for i in 0..12 {
98+
for i in 0..DRAIN_POLL_ATTEMPTS {
9699
// Check status first, then sleep — avoids an unnecessary initial delay
97100
// when the service transitions quickly.
98101
let resp = ecs
@@ -116,16 +119,16 @@ pub async fn run(
116119
if i == 0 {
117120
eprintln!(" done (immediate)");
118121
} else {
119-
let elapsed = i * 5;
122+
let elapsed = u64::from(i) * DRAIN_POLL_INTERVAL.as_secs();
120123
eprintln!(" done ({elapsed}s)");
121124
}
122125
break;
123126
}
124-
if i == 11 {
127+
if i == DRAIN_POLL_ATTEMPTS - 1 {
125128
eprintln!(" timed out (service may still be draining)");
126129
} else {
127130
eprint!(".");
128-
tokio::time::sleep(std::time::Duration::from_secs(5)).await;
131+
tokio::time::sleep(DRAIN_POLL_INTERVAL).await;
129132
}
130133
}
131134

operator/src/main.rs

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,9 @@ enum Commands {
4949
resource: String,
5050
/// Optional resource name
5151
name: Option<String>,
52-
/// ECS cluster name
53-
#[arg(long, default_value = "default")]
54-
cluster: String,
52+
/// ECS cluster name (default: from ~/.oabctl/config.toml)
53+
#[arg(long)]
54+
cluster: Option<String>,
5555
},
5656
/// Delete an OAB service
5757
Delete {
@@ -63,13 +63,12 @@ enum Commands {
6363
/// instead of specifying <resource> <name> directly (mirrors `apply -f`)
6464
#[arg(short, long, conflicts_with_all = ["resource", "name"])]
6565
file: Option<String>,
66-
/// ECS cluster name (ignored when using -f — manifests are always
67-
/// deployed to the "oab" cluster, same as `apply`)
68-
#[arg(long, default_value = "default")]
69-
cluster: String,
70-
/// Namespace (ignored when using -f — read from each manifest instead)
71-
#[arg(long, default_value = "prod")]
72-
namespace: String,
66+
/// ECS cluster name (default: from ~/.oabctl/config.toml; ignored when using -f)
67+
#[arg(long)]
68+
cluster: Option<String>,
69+
/// Namespace (default: from ~/.oabctl/config.toml; ignored when using -f)
70+
#[arg(long)]
71+
namespace: Option<String>,
7372
},
7473
/// Execute a command in an agent container (via ecsctl)
7574
Exec {
@@ -133,13 +132,20 @@ async fn main() -> anyhow::Result<()> {
133132
match cli.command {
134133
Commands::Apply { file, no_sync, wait } => apply::run(&config, &file, !no_sync, wait).await,
135134
Commands::Create { name, namespace, auto_apply } => create::run(&config, &name, &namespace, auto_apply).await,
136-
Commands::Get { resource, name, cluster } => get::run(&config, &resource, name.as_deref(), &cluster).await,
135+
Commands::Get { resource, name, cluster } => {
136+
let oab_cfg = config::OabConfig::load().context("failed to load ~/.oabctl/config.toml")?;
137+
let cluster = cluster.unwrap_or(oab_cfg.defaults.cluster);
138+
get::run(&config, &resource, name.as_deref(), &cluster).await
139+
}
137140
Commands::Delete { resource, name, file, cluster, namespace } => {
138141
if let Some(file) = file {
139142
delete::run_from_file(&config, &file).await
140143
} else {
141144
let resource = resource.context("<RESOURCE> is required when not using -f")?;
142145
let name = name.context("<NAME> is required when not using -f")?;
146+
let oab_cfg = config::OabConfig::load().context("failed to load ~/.oabctl/config.toml")?;
147+
let cluster = cluster.unwrap_or(oab_cfg.defaults.cluster);
148+
let namespace = namespace.unwrap_or(oab_cfg.defaults.namespace);
143149
delete::run(&config, &resource, &name, &cluster, &namespace).await
144150
}
145151
}

0 commit comments

Comments
 (0)