From 04807026edb5da025177f5345189cebeb42e4c91 Mon Sep 17 00:00:00 2001 From: MasterPtato <23087326+MasterPtato@users.noreply.github.com> Date: Tue, 27 Aug 2024 18:51:51 +0000 Subject: [PATCH] feat(bolt): add lost servers list and prune commands (#1096) Fixes RVT-3816 ## Changes --- fern/definition/admin/clusters/common.yml | 4 +- fern/definition/admin/clusters/servers.yml | 23 + .../cli/src/commands/cluster/datacenter.rs | 104 ++++- lib/bolt/cli/src/commands/cluster/mod.rs | 234 ++--------- lib/bolt/cli/src/commands/cluster/server.rs | 394 ++++++++++++++++++ lib/bolt/core/src/tasks/ssh.rs | 2 +- lib/convert/src/impls/admin.rs | 15 +- sdks/full/go/admin/clusters/servers.go | 14 + sdks/full/go/admin/clusters/servers/client.go | 186 +++++++++ sdks/full/go/admin/clusters/types.go | 8 +- sdks/full/openapi/openapi.yml | 160 ++++++- sdks/full/openapi_compat/openapi.yml | 160 ++++++- sdks/full/rust-cli/README.md | 2 + .../rust-cli/docs/AdminClustersDatacenter.md | 2 +- .../full/rust-cli/docs/AdminClustersServer.md | 2 + .../rust-cli/docs/AdminClustersServersApi.md | 66 +++ .../src/apis/admin_clusters_servers_api.rs | 110 +++++ .../src/models/admin_clusters_datacenter.rs | 8 +- .../src/models/admin_clusters_server.rs | 8 +- sdks/full/rust/README.md | 2 + .../full/rust/docs/AdminClustersDatacenter.md | 2 +- sdks/full/rust/docs/AdminClustersServer.md | 2 + .../full/rust/docs/AdminClustersServersApi.md | 66 +++ .../src/apis/admin_clusters_servers_api.rs | 110 +++++ .../src/models/admin_clusters_datacenter.rs | 8 +- .../rust/src/models/admin_clusters_server.rs | 8 +- sdks/full/typescript/archive.tgz | 4 +- .../resources/servers/client/Client.ts | 302 ++++++++++++++ .../client/requests/ListLostServersRequest.ts | 21 + .../client/requests/PruneServersRequest.ts | 21 + .../servers/client/requests/index.ts | 2 + .../resources/common/types/Datacenter.d.ts | 2 +- .../resources/common/types/Server.d.ts | 3 + .../resources/servers/client/Client.d.ts | 42 ++ .../servers/client/requests/index.d.ts | 2 + .../resources/common/types/Datacenter.d.ts | 2 +- .../resources/common/types/Server.d.ts | 3 + sdks/runtime/typescript/archive.tgz | 4 +- svc/Cargo.lock | 169 ++++---- .../admin/src/route/clusters/datacenters.rs | 2 +- svc/api/admin/src/route/clusters/servers.rs | 48 ++- svc/api/admin/src/route/mod.rs | 13 + svc/pkg/cluster/Cargo.toml | 1 + svc/pkg/cluster/src/ops/server/get.rs | 3 + svc/pkg/cluster/src/ops/server/list.rs | 13 +- svc/pkg/cluster/src/ops/server/lost_list.rs | 180 ++++++++ svc/pkg/cluster/src/ops/server/mod.rs | 2 + .../src/ops/server/prune_with_filter.rs | 110 +++++ svc/pkg/cluster/src/types.rs | 3 +- svc/pkg/linode/src/util/api.rs | 20 + 50 files changed, 2342 insertions(+), 330 deletions(-) create mode 100644 lib/bolt/cli/src/commands/cluster/server.rs create mode 100644 sdks/full/typescript/src/api/resources/admin/resources/clusters/resources/servers/client/requests/ListLostServersRequest.ts create mode 100644 sdks/full/typescript/src/api/resources/admin/resources/clusters/resources/servers/client/requests/PruneServersRequest.ts create mode 100644 svc/pkg/cluster/src/ops/server/lost_list.rs create mode 100644 svc/pkg/cluster/src/ops/server/prune_with_filter.rs diff --git a/fern/definition/admin/clusters/common.yml b/fern/definition/admin/clusters/common.yml index cd5d8ce66a..210f67863b 100644 --- a/fern/definition/admin/clusters/common.yml +++ b/fern/definition/admin/clusters/common.yml @@ -44,13 +44,15 @@ types: display_name: string provider: Provider provider_datacenter_id: string - provider_api_token: optional pools: list build_delivery_method: BuildDeliveryMethod + prebakes_enabled: boolean Server: properties: server_id: uuid + datacenter_id: uuid + pool_type: PoolType public_ip: optional PoolUpdate: diff --git a/fern/definition/admin/clusters/servers.yml b/fern/definition/admin/clusters/servers.yml index d05ca808a7..e0da49f511 100644 --- a/fern/definition/admin/clusters/servers.yml +++ b/fern/definition/admin/clusters/servers.yml @@ -44,6 +44,29 @@ service: pool: optional public_ip: optional + listLost: + path: /lost + method: GET + request: + name: ListLostServersRequest + query-parameters: + server_id: optional + datacenter: optional + pool: optional + public_ip: optional + response: ListServersResponse + + prune: + path: /prune + method: POST + request: + name: PruneServersRequest + query-parameters: + server_id: optional + datacenter: optional + pool: optional + public_ip: optional + types: ListServersResponse: properties: diff --git a/lib/bolt/cli/src/commands/cluster/datacenter.rs b/lib/bolt/cli/src/commands/cluster/datacenter.rs index a28989612f..ebc9250ea9 100644 --- a/lib/bolt/cli/src/commands/cluster/datacenter.rs +++ b/lib/bolt/cli/src/commands/cluster/datacenter.rs @@ -2,8 +2,6 @@ use anyhow::*; use bolt_core::context::ProjectContext; use clap::{Parser, ValueEnum}; use rivet_api::{apis::*, models}; -use tabled::Tabled; -use uuid::Uuid; #[derive(ValueEnum, Clone)] pub enum DatacenterProvider { @@ -59,10 +57,10 @@ pub enum SubCommand { /// Creates a new datacenter Create { /// The name id of the cluster - #[clap(long, short = 'c')] + #[clap(index = 1)] cluster: String, /// The name id of the datacenter - #[clap(long, short = 'd')] + #[clap(index = 2)] name_id: String, /// The display name of the datacenter #[clap(long)] @@ -83,19 +81,19 @@ pub enum SubCommand { /// Lists all datacenters of a cluster List { /// The name id of the cluster - #[clap(long, short = 'c')] + #[clap(index = 1)] cluster: String, }, /// Update a datacenter's pools Update { /// The name id of the cluster - #[clap(long, short = 'c')] + #[clap(index = 1)] cluster: String, /// The name id of the datacenter - #[clap(index = 1)] + #[clap(index = 2)] name_id: String, /// The pool type - #[clap(index = 2)] + #[clap(index = 3)] pool: DatacenterPoolType, /// The hardware types #[clap(long)] @@ -118,12 +116,6 @@ pub enum SubCommand { }, } -#[derive(Tabled)] -struct DatacenterTableRow { - name_id: String, - datacenter_id: Uuid, -} - impl SubCommand { pub async fn execute(self, ctx: ProjectContext) -> Result<()> { match self { @@ -191,11 +183,10 @@ impl SubCommand { .await? .datacenters; - rivet_term::status::success("Datacenters", ""); - rivet_term::format::table(datacenters.iter().map(|d| DatacenterTableRow { - name_id: d.name_id.clone(), - datacenter_id: d.datacenter_id, - })); + rivet_term::status::success("Datacenters", datacenters.len().to_string()); + if !datacenters.is_empty() { + render::datacenters(datacenters); + } } Self::Update { cluster: cluster_name_id, @@ -264,3 +255,78 @@ impl SubCommand { Ok(()) } } + +mod render { + use rivet_api::models; + use tabled::Tabled; + use uuid::Uuid; + + use super::super::render::display_option; + + #[derive(Tabled, Default)] + struct DcTableRow { + #[tabled(display_with = "display_option")] + pub name_id: Option, + #[tabled(display_with = "display_option")] + pub datacenter_id: Option, + #[tabled(display_with = "display_provider")] + pub provider: Option, + #[tabled(inline)] + pub pool: PoolTableRow, + #[tabled(display_with = "display_option")] + pub prebakes_enabled: Option, + } + + #[derive(Tabled, Default)] + struct PoolTableRow { + #[tabled(display_with = "display_pool_type")] + pub pool_type: Option, + #[tabled(display_with = "display_option")] + pub min_count: Option, + #[tabled(display_with = "display_option")] + pub desired_count: Option, + #[tabled(display_with = "display_option")] + pub max_count: Option, + } + + pub fn datacenters(mut datacenters: Vec) { + let rows = datacenters.iter_mut().flat_map(|d| { + d.pools.sort_by_key(|pool| pool.pool_type); + + std::iter::once(DcTableRow { + name_id: Some(d.name_id.clone()), + datacenter_id: Some(d.datacenter_id), + provider: Some(d.provider), + prebakes_enabled: Some(d.prebakes_enabled), + ..Default::default() + }) + .chain(d.pools.iter().cloned().map(|pool| DcTableRow { + pool: PoolTableRow { + pool_type: Some(pool.pool_type), + min_count: Some(pool.min_count), + desired_count: Some(pool.desired_count), + max_count: Some(pool.max_count), + }, + ..Default::default() + })) + }); + + rivet_term::format::table(rows); + } + + fn display_provider(item: &Option) -> String { + match item { + Some(models::AdminClustersProvider::Linode) => "Linode".to_string(), + None => String::new(), + } + } + + fn display_pool_type(item: &Option) -> String { + match item { + Some(models::AdminClustersPoolType::Job) => "Job".to_string(), + Some(models::AdminClustersPoolType::Gg) => "GG".to_string(), + Some(models::AdminClustersPoolType::Ats) => "ATS".to_string(), + None => String::new(), + } + } +} diff --git a/lib/bolt/cli/src/commands/cluster/mod.rs b/lib/bolt/cli/src/commands/cluster/mod.rs index 33a6e7470e..7d67089d89 100644 --- a/lib/bolt/cli/src/commands/cluster/mod.rs +++ b/lib/bolt/cli/src/commands/cluster/mod.rs @@ -1,11 +1,11 @@ use anyhow::*; -use bolt_core::{context::ProjectContext, tasks::ssh}; +use bolt_core::context::ProjectContext; use clap::Parser; use rivet_api::{apis::*, models}; -use tabled::Tabled; use uuid::Uuid; mod datacenter; +mod server; #[derive(Parser)] pub enum SubCommand { @@ -20,62 +20,18 @@ pub enum SubCommand { }, /// Lists all clusters List, - /// Taint servers in a cluster - Taint { - /// The name id of the cluster - #[clap(index = 1)] - cluster: String, - #[clap(long)] - server_id: Option, - #[clap(long, short = 'p')] - pool: Option, - #[clap(long, short = 'd')] - datacenter: Option, - #[clap(long)] - ip: Option, - }, - /// Destroy servers in a cluster - Destroy { - /// The name id of the cluster - #[clap(index = 1)] - cluster: String, - #[clap(long)] - server_id: Option, - #[clap(long, short = 'p')] - pool: Option, - #[clap(long, short = 'd')] - datacenter: Option, - #[clap(long)] - ip: Option, - }, - /// SSH in to a server in the cluster - Ssh { - /// The name id of the cluster - #[clap(index = 1)] - cluster: String, - #[clap(long)] - server_id: Option, - #[clap(long, short = 'p')] - pool: Option, - #[clap(long, short = 'd')] - datacenter: Option, - #[clap(long)] - ip: Option, - - #[clap(long, short = 'c')] - command: Option, - }, /// Datacenter handler + #[clap(alias = "dc")] Datacenter { #[clap(subcommand)] command: datacenter::SubCommand, }, -} - -#[derive(Tabled)] -struct ClusterTableRow { - name_id: String, - cluster_id: Uuid, + /// Server handler + #[clap(alias = "s")] + Server { + #[clap(subcommand)] + command: server::SubCommand, + }, } impl SubCommand { @@ -101,7 +57,6 @@ impl SubCommand { rivet_term::status::success("Cluster created", ""); } - Self::List => { let clusters = admin_clusters_api::admin_clusters_list(&ctx.openapi_config_cloud().await?) @@ -109,148 +64,51 @@ impl SubCommand { .unwrap() .clusters; - rivet_term::status::success("Clusters", ""); - rivet_term::format::table(clusters.iter().map(|c| ClusterTableRow { - name_id: c.name_id.clone(), - cluster_id: c.cluster_id, - })); - } - - Self::Taint { - cluster: cluster_name_id, - server_id, - pool, - datacenter, - ip, - } => { - let cloud_config = ctx.openapi_config_cloud().await?; - - // Look up cluster - let clusters = admin_clusters_api::admin_clusters_list(&cloud_config) - .await? - .clusters; - let cluster = clusters.iter().find(|c| c.name_id == cluster_name_id); - let cluster = match cluster { - Some(c) => c, - None => bail!("cluster with the name id {} not found", cluster_name_id), - }; - - // Taint servers - let pool_type = pool - .map(|p| match p.as_str() { - "job" => Ok(models::AdminClustersPoolType::Job), - "gg" => Ok(models::AdminClustersPoolType::Gg), - "ats" => Ok(models::AdminClustersPoolType::Ats), - _ => Err(anyhow!("invalid pool type")), - }) - .transpose()?; - admin_clusters_servers_api::admin_clusters_servers_taint( - &cloud_config, - &cluster.cluster_id.to_string(), - server_id.as_deref(), - datacenter.as_deref(), - pool_type, - ip.as_deref(), - ) - .await?; - } - Self::Destroy { - cluster: cluster_name_id, - server_id, - pool, - datacenter, - ip, - } => { - let cloud_config = ctx.openapi_config_cloud().await?; - - // Look up cluster - let clusters = admin_clusters_api::admin_clusters_list(&cloud_config) - .await? - .clusters; - let cluster = clusters.iter().find(|c| c.name_id == cluster_name_id); - let cluster = match cluster { - Some(c) => c, - None => bail!("cluster with the name id {} not found", cluster_name_id), - }; - - // Destroy servers - let pool_type = pool - .map(|p| match p.as_str() { - "job" => Ok(models::AdminClustersPoolType::Job), - "gg" => Ok(models::AdminClustersPoolType::Gg), - "ats" => Ok(models::AdminClustersPoolType::Ats), - _ => Err(anyhow!("invalid pool type")), - }) - .transpose()?; - admin_clusters_servers_api::admin_clusters_servers_destroy( - &cloud_config, - &cluster.cluster_id.to_string(), - server_id.as_deref(), - datacenter.as_deref(), - pool_type, - ip.as_deref(), - ) - .await?; - } - Self::Ssh { - cluster: cluster_name_id, - command, - server_id, - pool, - datacenter, - ip, - } => { - let cloud_config = ctx.openapi_config_cloud().await?; - - // Look up cluster - let clusters = admin_clusters_api::admin_clusters_list(&cloud_config) - .await? - .clusters; - let cluster = clusters.iter().find(|c| c.name_id == cluster_name_id); - let cluster = match cluster { - Some(c) => c, - None => bail!("cluster with the name id {} not found", cluster_name_id), - }; - - // Look up server IPs - let pool_type = pool - .map(|p| match p.as_str() { - "job" => Ok(models::AdminClustersPoolType::Job), - "gg" => Ok(models::AdminClustersPoolType::Gg), - "ats" => Ok(models::AdminClustersPoolType::Ats), - _ => Err(anyhow!("invalid pool type")), - }) - .transpose()?; - let mut servers = admin_clusters_servers_api::admin_clusters_servers_list( - &cloud_config, - &cluster.cluster_id.to_string(), - server_id.as_deref(), - datacenter.as_deref(), - pool_type, - ip.as_deref(), - ) - .await?; - servers.servers.sort_by_key(|s| s.server_id); - let server_ips = servers - .servers - .iter() - .filter_map(|x| x.public_ip.as_ref()) - .map(|x| x.as_str()) - .collect::>(); + rivet_term::status::success("Clusters", clusters.len().to_string()); - // SSH in to servers - if let Some(command) = command { - ssh::ip_all(&ctx, &server_ips, &command).await?; - } else { - let ip = server_ips.first().context("no matching servers")?; - ssh::ip(&ctx, ip, command.as_deref()).await?; + if !clusters.is_empty() { + render::clusters(clusters); } } Self::Datacenter { command } => { command.execute(ctx).await?; } + Self::Server { command } => { + command.execute(ctx).await?; + } } Ok(()) } } + +mod render { + use rivet_api::models; + use tabled::Tabled; + use uuid::Uuid; + + #[derive(Tabled)] + pub struct ClusterTableRow { + pub name_id: String, + pub cluster_id: Uuid, + #[tabled(display_with = "display_option")] + pub owner_team_id: Option, + } + + pub fn clusters(clusters: Vec) { + let rows = clusters.iter().map(|c| ClusterTableRow { + name_id: c.name_id.clone(), + cluster_id: c.cluster_id, + owner_team_id: c.owner_team_id, + }); + + rivet_term::format::table(rows); + } + + pub(crate) fn display_option(item: &Option) -> String { + match item { + Some(s) => s.to_string(), + None => String::new(), + } + } +} diff --git a/lib/bolt/cli/src/commands/cluster/server.rs b/lib/bolt/cli/src/commands/cluster/server.rs new file mode 100644 index 0000000000..ca48d05502 --- /dev/null +++ b/lib/bolt/cli/src/commands/cluster/server.rs @@ -0,0 +1,394 @@ +use anyhow::*; +use bolt_core::{context::ProjectContext, tasks::ssh}; +use clap::Parser; +use rivet_api::{apis::*, models}; + +#[derive(Parser)] +pub enum SubCommand { + /// Lists all datacenters of a cluster + List { + /// The name id of the cluster + #[clap(index = 1)] + cluster: String, + #[clap(long)] + server_id: Option, + #[clap(long, short = 'p')] + pool: Option, + #[clap(long, short = 'd')] + datacenter: Option, + #[clap(long)] + ip: Option, + }, + /// Taint servers in a cluster + Taint { + /// The name id of the cluster + #[clap(index = 1)] + cluster: String, + #[clap(long)] + server_id: Option, + #[clap(long, short = 'p')] + pool: Option, + #[clap(long, short = 'd')] + datacenter: Option, + #[clap(long)] + ip: Option, + }, + /// Destroy servers in a cluster + Destroy { + /// The name id of the cluster + #[clap(index = 1)] + cluster: String, + #[clap(long)] + server_id: Option, + #[clap(long, short = 'p')] + pool: Option, + #[clap(long, short = 'd')] + datacenter: Option, + #[clap(long)] + ip: Option, + }, + /// Lists lost servers in a cluster + ListLost { + /// The name id of the cluster + #[clap(index = 1)] + cluster: String, + #[clap(long)] + server_id: Option, + #[clap(long, short = 'p')] + pool: Option, + #[clap(long, short = 'd')] + datacenter: Option, + #[clap(long)] + ip: Option, + }, + /// Prunes lost servers in a cluster. use `list-lost` to see servers first. + Prune { + /// The name id of the cluster + #[clap(index = 1)] + cluster: String, + #[clap(long)] + server_id: Option, + #[clap(long, short = 'p')] + pool: Option, + #[clap(long, short = 'd')] + datacenter: Option, + #[clap(long)] + ip: Option, + }, + /// SSH in to a server in the cluster + Ssh { + /// The name id of the cluster + #[clap(index = 1)] + cluster: String, + #[clap(long)] + server_id: Option, + #[clap(long, short = 'p')] + pool: Option, + #[clap(long, short = 'd')] + datacenter: Option, + #[clap(long)] + ip: Option, + + #[clap(long, short = 'c')] + command: Option, + }, +} + +impl SubCommand { + pub async fn execute(self, ctx: ProjectContext) -> Result<()> { + match self { + Self::List { + cluster: cluster_name_id, + server_id, + pool, + datacenter, + ip, + } => { + let cloud_config = ctx.openapi_config_cloud().await?; + + // Look up cluster + let clusters = admin_clusters_api::admin_clusters_list(&cloud_config) + .await? + .clusters; + let cluster = clusters.iter().find(|c| c.name_id == cluster_name_id); + let cluster = match cluster { + Some(c) => c, + None => bail!("cluster with the name id {} not found", cluster_name_id), + }; + + // Taint servers + let pool_type = pool + .map(|p| match p.as_str() { + "job" => Ok(models::AdminClustersPoolType::Job), + "gg" => Ok(models::AdminClustersPoolType::Gg), + "ats" => Ok(models::AdminClustersPoolType::Ats), + _ => Err(anyhow!("invalid pool type")), + }) + .transpose()?; + let servers = admin_clusters_servers_api::admin_clusters_servers_list( + &cloud_config, + &cluster.cluster_id.to_string(), + server_id.as_deref(), + datacenter.as_deref(), + pool_type, + ip.as_deref(), + ) + .await? + .servers; + + rivet_term::status::success("Servers", servers.len().to_string()); + render::servers(servers); + } + Self::Taint { + cluster: cluster_name_id, + server_id, + pool, + datacenter, + ip, + } => { + let cloud_config = ctx.openapi_config_cloud().await?; + + // Look up cluster + let clusters = admin_clusters_api::admin_clusters_list(&cloud_config) + .await? + .clusters; + let cluster = clusters.iter().find(|c| c.name_id == cluster_name_id); + let cluster = match cluster { + Some(c) => c, + None => bail!("cluster with the name id {} not found", cluster_name_id), + }; + + // Taint servers + let pool_type = pool + .map(|p| match p.as_str() { + "job" => Ok(models::AdminClustersPoolType::Job), + "gg" => Ok(models::AdminClustersPoolType::Gg), + "ats" => Ok(models::AdminClustersPoolType::Ats), + _ => Err(anyhow!("invalid pool type")), + }) + .transpose()?; + admin_clusters_servers_api::admin_clusters_servers_taint( + &cloud_config, + &cluster.cluster_id.to_string(), + server_id.as_deref(), + datacenter.as_deref(), + pool_type, + ip.as_deref(), + ) + .await?; + } + Self::Destroy { + cluster: cluster_name_id, + server_id, + pool, + datacenter, + ip, + } => { + let cloud_config = ctx.openapi_config_cloud().await?; + + // Look up cluster + let clusters = admin_clusters_api::admin_clusters_list(&cloud_config) + .await? + .clusters; + let cluster = clusters.iter().find(|c| c.name_id == cluster_name_id); + let cluster = match cluster { + Some(c) => c, + None => bail!("cluster with the name id {} not found", cluster_name_id), + }; + + // Destroy servers + let pool_type = pool + .map(|p| match p.as_str() { + "job" => Ok(models::AdminClustersPoolType::Job), + "gg" => Ok(models::AdminClustersPoolType::Gg), + "ats" => Ok(models::AdminClustersPoolType::Ats), + _ => Err(anyhow!("invalid pool type")), + }) + .transpose()?; + admin_clusters_servers_api::admin_clusters_servers_destroy( + &cloud_config, + &cluster.cluster_id.to_string(), + server_id.as_deref(), + datacenter.as_deref(), + pool_type, + ip.as_deref(), + ) + .await?; + } + Self::ListLost { + cluster: cluster_name_id, + server_id, + pool, + datacenter, + ip, + } => { + let cloud_config = ctx.openapi_config_cloud().await?; + + // Look up cluster + let clusters = admin_clusters_api::admin_clusters_list(&cloud_config) + .await? + .clusters; + let cluster = clusters.iter().find(|c| c.name_id == cluster_name_id); + let cluster = match cluster { + Some(c) => c, + None => bail!("cluster with the name id {} not found", cluster_name_id), + }; + + let pool_type = pool + .map(|p| match p.as_str() { + "job" => Ok(models::AdminClustersPoolType::Job), + "gg" => Ok(models::AdminClustersPoolType::Gg), + "ats" => Ok(models::AdminClustersPoolType::Ats), + _ => Err(anyhow!("invalid pool type")), + }) + .transpose()?; + let servers = admin_clusters_servers_api::admin_clusters_servers_list_lost( + &cloud_config, + &cluster.cluster_id.to_string(), + server_id.as_deref(), + datacenter.as_deref(), + pool_type, + ip.as_deref(), + ) + .await? + .servers; + + rivet_term::status::success("Lost Servers", servers.len().to_string()); + if !servers.is_empty() { + render::servers(servers); + } + } + Self::Prune { + cluster: cluster_name_id, + server_id, + pool, + datacenter, + ip, + } => { + let cloud_config = ctx.openapi_config_cloud().await?; + + // Look up cluster + let clusters = admin_clusters_api::admin_clusters_list(&cloud_config) + .await? + .clusters; + let cluster = clusters.iter().find(|c| c.name_id == cluster_name_id); + let cluster = match cluster { + Some(c) => c, + None => bail!("cluster with the name id {} not found", cluster_name_id), + }; + + // Prune servers + let pool_type = pool + .map(|p| match p.as_str() { + "job" => Ok(models::AdminClustersPoolType::Job), + "gg" => Ok(models::AdminClustersPoolType::Gg), + "ats" => Ok(models::AdminClustersPoolType::Ats), + _ => Err(anyhow!("invalid pool type")), + }) + .transpose()?; + admin_clusters_servers_api::admin_clusters_servers_prune( + &cloud_config, + &cluster.cluster_id.to_string(), + server_id.as_deref(), + datacenter.as_deref(), + pool_type, + ip.as_deref(), + ) + .await?; + } + Self::Ssh { + cluster: cluster_name_id, + command, + server_id, + pool, + datacenter, + ip, + } => { + let cloud_config = ctx.openapi_config_cloud().await?; + + // Look up cluster + let clusters = admin_clusters_api::admin_clusters_list(&cloud_config) + .await? + .clusters; + let cluster = clusters.iter().find(|c| c.name_id == cluster_name_id); + let cluster = match cluster { + Some(c) => c, + None => bail!("cluster with the name id {} not found", cluster_name_id), + }; + + // Look up server IPs + let pool_type = pool + .map(|p| match p.as_str() { + "job" => Ok(models::AdminClustersPoolType::Job), + "gg" => Ok(models::AdminClustersPoolType::Gg), + "ats" => Ok(models::AdminClustersPoolType::Ats), + _ => Err(anyhow!("invalid pool type")), + }) + .transpose()?; + let mut servers = admin_clusters_servers_api::admin_clusters_servers_list( + &cloud_config, + &cluster.cluster_id.to_string(), + server_id.as_deref(), + datacenter.as_deref(), + pool_type, + ip.as_deref(), + ) + .await?; + servers.servers.sort_by_key(|s| s.server_id); + let server_ips = servers + .servers + .iter() + .filter_map(|x| x.public_ip.as_ref()) + .map(|x| x.as_str()) + .collect::>(); + + // SSH in to servers + if let Some(command) = command { + ssh::ip_all(&ctx, &server_ips, &command).await?; + } else { + let ip = server_ips.first().context("no matching servers")?; + ssh::ip(&ctx, ip, command.as_deref()).await?; + } + } + } + + Ok(()) + } +} + +mod render { + use rivet_api::models; + use tabled::Tabled; + use uuid::Uuid; + + use super::super::render::display_option; + + #[derive(Tabled, Default)] + struct ServerTableRow { + pub server_id: Uuid, + pub datacenter_id: Uuid, + #[tabled(display_with = "display_pool_type")] + pub pool_type: models::AdminClustersPoolType, + #[tabled(display_with = "display_option")] + pub public_ip: Option, + } + + pub fn servers(servers: Vec) { + let rows = servers.iter().map(|s| ServerTableRow { + server_id: s.server_id, + datacenter_id: s.datacenter_id, + pool_type: s.pool_type, + public_ip: s.public_ip.clone(), + }); + + rivet_term::format::table(rows); + } + + fn display_pool_type(item: &models::AdminClustersPoolType) -> String { + match item { + models::AdminClustersPoolType::Job => "Job".to_string(), + models::AdminClustersPoolType::Gg => "GG".to_string(), + models::AdminClustersPoolType::Ats => "ATS".to_string(), + } + } +} diff --git a/lib/bolt/core/src/tasks/ssh.rs b/lib/bolt/core/src/tasks/ssh.rs index 72fb0fd574..bb9a6891aa 100644 --- a/lib/bolt/core/src/tasks/ssh.rs +++ b/lib/bolt/core/src/tasks/ssh.rs @@ -5,7 +5,7 @@ use duct::cmd; use futures_util::StreamExt; use tokio::task::block_in_place; -use crate::{context::ProjectContext, tasks}; +use crate::context::ProjectContext; pub struct TempSshKey { tempfile: tempfile::NamedTempFile, diff --git a/lib/convert/src/impls/admin.rs b/lib/convert/src/impls/admin.rs index f30db34bbb..2091f072f9 100644 --- a/lib/convert/src/impls/admin.rs +++ b/lib/convert/src/impls/admin.rs @@ -113,8 +113,8 @@ impl ApiTryFrom for models::AdminClustersDatacenter }) .collect::>>()?, provider: value.provider.api_into(), - provider_api_token: value.provider_api_token, provider_datacenter_id: value.provider_datacenter_id, + prebakes_enabled: value.prebakes_enabled, }) } } @@ -137,3 +137,16 @@ impl ApiFrom for cluster::types::PoolUpdate { } } } + +impl ApiTryFrom for models::AdminClustersServer { + type Error = GlobalError; + + fn api_try_from(value: cluster::types::Server) -> GlobalResult { + Ok(models::AdminClustersServer { + server_id: value.server_id, + datacenter_id: value.datacenter_id, + pool_type: value.pool_type.api_into(), + public_ip: value.public_ip.map(|ip| ip.to_string()), + }) + } +} \ No newline at end of file diff --git a/sdks/full/go/admin/clusters/servers.go b/sdks/full/go/admin/clusters/servers.go index f97bbee9bb..753c6e046a 100644 --- a/sdks/full/go/admin/clusters/servers.go +++ b/sdks/full/go/admin/clusters/servers.go @@ -22,6 +22,20 @@ type ListServersRequest struct { PublicIp *string `json:"-"` } +type ListLostServersRequest struct { + ServerId *string `json:"-"` + Datacenter *string `json:"-"` + Pool *PoolType `json:"-"` + PublicIp *string `json:"-"` +} + +type PruneServersRequest struct { + ServerId *string `json:"-"` + Datacenter *string `json:"-"` + Pool *PoolType `json:"-"` + PublicIp *string `json:"-"` +} + type TaintServersRequest struct { ServerId *string `json:"-"` Datacenter *string `json:"-"` diff --git a/sdks/full/go/admin/clusters/servers/client.go b/sdks/full/go/admin/clusters/servers/client.go index 3b710dcd36..b80b3bb5ab 100644 --- a/sdks/full/go/admin/clusters/servers/client.go +++ b/sdks/full/go/admin/clusters/servers/client.go @@ -312,3 +312,189 @@ func (c *Client) Destroy(ctx context.Context, clusterId uuid.UUID, request *clus } return nil } + +func (c *Client) ListLost(ctx context.Context, clusterId uuid.UUID, request *clusters.ListLostServersRequest) (*clusters.ListServersResponse, error) { + baseURL := "https://api.rivet.gg" + if c.baseURL != "" { + baseURL = c.baseURL + } + endpointURL := fmt.Sprintf(baseURL+"/"+"admin/clusters/%v/servers/lost", clusterId) + + queryParams := make(url.Values) + if request.ServerId != nil { + queryParams.Add("server_id", fmt.Sprintf("%v", *request.ServerId)) + } + if request.Datacenter != nil { + queryParams.Add("datacenter", fmt.Sprintf("%v", *request.Datacenter)) + } + if request.Pool != nil { + queryParams.Add("pool", fmt.Sprintf("%v", *request.Pool)) + } + if request.PublicIp != nil { + queryParams.Add("public_ip", fmt.Sprintf("%v", *request.PublicIp)) + } + if len(queryParams) > 0 { + endpointURL += "?" + queryParams.Encode() + } + + errorDecoder := func(statusCode int, body io.Reader) error { + raw, err := io.ReadAll(body) + if err != nil { + return err + } + apiError := core.NewAPIError(statusCode, errors.New(string(raw))) + decoder := json.NewDecoder(bytes.NewReader(raw)) + switch statusCode { + case 500: + value := new(sdk.InternalError) + value.APIError = apiError + if err := decoder.Decode(value); err != nil { + return apiError + } + return value + case 429: + value := new(sdk.RateLimitError) + value.APIError = apiError + if err := decoder.Decode(value); err != nil { + return apiError + } + return value + case 403: + value := new(sdk.ForbiddenError) + value.APIError = apiError + if err := decoder.Decode(value); err != nil { + return apiError + } + return value + case 408: + value := new(sdk.UnauthorizedError) + value.APIError = apiError + if err := decoder.Decode(value); err != nil { + return apiError + } + return value + case 404: + value := new(sdk.NotFoundError) + value.APIError = apiError + if err := decoder.Decode(value); err != nil { + return apiError + } + return value + case 400: + value := new(sdk.BadRequestError) + value.APIError = apiError + if err := decoder.Decode(value); err != nil { + return apiError + } + return value + } + return apiError + } + + var response *clusters.ListServersResponse + if err := c.caller.Call( + ctx, + &core.CallParams{ + URL: endpointURL, + Method: http.MethodGet, + Headers: c.header, + Response: &response, + ErrorDecoder: errorDecoder, + }, + ); err != nil { + return nil, err + } + return response, nil +} + +func (c *Client) Prune(ctx context.Context, clusterId uuid.UUID, request *clusters.PruneServersRequest) error { + baseURL := "https://api.rivet.gg" + if c.baseURL != "" { + baseURL = c.baseURL + } + endpointURL := fmt.Sprintf(baseURL+"/"+"admin/clusters/%v/servers/prune", clusterId) + + queryParams := make(url.Values) + if request.ServerId != nil { + queryParams.Add("server_id", fmt.Sprintf("%v", *request.ServerId)) + } + if request.Datacenter != nil { + queryParams.Add("datacenter", fmt.Sprintf("%v", *request.Datacenter)) + } + if request.Pool != nil { + queryParams.Add("pool", fmt.Sprintf("%v", *request.Pool)) + } + if request.PublicIp != nil { + queryParams.Add("public_ip", fmt.Sprintf("%v", *request.PublicIp)) + } + if len(queryParams) > 0 { + endpointURL += "?" + queryParams.Encode() + } + + errorDecoder := func(statusCode int, body io.Reader) error { + raw, err := io.ReadAll(body) + if err != nil { + return err + } + apiError := core.NewAPIError(statusCode, errors.New(string(raw))) + decoder := json.NewDecoder(bytes.NewReader(raw)) + switch statusCode { + case 500: + value := new(sdk.InternalError) + value.APIError = apiError + if err := decoder.Decode(value); err != nil { + return apiError + } + return value + case 429: + value := new(sdk.RateLimitError) + value.APIError = apiError + if err := decoder.Decode(value); err != nil { + return apiError + } + return value + case 403: + value := new(sdk.ForbiddenError) + value.APIError = apiError + if err := decoder.Decode(value); err != nil { + return apiError + } + return value + case 408: + value := new(sdk.UnauthorizedError) + value.APIError = apiError + if err := decoder.Decode(value); err != nil { + return apiError + } + return value + case 404: + value := new(sdk.NotFoundError) + value.APIError = apiError + if err := decoder.Decode(value); err != nil { + return apiError + } + return value + case 400: + value := new(sdk.BadRequestError) + value.APIError = apiError + if err := decoder.Decode(value); err != nil { + return apiError + } + return value + } + return apiError + } + + if err := c.caller.Call( + ctx, + &core.CallParams{ + URL: endpointURL, + Method: http.MethodPost, + Headers: c.header, + ErrorDecoder: errorDecoder, + }, + ); err != nil { + return err + } + return nil +} diff --git a/sdks/full/go/admin/clusters/types.go b/sdks/full/go/admin/clusters/types.go index b8b0b1615f..81f0fcebc9 100644 --- a/sdks/full/go/admin/clusters/types.go +++ b/sdks/full/go/admin/clusters/types.go @@ -70,9 +70,9 @@ type Datacenter struct { DisplayName string `json:"display_name"` Provider Provider `json:"provider,omitempty"` ProviderDatacenterId string `json:"provider_datacenter_id"` - ProviderApiToken *string `json:"provider_api_token,omitempty"` Pools []*Pool `json:"pools,omitempty"` BuildDeliveryMethod BuildDeliveryMethod `json:"build_delivery_method,omitempty"` + PrebakesEnabled bool `json:"prebakes_enabled"` _rawJSON json.RawMessage } @@ -217,8 +217,10 @@ func (p Provider) Ptr() *Provider { } type Server struct { - ServerId uuid.UUID `json:"server_id"` - PublicIp *string `json:"public_ip,omitempty"` + ServerId uuid.UUID `json:"server_id"` + DatacenterId uuid.UUID `json:"datacenter_id"` + PoolType PoolType `json:"pool_type,omitempty"` + PublicIp *string `json:"public_ip,omitempty"` _rawJSON json.RawMessage } diff --git a/sdks/full/openapi/openapi.yml b/sdks/full/openapi/openapi.yml index f58e8fede3..d4228f5e7e 100644 --- a/sdks/full/openapi/openapi.yml +++ b/sdks/full/openapi/openapi.yml @@ -5574,6 +5574,154 @@ paths: schema: $ref: '#/components/schemas/ErrorBody' security: *ref_0 + /admin/clusters/{cluster_id}/servers/lost: + get: + operationId: admin_clusters_servers_listLost + tags: + - AdminClustersServers + parameters: + - name: cluster_id + in: path + required: true + schema: + type: string + format: uuid + - name: server_id + in: query + required: false + schema: + type: string + - name: datacenter + in: query + required: false + schema: + type: string + - name: pool + in: query + required: false + schema: + $ref: '#/components/schemas/AdminClustersPoolType' + - name: public_ip + in: query + required: false + schema: + type: string + responses: + '200': + description: '' + content: + application/json: + schema: + $ref: '#/components/schemas/AdminClustersListServersResponse' + '400': + description: '' + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorBody' + '403': + description: '' + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorBody' + '404': + description: '' + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorBody' + '408': + description: '' + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorBody' + '429': + description: '' + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorBody' + '500': + description: '' + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorBody' + security: *ref_0 + /admin/clusters/{cluster_id}/servers/prune: + post: + operationId: admin_clusters_servers_prune + tags: + - AdminClustersServers + parameters: + - name: cluster_id + in: path + required: true + schema: + type: string + format: uuid + - name: server_id + in: query + required: false + schema: + type: string + - name: datacenter + in: query + required: false + schema: + type: string + - name: pool + in: query + required: false + schema: + $ref: '#/components/schemas/AdminClustersPoolType' + - name: public_ip + in: query + required: false + schema: + type: string + responses: + '204': + description: '' + '400': + description: '' + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorBody' + '403': + description: '' + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorBody' + '404': + description: '' + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorBody' + '408': + description: '' + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorBody' + '429': + description: '' + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorBody' + '500': + description: '' + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorBody' + security: *ref_0 /auth/identity/access-token/complete-verification: post: description: Completes the access token verification process. @@ -11002,14 +11150,14 @@ components: $ref: '#/components/schemas/AdminClustersProvider' provider_datacenter_id: type: string - provider_api_token: - type: string pools: type: array items: $ref: '#/components/schemas/AdminClustersPool' build_delivery_method: $ref: '#/components/schemas/AdminClustersBuildDeliveryMethod' + prebakes_enabled: + type: boolean required: - datacenter_id - cluster_id @@ -11019,16 +11167,24 @@ components: - provider_datacenter_id - pools - build_delivery_method + - prebakes_enabled AdminClustersServer: type: object properties: server_id: type: string format: uuid + datacenter_id: + type: string + format: uuid + pool_type: + $ref: '#/components/schemas/AdminClustersPoolType' public_ip: type: string required: - server_id + - datacenter_id + - pool_type AdminClustersPoolUpdate: type: object properties: diff --git a/sdks/full/openapi_compat/openapi.yml b/sdks/full/openapi_compat/openapi.yml index bd725fd73e..aaa67cca65 100644 --- a/sdks/full/openapi_compat/openapi.yml +++ b/sdks/full/openapi_compat/openapi.yml @@ -91,10 +91,10 @@ components: items: $ref: '#/components/schemas/AdminClustersPool' type: array + prebakes_enabled: + type: boolean provider: $ref: '#/components/schemas/AdminClustersProvider' - provider_api_token: - type: string provider_datacenter_id: type: string required: @@ -106,6 +106,7 @@ components: - provider_datacenter_id - pools - build_delivery_method + - prebakes_enabled type: object AdminClustersHardware: properties: @@ -199,6 +200,11 @@ components: type: string AdminClustersServer: properties: + datacenter_id: + format: uuid + type: string + pool_type: + $ref: '#/components/schemas/AdminClustersPoolType' public_ip: type: string server_id: @@ -206,6 +212,8 @@ components: type: string required: - server_id + - datacenter_id + - pool_type type: object AdminClustersUpdateDatacenterRequest: properties: @@ -5291,6 +5299,154 @@ paths: security: *id001 tags: - AdminClustersServers + /admin/clusters/{cluster_id}/servers/lost: + get: + operationId: admin_clusters_servers_listLost + parameters: + - in: path + name: cluster_id + required: true + schema: + format: uuid + type: string + - in: query + name: server_id + required: false + schema: + type: string + - in: query + name: datacenter + required: false + schema: + type: string + - in: query + name: pool + required: false + schema: + $ref: '#/components/schemas/AdminClustersPoolType' + - in: query + name: public_ip + required: false + schema: + type: string + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/AdminClustersListServersResponse' + description: '' + '400': + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorBody' + description: '' + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorBody' + description: '' + '404': + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorBody' + description: '' + '408': + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorBody' + description: '' + '429': + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorBody' + description: '' + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorBody' + description: '' + security: *id001 + tags: + - AdminClustersServers + /admin/clusters/{cluster_id}/servers/prune: + post: + operationId: admin_clusters_servers_prune + parameters: + - in: path + name: cluster_id + required: true + schema: + format: uuid + type: string + - in: query + name: server_id + required: false + schema: + type: string + - in: query + name: datacenter + required: false + schema: + type: string + - in: query + name: pool + required: false + schema: + $ref: '#/components/schemas/AdminClustersPoolType' + - in: query + name: public_ip + required: false + schema: + type: string + responses: + '204': + description: '' + '400': + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorBody' + description: '' + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorBody' + description: '' + '404': + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorBody' + description: '' + '408': + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorBody' + description: '' + '429': + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorBody' + description: '' + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorBody' + description: '' + security: *id001 + tags: + - AdminClustersServers /admin/clusters/{cluster_id}/servers/taint: post: operationId: admin_clusters_servers_taint diff --git a/sdks/full/rust-cli/README.md b/sdks/full/rust-cli/README.md index 0d13cb305d..ffe8ca964f 100644 --- a/sdks/full/rust-cli/README.md +++ b/sdks/full/rust-cli/README.md @@ -33,6 +33,8 @@ Class | Method | HTTP request | Description *AdminClustersDatacentersApi* | [**admin_clusters_datacenters_update**](docs/AdminClustersDatacentersApi.md#admin_clusters_datacenters_update) | **PATCH** /admin/clusters/{cluster_id}/datacenters/{datacenter_id} | *AdminClustersServersApi* | [**admin_clusters_servers_destroy**](docs/AdminClustersServersApi.md#admin_clusters_servers_destroy) | **POST** /admin/clusters/{cluster_id}/servers/destroy | *AdminClustersServersApi* | [**admin_clusters_servers_list**](docs/AdminClustersServersApi.md#admin_clusters_servers_list) | **GET** /admin/clusters/{cluster_id}/servers | +*AdminClustersServersApi* | [**admin_clusters_servers_list_lost**](docs/AdminClustersServersApi.md#admin_clusters_servers_list_lost) | **GET** /admin/clusters/{cluster_id}/servers/lost | +*AdminClustersServersApi* | [**admin_clusters_servers_prune**](docs/AdminClustersServersApi.md#admin_clusters_servers_prune) | **POST** /admin/clusters/{cluster_id}/servers/prune | *AdminClustersServersApi* | [**admin_clusters_servers_taint**](docs/AdminClustersServersApi.md#admin_clusters_servers_taint) | **POST** /admin/clusters/{cluster_id}/servers/taint | *AuthIdentityAccessTokenApi* | [**auth_identity_access_token_complete_access_token_verification**](docs/AuthIdentityAccessTokenApi.md#auth_identity_access_token_complete_access_token_verification) | **POST** /auth/identity/access-token/complete-verification | *AuthIdentityEmailApi* | [**auth_identity_email_complete_email_verification**](docs/AuthIdentityEmailApi.md#auth_identity_email_complete_email_verification) | **POST** /auth/identity/email/complete-verification | diff --git a/sdks/full/rust-cli/docs/AdminClustersDatacenter.md b/sdks/full/rust-cli/docs/AdminClustersDatacenter.md index bd81008321..8b01e2f780 100644 --- a/sdks/full/rust-cli/docs/AdminClustersDatacenter.md +++ b/sdks/full/rust-cli/docs/AdminClustersDatacenter.md @@ -10,8 +10,8 @@ Name | Type | Description | Notes **display_name** | **String** | | **name_id** | **String** | | **pools** | [**Vec**](AdminClustersPool.md) | | +**prebakes_enabled** | **bool** | | **provider** | [**crate::models::AdminClustersProvider**](AdminClustersProvider.md) | | -**provider_api_token** | Option<**String**> | | [optional] **provider_datacenter_id** | **String** | | [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/sdks/full/rust-cli/docs/AdminClustersServer.md b/sdks/full/rust-cli/docs/AdminClustersServer.md index 08f7aa7f98..760a87241a 100644 --- a/sdks/full/rust-cli/docs/AdminClustersServer.md +++ b/sdks/full/rust-cli/docs/AdminClustersServer.md @@ -4,6 +4,8 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- +**datacenter_id** | [**uuid::Uuid**](uuid::Uuid.md) | | +**pool_type** | [**crate::models::AdminClustersPoolType**](AdminClustersPoolType.md) | | **public_ip** | Option<**String**> | | [optional] **server_id** | [**uuid::Uuid**](uuid::Uuid.md) | | diff --git a/sdks/full/rust-cli/docs/AdminClustersServersApi.md b/sdks/full/rust-cli/docs/AdminClustersServersApi.md index 78a82f9172..f422c45423 100644 --- a/sdks/full/rust-cli/docs/AdminClustersServersApi.md +++ b/sdks/full/rust-cli/docs/AdminClustersServersApi.md @@ -6,6 +6,8 @@ Method | HTTP request | Description ------------- | ------------- | ------------- [**admin_clusters_servers_destroy**](AdminClustersServersApi.md#admin_clusters_servers_destroy) | **POST** /admin/clusters/{cluster_id}/servers/destroy | [**admin_clusters_servers_list**](AdminClustersServersApi.md#admin_clusters_servers_list) | **GET** /admin/clusters/{cluster_id}/servers | +[**admin_clusters_servers_list_lost**](AdminClustersServersApi.md#admin_clusters_servers_list_lost) | **GET** /admin/clusters/{cluster_id}/servers/lost | +[**admin_clusters_servers_prune**](AdminClustersServersApi.md#admin_clusters_servers_prune) | **POST** /admin/clusters/{cluster_id}/servers/prune | [**admin_clusters_servers_taint**](AdminClustersServersApi.md#admin_clusters_servers_taint) | **POST** /admin/clusters/{cluster_id}/servers/taint | @@ -74,6 +76,70 @@ Name | Type | Description | Required | Notes [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) +## admin_clusters_servers_list_lost + +> crate::models::AdminClustersListServersResponse admin_clusters_servers_list_lost(cluster_id, server_id, datacenter, pool, public_ip) + + +### Parameters + + +Name | Type | Description | Required | Notes +------------- | ------------- | ------------- | ------------- | ------------- +**cluster_id** | **uuid::Uuid** | | [required] | +**server_id** | Option<**String**> | | | +**datacenter** | Option<**String**> | | | +**pool** | Option<[**AdminClustersPoolType**](.md)> | | | +**public_ip** | Option<**String**> | | | + +### Return type + +[**crate::models::AdminClustersListServersResponse**](AdminClustersListServersResponse.md) + +### Authorization + +[BearerAuth](../README.md#BearerAuth) + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + + +## admin_clusters_servers_prune + +> admin_clusters_servers_prune(cluster_id, server_id, datacenter, pool, public_ip) + + +### Parameters + + +Name | Type | Description | Required | Notes +------------- | ------------- | ------------- | ------------- | ------------- +**cluster_id** | **uuid::Uuid** | | [required] | +**server_id** | Option<**String**> | | | +**datacenter** | Option<**String**> | | | +**pool** | Option<[**AdminClustersPoolType**](.md)> | | | +**public_ip** | Option<**String**> | | | + +### Return type + + (empty response body) + +### Authorization + +[BearerAuth](../README.md#BearerAuth) + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + + ## admin_clusters_servers_taint > admin_clusters_servers_taint(cluster_id, server_id, datacenter, pool, public_ip) diff --git a/sdks/full/rust-cli/src/apis/admin_clusters_servers_api.rs b/sdks/full/rust-cli/src/apis/admin_clusters_servers_api.rs index 1bf403175b..f8e05246aa 100644 --- a/sdks/full/rust-cli/src/apis/admin_clusters_servers_api.rs +++ b/sdks/full/rust-cli/src/apis/admin_clusters_servers_api.rs @@ -41,6 +41,32 @@ pub enum AdminClustersServersListError { UnknownValue(serde_json::Value), } +/// struct for typed errors of method [`admin_clusters_servers_list_lost`] +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum AdminClustersServersListLostError { + Status400(crate::models::ErrorBody), + Status403(crate::models::ErrorBody), + Status404(crate::models::ErrorBody), + Status408(crate::models::ErrorBody), + Status429(crate::models::ErrorBody), + Status500(crate::models::ErrorBody), + UnknownValue(serde_json::Value), +} + +/// struct for typed errors of method [`admin_clusters_servers_prune`] +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum AdminClustersServersPruneError { + Status400(crate::models::ErrorBody), + Status403(crate::models::ErrorBody), + Status404(crate::models::ErrorBody), + Status408(crate::models::ErrorBody), + Status429(crate::models::ErrorBody), + Status500(crate::models::ErrorBody), + UnknownValue(serde_json::Value), +} + /// struct for typed errors of method [`admin_clusters_servers_taint`] #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(untagged)] @@ -139,6 +165,90 @@ pub async fn admin_clusters_servers_list(configuration: &configuration::Configur } } +pub async fn admin_clusters_servers_list_lost(configuration: &configuration::Configuration, cluster_id: &str, server_id: Option<&str>, datacenter: Option<&str>, pool: Option, public_ip: Option<&str>) -> Result> { + let local_var_configuration = configuration; + + let local_var_client = &local_var_configuration.client; + + let local_var_uri_str = format!("{}/admin/clusters/{cluster_id}/servers/lost", local_var_configuration.base_path, cluster_id=crate::apis::urlencode(cluster_id)); + let mut local_var_req_builder = local_var_client.request(reqwest::Method::GET, local_var_uri_str.as_str()); + + if let Some(ref local_var_str) = server_id { + local_var_req_builder = local_var_req_builder.query(&[("server_id", &local_var_str.to_string())]); + } + if let Some(ref local_var_str) = datacenter { + local_var_req_builder = local_var_req_builder.query(&[("datacenter", &local_var_str.to_string())]); + } + if let Some(ref local_var_str) = pool { + local_var_req_builder = local_var_req_builder.query(&[("pool", &local_var_str.to_string())]); + } + if let Some(ref local_var_str) = public_ip { + local_var_req_builder = local_var_req_builder.query(&[("public_ip", &local_var_str.to_string())]); + } + if let Some(ref local_var_user_agent) = local_var_configuration.user_agent { + local_var_req_builder = local_var_req_builder.header(reqwest::header::USER_AGENT, local_var_user_agent.clone()); + } + if let Some(ref local_var_token) = local_var_configuration.bearer_access_token { + local_var_req_builder = local_var_req_builder.bearer_auth(local_var_token.to_owned()); + }; + + let local_var_req = local_var_req_builder.build()?; + let local_var_resp = local_var_client.execute(local_var_req).await?; + + let local_var_status = local_var_resp.status(); + let local_var_content = local_var_resp.text().await?; + + if !local_var_status.is_client_error() && !local_var_status.is_server_error() { + serde_json::from_str(&local_var_content).map_err(Error::from) + } else { + let local_var_entity: Option = serde_json::from_str(&local_var_content).ok(); + let local_var_error = ResponseContent { status: local_var_status, content: local_var_content, entity: local_var_entity }; + Err(Error::ResponseError(local_var_error)) + } +} + +pub async fn admin_clusters_servers_prune(configuration: &configuration::Configuration, cluster_id: &str, server_id: Option<&str>, datacenter: Option<&str>, pool: Option, public_ip: Option<&str>) -> Result<(), Error> { + let local_var_configuration = configuration; + + let local_var_client = &local_var_configuration.client; + + let local_var_uri_str = format!("{}/admin/clusters/{cluster_id}/servers/prune", local_var_configuration.base_path, cluster_id=crate::apis::urlencode(cluster_id)); + let mut local_var_req_builder = local_var_client.request(reqwest::Method::POST, local_var_uri_str.as_str()); + + if let Some(ref local_var_str) = server_id { + local_var_req_builder = local_var_req_builder.query(&[("server_id", &local_var_str.to_string())]); + } + if let Some(ref local_var_str) = datacenter { + local_var_req_builder = local_var_req_builder.query(&[("datacenter", &local_var_str.to_string())]); + } + if let Some(ref local_var_str) = pool { + local_var_req_builder = local_var_req_builder.query(&[("pool", &local_var_str.to_string())]); + } + if let Some(ref local_var_str) = public_ip { + local_var_req_builder = local_var_req_builder.query(&[("public_ip", &local_var_str.to_string())]); + } + if let Some(ref local_var_user_agent) = local_var_configuration.user_agent { + local_var_req_builder = local_var_req_builder.header(reqwest::header::USER_AGENT, local_var_user_agent.clone()); + } + if let Some(ref local_var_token) = local_var_configuration.bearer_access_token { + local_var_req_builder = local_var_req_builder.bearer_auth(local_var_token.to_owned()); + }; + + let local_var_req = local_var_req_builder.build()?; + let local_var_resp = local_var_client.execute(local_var_req).await?; + + let local_var_status = local_var_resp.status(); + let local_var_content = local_var_resp.text().await?; + + if !local_var_status.is_client_error() && !local_var_status.is_server_error() { + Ok(()) + } else { + let local_var_entity: Option = serde_json::from_str(&local_var_content).ok(); + let local_var_error = ResponseContent { status: local_var_status, content: local_var_content, entity: local_var_entity }; + Err(Error::ResponseError(local_var_error)) + } +} + pub async fn admin_clusters_servers_taint(configuration: &configuration::Configuration, cluster_id: &str, server_id: Option<&str>, datacenter: Option<&str>, pool: Option, public_ip: Option<&str>) -> Result<(), Error> { let local_var_configuration = configuration; diff --git a/sdks/full/rust-cli/src/models/admin_clusters_datacenter.rs b/sdks/full/rust-cli/src/models/admin_clusters_datacenter.rs index 80318b2271..55603b0cfb 100644 --- a/sdks/full/rust-cli/src/models/admin_clusters_datacenter.rs +++ b/sdks/full/rust-cli/src/models/admin_clusters_datacenter.rs @@ -25,16 +25,16 @@ pub struct AdminClustersDatacenter { pub name_id: String, #[serde(rename = "pools")] pub pools: Vec, + #[serde(rename = "prebakes_enabled")] + pub prebakes_enabled: bool, #[serde(rename = "provider")] pub provider: crate::models::AdminClustersProvider, - #[serde(rename = "provider_api_token", skip_serializing_if = "Option::is_none")] - pub provider_api_token: Option, #[serde(rename = "provider_datacenter_id")] pub provider_datacenter_id: String, } impl AdminClustersDatacenter { - pub fn new(build_delivery_method: crate::models::AdminClustersBuildDeliveryMethod, cluster_id: uuid::Uuid, datacenter_id: uuid::Uuid, display_name: String, name_id: String, pools: Vec, provider: crate::models::AdminClustersProvider, provider_datacenter_id: String) -> AdminClustersDatacenter { + pub fn new(build_delivery_method: crate::models::AdminClustersBuildDeliveryMethod, cluster_id: uuid::Uuid, datacenter_id: uuid::Uuid, display_name: String, name_id: String, pools: Vec, prebakes_enabled: bool, provider: crate::models::AdminClustersProvider, provider_datacenter_id: String) -> AdminClustersDatacenter { AdminClustersDatacenter { build_delivery_method, cluster_id, @@ -42,8 +42,8 @@ impl AdminClustersDatacenter { display_name, name_id, pools, + prebakes_enabled, provider, - provider_api_token: None, provider_datacenter_id, } } diff --git a/sdks/full/rust-cli/src/models/admin_clusters_server.rs b/sdks/full/rust-cli/src/models/admin_clusters_server.rs index c1d6061f00..6c74f8f524 100644 --- a/sdks/full/rust-cli/src/models/admin_clusters_server.rs +++ b/sdks/full/rust-cli/src/models/admin_clusters_server.rs @@ -13,6 +13,10 @@ #[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] pub struct AdminClustersServer { + #[serde(rename = "datacenter_id")] + pub datacenter_id: uuid::Uuid, + #[serde(rename = "pool_type")] + pub pool_type: crate::models::AdminClustersPoolType, #[serde(rename = "public_ip", skip_serializing_if = "Option::is_none")] pub public_ip: Option, #[serde(rename = "server_id")] @@ -20,8 +24,10 @@ pub struct AdminClustersServer { } impl AdminClustersServer { - pub fn new(server_id: uuid::Uuid) -> AdminClustersServer { + pub fn new(datacenter_id: uuid::Uuid, pool_type: crate::models::AdminClustersPoolType, server_id: uuid::Uuid) -> AdminClustersServer { AdminClustersServer { + datacenter_id, + pool_type, public_ip: None, server_id, } diff --git a/sdks/full/rust/README.md b/sdks/full/rust/README.md index 0d13cb305d..ffe8ca964f 100644 --- a/sdks/full/rust/README.md +++ b/sdks/full/rust/README.md @@ -33,6 +33,8 @@ Class | Method | HTTP request | Description *AdminClustersDatacentersApi* | [**admin_clusters_datacenters_update**](docs/AdminClustersDatacentersApi.md#admin_clusters_datacenters_update) | **PATCH** /admin/clusters/{cluster_id}/datacenters/{datacenter_id} | *AdminClustersServersApi* | [**admin_clusters_servers_destroy**](docs/AdminClustersServersApi.md#admin_clusters_servers_destroy) | **POST** /admin/clusters/{cluster_id}/servers/destroy | *AdminClustersServersApi* | [**admin_clusters_servers_list**](docs/AdminClustersServersApi.md#admin_clusters_servers_list) | **GET** /admin/clusters/{cluster_id}/servers | +*AdminClustersServersApi* | [**admin_clusters_servers_list_lost**](docs/AdminClustersServersApi.md#admin_clusters_servers_list_lost) | **GET** /admin/clusters/{cluster_id}/servers/lost | +*AdminClustersServersApi* | [**admin_clusters_servers_prune**](docs/AdminClustersServersApi.md#admin_clusters_servers_prune) | **POST** /admin/clusters/{cluster_id}/servers/prune | *AdminClustersServersApi* | [**admin_clusters_servers_taint**](docs/AdminClustersServersApi.md#admin_clusters_servers_taint) | **POST** /admin/clusters/{cluster_id}/servers/taint | *AuthIdentityAccessTokenApi* | [**auth_identity_access_token_complete_access_token_verification**](docs/AuthIdentityAccessTokenApi.md#auth_identity_access_token_complete_access_token_verification) | **POST** /auth/identity/access-token/complete-verification | *AuthIdentityEmailApi* | [**auth_identity_email_complete_email_verification**](docs/AuthIdentityEmailApi.md#auth_identity_email_complete_email_verification) | **POST** /auth/identity/email/complete-verification | diff --git a/sdks/full/rust/docs/AdminClustersDatacenter.md b/sdks/full/rust/docs/AdminClustersDatacenter.md index bd81008321..8b01e2f780 100644 --- a/sdks/full/rust/docs/AdminClustersDatacenter.md +++ b/sdks/full/rust/docs/AdminClustersDatacenter.md @@ -10,8 +10,8 @@ Name | Type | Description | Notes **display_name** | **String** | | **name_id** | **String** | | **pools** | [**Vec**](AdminClustersPool.md) | | +**prebakes_enabled** | **bool** | | **provider** | [**crate::models::AdminClustersProvider**](AdminClustersProvider.md) | | -**provider_api_token** | Option<**String**> | | [optional] **provider_datacenter_id** | **String** | | [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/sdks/full/rust/docs/AdminClustersServer.md b/sdks/full/rust/docs/AdminClustersServer.md index 08f7aa7f98..760a87241a 100644 --- a/sdks/full/rust/docs/AdminClustersServer.md +++ b/sdks/full/rust/docs/AdminClustersServer.md @@ -4,6 +4,8 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- +**datacenter_id** | [**uuid::Uuid**](uuid::Uuid.md) | | +**pool_type** | [**crate::models::AdminClustersPoolType**](AdminClustersPoolType.md) | | **public_ip** | Option<**String**> | | [optional] **server_id** | [**uuid::Uuid**](uuid::Uuid.md) | | diff --git a/sdks/full/rust/docs/AdminClustersServersApi.md b/sdks/full/rust/docs/AdminClustersServersApi.md index 78a82f9172..f422c45423 100644 --- a/sdks/full/rust/docs/AdminClustersServersApi.md +++ b/sdks/full/rust/docs/AdminClustersServersApi.md @@ -6,6 +6,8 @@ Method | HTTP request | Description ------------- | ------------- | ------------- [**admin_clusters_servers_destroy**](AdminClustersServersApi.md#admin_clusters_servers_destroy) | **POST** /admin/clusters/{cluster_id}/servers/destroy | [**admin_clusters_servers_list**](AdminClustersServersApi.md#admin_clusters_servers_list) | **GET** /admin/clusters/{cluster_id}/servers | +[**admin_clusters_servers_list_lost**](AdminClustersServersApi.md#admin_clusters_servers_list_lost) | **GET** /admin/clusters/{cluster_id}/servers/lost | +[**admin_clusters_servers_prune**](AdminClustersServersApi.md#admin_clusters_servers_prune) | **POST** /admin/clusters/{cluster_id}/servers/prune | [**admin_clusters_servers_taint**](AdminClustersServersApi.md#admin_clusters_servers_taint) | **POST** /admin/clusters/{cluster_id}/servers/taint | @@ -74,6 +76,70 @@ Name | Type | Description | Required | Notes [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) +## admin_clusters_servers_list_lost + +> crate::models::AdminClustersListServersResponse admin_clusters_servers_list_lost(cluster_id, server_id, datacenter, pool, public_ip) + + +### Parameters + + +Name | Type | Description | Required | Notes +------------- | ------------- | ------------- | ------------- | ------------- +**cluster_id** | **uuid::Uuid** | | [required] | +**server_id** | Option<**String**> | | | +**datacenter** | Option<**String**> | | | +**pool** | Option<[**AdminClustersPoolType**](.md)> | | | +**public_ip** | Option<**String**> | | | + +### Return type + +[**crate::models::AdminClustersListServersResponse**](AdminClustersListServersResponse.md) + +### Authorization + +[BearerAuth](../README.md#BearerAuth) + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + + +## admin_clusters_servers_prune + +> admin_clusters_servers_prune(cluster_id, server_id, datacenter, pool, public_ip) + + +### Parameters + + +Name | Type | Description | Required | Notes +------------- | ------------- | ------------- | ------------- | ------------- +**cluster_id** | **uuid::Uuid** | | [required] | +**server_id** | Option<**String**> | | | +**datacenter** | Option<**String**> | | | +**pool** | Option<[**AdminClustersPoolType**](.md)> | | | +**public_ip** | Option<**String**> | | | + +### Return type + + (empty response body) + +### Authorization + +[BearerAuth](../README.md#BearerAuth) + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + + ## admin_clusters_servers_taint > admin_clusters_servers_taint(cluster_id, server_id, datacenter, pool, public_ip) diff --git a/sdks/full/rust/src/apis/admin_clusters_servers_api.rs b/sdks/full/rust/src/apis/admin_clusters_servers_api.rs index 1bf403175b..f8e05246aa 100644 --- a/sdks/full/rust/src/apis/admin_clusters_servers_api.rs +++ b/sdks/full/rust/src/apis/admin_clusters_servers_api.rs @@ -41,6 +41,32 @@ pub enum AdminClustersServersListError { UnknownValue(serde_json::Value), } +/// struct for typed errors of method [`admin_clusters_servers_list_lost`] +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum AdminClustersServersListLostError { + Status400(crate::models::ErrorBody), + Status403(crate::models::ErrorBody), + Status404(crate::models::ErrorBody), + Status408(crate::models::ErrorBody), + Status429(crate::models::ErrorBody), + Status500(crate::models::ErrorBody), + UnknownValue(serde_json::Value), +} + +/// struct for typed errors of method [`admin_clusters_servers_prune`] +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum AdminClustersServersPruneError { + Status400(crate::models::ErrorBody), + Status403(crate::models::ErrorBody), + Status404(crate::models::ErrorBody), + Status408(crate::models::ErrorBody), + Status429(crate::models::ErrorBody), + Status500(crate::models::ErrorBody), + UnknownValue(serde_json::Value), +} + /// struct for typed errors of method [`admin_clusters_servers_taint`] #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(untagged)] @@ -139,6 +165,90 @@ pub async fn admin_clusters_servers_list(configuration: &configuration::Configur } } +pub async fn admin_clusters_servers_list_lost(configuration: &configuration::Configuration, cluster_id: &str, server_id: Option<&str>, datacenter: Option<&str>, pool: Option, public_ip: Option<&str>) -> Result> { + let local_var_configuration = configuration; + + let local_var_client = &local_var_configuration.client; + + let local_var_uri_str = format!("{}/admin/clusters/{cluster_id}/servers/lost", local_var_configuration.base_path, cluster_id=crate::apis::urlencode(cluster_id)); + let mut local_var_req_builder = local_var_client.request(reqwest::Method::GET, local_var_uri_str.as_str()); + + if let Some(ref local_var_str) = server_id { + local_var_req_builder = local_var_req_builder.query(&[("server_id", &local_var_str.to_string())]); + } + if let Some(ref local_var_str) = datacenter { + local_var_req_builder = local_var_req_builder.query(&[("datacenter", &local_var_str.to_string())]); + } + if let Some(ref local_var_str) = pool { + local_var_req_builder = local_var_req_builder.query(&[("pool", &local_var_str.to_string())]); + } + if let Some(ref local_var_str) = public_ip { + local_var_req_builder = local_var_req_builder.query(&[("public_ip", &local_var_str.to_string())]); + } + if let Some(ref local_var_user_agent) = local_var_configuration.user_agent { + local_var_req_builder = local_var_req_builder.header(reqwest::header::USER_AGENT, local_var_user_agent.clone()); + } + if let Some(ref local_var_token) = local_var_configuration.bearer_access_token { + local_var_req_builder = local_var_req_builder.bearer_auth(local_var_token.to_owned()); + }; + + let local_var_req = local_var_req_builder.build()?; + let local_var_resp = local_var_client.execute(local_var_req).await?; + + let local_var_status = local_var_resp.status(); + let local_var_content = local_var_resp.text().await?; + + if !local_var_status.is_client_error() && !local_var_status.is_server_error() { + serde_json::from_str(&local_var_content).map_err(Error::from) + } else { + let local_var_entity: Option = serde_json::from_str(&local_var_content).ok(); + let local_var_error = ResponseContent { status: local_var_status, content: local_var_content, entity: local_var_entity }; + Err(Error::ResponseError(local_var_error)) + } +} + +pub async fn admin_clusters_servers_prune(configuration: &configuration::Configuration, cluster_id: &str, server_id: Option<&str>, datacenter: Option<&str>, pool: Option, public_ip: Option<&str>) -> Result<(), Error> { + let local_var_configuration = configuration; + + let local_var_client = &local_var_configuration.client; + + let local_var_uri_str = format!("{}/admin/clusters/{cluster_id}/servers/prune", local_var_configuration.base_path, cluster_id=crate::apis::urlencode(cluster_id)); + let mut local_var_req_builder = local_var_client.request(reqwest::Method::POST, local_var_uri_str.as_str()); + + if let Some(ref local_var_str) = server_id { + local_var_req_builder = local_var_req_builder.query(&[("server_id", &local_var_str.to_string())]); + } + if let Some(ref local_var_str) = datacenter { + local_var_req_builder = local_var_req_builder.query(&[("datacenter", &local_var_str.to_string())]); + } + if let Some(ref local_var_str) = pool { + local_var_req_builder = local_var_req_builder.query(&[("pool", &local_var_str.to_string())]); + } + if let Some(ref local_var_str) = public_ip { + local_var_req_builder = local_var_req_builder.query(&[("public_ip", &local_var_str.to_string())]); + } + if let Some(ref local_var_user_agent) = local_var_configuration.user_agent { + local_var_req_builder = local_var_req_builder.header(reqwest::header::USER_AGENT, local_var_user_agent.clone()); + } + if let Some(ref local_var_token) = local_var_configuration.bearer_access_token { + local_var_req_builder = local_var_req_builder.bearer_auth(local_var_token.to_owned()); + }; + + let local_var_req = local_var_req_builder.build()?; + let local_var_resp = local_var_client.execute(local_var_req).await?; + + let local_var_status = local_var_resp.status(); + let local_var_content = local_var_resp.text().await?; + + if !local_var_status.is_client_error() && !local_var_status.is_server_error() { + Ok(()) + } else { + let local_var_entity: Option = serde_json::from_str(&local_var_content).ok(); + let local_var_error = ResponseContent { status: local_var_status, content: local_var_content, entity: local_var_entity }; + Err(Error::ResponseError(local_var_error)) + } +} + pub async fn admin_clusters_servers_taint(configuration: &configuration::Configuration, cluster_id: &str, server_id: Option<&str>, datacenter: Option<&str>, pool: Option, public_ip: Option<&str>) -> Result<(), Error> { let local_var_configuration = configuration; diff --git a/sdks/full/rust/src/models/admin_clusters_datacenter.rs b/sdks/full/rust/src/models/admin_clusters_datacenter.rs index 80318b2271..55603b0cfb 100644 --- a/sdks/full/rust/src/models/admin_clusters_datacenter.rs +++ b/sdks/full/rust/src/models/admin_clusters_datacenter.rs @@ -25,16 +25,16 @@ pub struct AdminClustersDatacenter { pub name_id: String, #[serde(rename = "pools")] pub pools: Vec, + #[serde(rename = "prebakes_enabled")] + pub prebakes_enabled: bool, #[serde(rename = "provider")] pub provider: crate::models::AdminClustersProvider, - #[serde(rename = "provider_api_token", skip_serializing_if = "Option::is_none")] - pub provider_api_token: Option, #[serde(rename = "provider_datacenter_id")] pub provider_datacenter_id: String, } impl AdminClustersDatacenter { - pub fn new(build_delivery_method: crate::models::AdminClustersBuildDeliveryMethod, cluster_id: uuid::Uuid, datacenter_id: uuid::Uuid, display_name: String, name_id: String, pools: Vec, provider: crate::models::AdminClustersProvider, provider_datacenter_id: String) -> AdminClustersDatacenter { + pub fn new(build_delivery_method: crate::models::AdminClustersBuildDeliveryMethod, cluster_id: uuid::Uuid, datacenter_id: uuid::Uuid, display_name: String, name_id: String, pools: Vec, prebakes_enabled: bool, provider: crate::models::AdminClustersProvider, provider_datacenter_id: String) -> AdminClustersDatacenter { AdminClustersDatacenter { build_delivery_method, cluster_id, @@ -42,8 +42,8 @@ impl AdminClustersDatacenter { display_name, name_id, pools, + prebakes_enabled, provider, - provider_api_token: None, provider_datacenter_id, } } diff --git a/sdks/full/rust/src/models/admin_clusters_server.rs b/sdks/full/rust/src/models/admin_clusters_server.rs index c1d6061f00..6c74f8f524 100644 --- a/sdks/full/rust/src/models/admin_clusters_server.rs +++ b/sdks/full/rust/src/models/admin_clusters_server.rs @@ -13,6 +13,10 @@ #[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] pub struct AdminClustersServer { + #[serde(rename = "datacenter_id")] + pub datacenter_id: uuid::Uuid, + #[serde(rename = "pool_type")] + pub pool_type: crate::models::AdminClustersPoolType, #[serde(rename = "public_ip", skip_serializing_if = "Option::is_none")] pub public_ip: Option, #[serde(rename = "server_id")] @@ -20,8 +24,10 @@ pub struct AdminClustersServer { } impl AdminClustersServer { - pub fn new(server_id: uuid::Uuid) -> AdminClustersServer { + pub fn new(datacenter_id: uuid::Uuid, pool_type: crate::models::AdminClustersPoolType, server_id: uuid::Uuid) -> AdminClustersServer { AdminClustersServer { + datacenter_id, + pool_type, public_ip: None, server_id, } diff --git a/sdks/full/typescript/archive.tgz b/sdks/full/typescript/archive.tgz index 36fc4081c9..1049378c7c 100644 --- a/sdks/full/typescript/archive.tgz +++ b/sdks/full/typescript/archive.tgz @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:794ed14a6929341ffe70d362a5cb704a6681bac3ca2ad4685e1b72a7cf1b92a5 -size 550058 +oid sha256:e70ecd98fdc0a55c5837f78ea443c123cb26350b3116d8fef271bdd3c3440e9d +size 543786 diff --git a/sdks/full/typescript/src/api/resources/admin/resources/clusters/resources/servers/client/Client.ts b/sdks/full/typescript/src/api/resources/admin/resources/clusters/resources/servers/client/Client.ts index fe1abe7892..733cce18a9 100644 --- a/sdks/full/typescript/src/api/resources/admin/resources/clusters/resources/servers/client/Client.ts +++ b/sdks/full/typescript/src/api/resources/admin/resources/clusters/resources/servers/client/Client.ts @@ -479,6 +479,308 @@ export class Servers { } } + /** + * @param {string} clusterId + * @param {Rivet.admin.clusters.ListLostServersRequest} request + * @param {Servers.RequestOptions} requestOptions - Request-specific configuration. + * + * @throws {@link Rivet.InternalError} + * @throws {@link Rivet.RateLimitError} + * @throws {@link Rivet.ForbiddenError} + * @throws {@link Rivet.UnauthorizedError} + * @throws {@link Rivet.NotFoundError} + * @throws {@link Rivet.BadRequestError} + * + * @example + * await client.admin.clusters.servers.listLost("d5e9c84f-c2b2-4bf4-b4b0-7ffd7a9ffc32", { + * serverId: "string", + * datacenter: "string", + * pool: Rivet.admin.clusters.PoolType.Job, + * publicIp: "string" + * }) + */ + public async listLost( + clusterId: string, + request: Rivet.admin.clusters.ListLostServersRequest = {}, + requestOptions?: Servers.RequestOptions + ): Promise { + const { serverId, datacenter, pool, publicIp } = request; + const _queryParams: Record = {}; + if (serverId != null) { + _queryParams["server_id"] = serverId; + } + + if (datacenter != null) { + _queryParams["datacenter"] = datacenter; + } + + if (pool != null) { + _queryParams["pool"] = pool; + } + + if (publicIp != null) { + _queryParams["public_ip"] = publicIp; + } + + const _response = await (this._options.fetcher ?? core.fetcher)({ + url: urlJoin( + (await core.Supplier.get(this._options.environment)) ?? environments.RivetEnvironment.Production, + `/admin/clusters/${encodeURIComponent(clusterId)}/servers/lost` + ), + method: "GET", + headers: { + Authorization: await this._getAuthorizationHeader(), + }, + contentType: "application/json", + queryParameters: _queryParams, + requestType: "json", + timeoutMs: requestOptions?.timeoutInSeconds != null ? requestOptions.timeoutInSeconds * 1000 : 180000, + maxRetries: requestOptions?.maxRetries, + abortSignal: requestOptions?.abortSignal, + }); + if (_response.ok) { + return serializers.admin.clusters.ListServersResponse.parseOrThrow(_response.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }); + } + + if (_response.error.reason === "status-code") { + switch (_response.error.statusCode) { + case 500: + throw new Rivet.InternalError( + serializers.ErrorBody.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }) + ); + case 429: + throw new Rivet.RateLimitError( + serializers.ErrorBody.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }) + ); + case 403: + throw new Rivet.ForbiddenError( + serializers.ErrorBody.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }) + ); + case 408: + throw new Rivet.UnauthorizedError( + serializers.ErrorBody.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }) + ); + case 404: + throw new Rivet.NotFoundError( + serializers.ErrorBody.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }) + ); + case 400: + throw new Rivet.BadRequestError( + serializers.ErrorBody.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }) + ); + default: + throw new errors.RivetError({ + statusCode: _response.error.statusCode, + body: _response.error.body, + }); + } + } + + switch (_response.error.reason) { + case "non-json": + throw new errors.RivetError({ + statusCode: _response.error.statusCode, + body: _response.error.rawBody, + }); + case "timeout": + throw new errors.RivetTimeoutError(); + case "unknown": + throw new errors.RivetError({ + message: _response.error.errorMessage, + }); + } + } + + /** + * @param {string} clusterId + * @param {Rivet.admin.clusters.PruneServersRequest} request + * @param {Servers.RequestOptions} requestOptions - Request-specific configuration. + * + * @throws {@link Rivet.InternalError} + * @throws {@link Rivet.RateLimitError} + * @throws {@link Rivet.ForbiddenError} + * @throws {@link Rivet.UnauthorizedError} + * @throws {@link Rivet.NotFoundError} + * @throws {@link Rivet.BadRequestError} + * + * @example + * await client.admin.clusters.servers.prune("d5e9c84f-c2b2-4bf4-b4b0-7ffd7a9ffc32", { + * serverId: "string", + * datacenter: "string", + * pool: Rivet.admin.clusters.PoolType.Job, + * publicIp: "string" + * }) + */ + public async prune( + clusterId: string, + request: Rivet.admin.clusters.PruneServersRequest = {}, + requestOptions?: Servers.RequestOptions + ): Promise { + const { serverId, datacenter, pool, publicIp } = request; + const _queryParams: Record = {}; + if (serverId != null) { + _queryParams["server_id"] = serverId; + } + + if (datacenter != null) { + _queryParams["datacenter"] = datacenter; + } + + if (pool != null) { + _queryParams["pool"] = pool; + } + + if (publicIp != null) { + _queryParams["public_ip"] = publicIp; + } + + const _response = await (this._options.fetcher ?? core.fetcher)({ + url: urlJoin( + (await core.Supplier.get(this._options.environment)) ?? environments.RivetEnvironment.Production, + `/admin/clusters/${encodeURIComponent(clusterId)}/servers/prune` + ), + method: "POST", + headers: { + Authorization: await this._getAuthorizationHeader(), + }, + contentType: "application/json", + queryParameters: _queryParams, + requestType: "json", + timeoutMs: requestOptions?.timeoutInSeconds != null ? requestOptions.timeoutInSeconds * 1000 : 180000, + maxRetries: requestOptions?.maxRetries, + abortSignal: requestOptions?.abortSignal, + }); + if (_response.ok) { + return; + } + + if (_response.error.reason === "status-code") { + switch (_response.error.statusCode) { + case 500: + throw new Rivet.InternalError( + serializers.ErrorBody.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }) + ); + case 429: + throw new Rivet.RateLimitError( + serializers.ErrorBody.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }) + ); + case 403: + throw new Rivet.ForbiddenError( + serializers.ErrorBody.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }) + ); + case 408: + throw new Rivet.UnauthorizedError( + serializers.ErrorBody.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }) + ); + case 404: + throw new Rivet.NotFoundError( + serializers.ErrorBody.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }) + ); + case 400: + throw new Rivet.BadRequestError( + serializers.ErrorBody.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }) + ); + default: + throw new errors.RivetError({ + statusCode: _response.error.statusCode, + body: _response.error.body, + }); + } + } + + switch (_response.error.reason) { + case "non-json": + throw new errors.RivetError({ + statusCode: _response.error.statusCode, + body: _response.error.rawBody, + }); + case "timeout": + throw new errors.RivetTimeoutError(); + case "unknown": + throw new errors.RivetError({ + message: _response.error.errorMessage, + }); + } + } + protected async _getAuthorizationHeader(): Promise { const bearer = await core.Supplier.get(this._options.token); if (bearer != null) { diff --git a/sdks/full/typescript/src/api/resources/admin/resources/clusters/resources/servers/client/requests/ListLostServersRequest.ts b/sdks/full/typescript/src/api/resources/admin/resources/clusters/resources/servers/client/requests/ListLostServersRequest.ts new file mode 100644 index 0000000000..b5780d27ff --- /dev/null +++ b/sdks/full/typescript/src/api/resources/admin/resources/clusters/resources/servers/client/requests/ListLostServersRequest.ts @@ -0,0 +1,21 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ + +import * as Rivet from "../../../../../../../../index"; + +/** + * @example + * { + * serverId: "string", + * datacenter: "string", + * pool: Rivet.admin.clusters.PoolType.Job, + * publicIp: "string" + * } + */ +export interface ListLostServersRequest { + serverId?: string; + datacenter?: string; + pool?: Rivet.admin.clusters.PoolType; + publicIp?: string; +} diff --git a/sdks/full/typescript/src/api/resources/admin/resources/clusters/resources/servers/client/requests/PruneServersRequest.ts b/sdks/full/typescript/src/api/resources/admin/resources/clusters/resources/servers/client/requests/PruneServersRequest.ts new file mode 100644 index 0000000000..391f2a7867 --- /dev/null +++ b/sdks/full/typescript/src/api/resources/admin/resources/clusters/resources/servers/client/requests/PruneServersRequest.ts @@ -0,0 +1,21 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ + +import * as Rivet from "../../../../../../../../index"; + +/** + * @example + * { + * serverId: "string", + * datacenter: "string", + * pool: Rivet.admin.clusters.PoolType.Job, + * publicIp: "string" + * } + */ +export interface PruneServersRequest { + serverId?: string; + datacenter?: string; + pool?: Rivet.admin.clusters.PoolType; + publicIp?: string; +} diff --git a/sdks/full/typescript/src/api/resources/admin/resources/clusters/resources/servers/client/requests/index.ts b/sdks/full/typescript/src/api/resources/admin/resources/clusters/resources/servers/client/requests/index.ts index dc9931a37d..9c5eafd04f 100644 --- a/sdks/full/typescript/src/api/resources/admin/resources/clusters/resources/servers/client/requests/index.ts +++ b/sdks/full/typescript/src/api/resources/admin/resources/clusters/resources/servers/client/requests/index.ts @@ -1,3 +1,5 @@ export { type ListServersRequest } from "./ListServersRequest"; export { type TaintServersRequest } from "./TaintServersRequest"; export { type DestroyServersRequest } from "./DestroyServersRequest"; +export { type ListLostServersRequest } from "./ListLostServersRequest"; +export { type PruneServersRequest } from "./PruneServersRequest"; diff --git a/sdks/full/typescript/types/api/resources/admin/resources/clusters/resources/common/types/Datacenter.d.ts b/sdks/full/typescript/types/api/resources/admin/resources/clusters/resources/common/types/Datacenter.d.ts index af83dfd707..16f2ab0b60 100644 --- a/sdks/full/typescript/types/api/resources/admin/resources/clusters/resources/common/types/Datacenter.d.ts +++ b/sdks/full/typescript/types/api/resources/admin/resources/clusters/resources/common/types/Datacenter.d.ts @@ -9,7 +9,7 @@ export interface Datacenter { displayName: string; provider: Rivet.admin.clusters.Provider; providerDatacenterId: string; - providerApiToken?: string; pools: Rivet.admin.clusters.Pool[]; buildDeliveryMethod: Rivet.admin.clusters.BuildDeliveryMethod; + prebakesEnabled: boolean; } diff --git a/sdks/full/typescript/types/api/resources/admin/resources/clusters/resources/common/types/Server.d.ts b/sdks/full/typescript/types/api/resources/admin/resources/clusters/resources/common/types/Server.d.ts index 6f69f68d41..842d7feb3c 100644 --- a/sdks/full/typescript/types/api/resources/admin/resources/clusters/resources/common/types/Server.d.ts +++ b/sdks/full/typescript/types/api/resources/admin/resources/clusters/resources/common/types/Server.d.ts @@ -1,7 +1,10 @@ /** * This file was auto-generated by Fern from our API Definition. */ +import * as Rivet from "../../../../../../../index"; export interface Server { serverId: string; + datacenterId: string; + poolType: Rivet.admin.clusters.PoolType; publicIp?: string; } diff --git a/sdks/full/typescript/types/api/resources/admin/resources/clusters/resources/servers/client/Client.d.ts b/sdks/full/typescript/types/api/resources/admin/resources/clusters/resources/servers/client/Client.d.ts index 9be115c8d0..6b96b58814 100644 --- a/sdks/full/typescript/types/api/resources/admin/resources/clusters/resources/servers/client/Client.d.ts +++ b/sdks/full/typescript/types/api/resources/admin/resources/clusters/resources/servers/client/Client.d.ts @@ -85,5 +85,47 @@ export declare class Servers { * }) */ destroy(clusterId: string, request?: Rivet.admin.clusters.DestroyServersRequest, requestOptions?: Servers.RequestOptions): Promise; + /** + * @param {string} clusterId + * @param {Rivet.admin.clusters.ListLostServersRequest} request + * @param {Servers.RequestOptions} requestOptions - Request-specific configuration. + * + * @throws {@link Rivet.InternalError} + * @throws {@link Rivet.RateLimitError} + * @throws {@link Rivet.ForbiddenError} + * @throws {@link Rivet.UnauthorizedError} + * @throws {@link Rivet.NotFoundError} + * @throws {@link Rivet.BadRequestError} + * + * @example + * await client.admin.clusters.servers.listLost("d5e9c84f-c2b2-4bf4-b4b0-7ffd7a9ffc32", { + * serverId: "string", + * datacenter: "string", + * pool: Rivet.admin.clusters.PoolType.Job, + * publicIp: "string" + * }) + */ + listLost(clusterId: string, request?: Rivet.admin.clusters.ListLostServersRequest, requestOptions?: Servers.RequestOptions): Promise; + /** + * @param {string} clusterId + * @param {Rivet.admin.clusters.PruneServersRequest} request + * @param {Servers.RequestOptions} requestOptions - Request-specific configuration. + * + * @throws {@link Rivet.InternalError} + * @throws {@link Rivet.RateLimitError} + * @throws {@link Rivet.ForbiddenError} + * @throws {@link Rivet.UnauthorizedError} + * @throws {@link Rivet.NotFoundError} + * @throws {@link Rivet.BadRequestError} + * + * @example + * await client.admin.clusters.servers.prune("d5e9c84f-c2b2-4bf4-b4b0-7ffd7a9ffc32", { + * serverId: "string", + * datacenter: "string", + * pool: Rivet.admin.clusters.PoolType.Job, + * publicIp: "string" + * }) + */ + prune(clusterId: string, request?: Rivet.admin.clusters.PruneServersRequest, requestOptions?: Servers.RequestOptions): Promise; protected _getAuthorizationHeader(): Promise; } diff --git a/sdks/full/typescript/types/api/resources/admin/resources/clusters/resources/servers/client/requests/index.d.ts b/sdks/full/typescript/types/api/resources/admin/resources/clusters/resources/servers/client/requests/index.d.ts index dc9931a37d..9c5eafd04f 100644 --- a/sdks/full/typescript/types/api/resources/admin/resources/clusters/resources/servers/client/requests/index.d.ts +++ b/sdks/full/typescript/types/api/resources/admin/resources/clusters/resources/servers/client/requests/index.d.ts @@ -1,3 +1,5 @@ export { type ListServersRequest } from "./ListServersRequest"; export { type TaintServersRequest } from "./TaintServersRequest"; export { type DestroyServersRequest } from "./DestroyServersRequest"; +export { type ListLostServersRequest } from "./ListLostServersRequest"; +export { type PruneServersRequest } from "./PruneServersRequest"; diff --git a/sdks/full/typescript/types/serialization/resources/admin/resources/clusters/resources/common/types/Datacenter.d.ts b/sdks/full/typescript/types/serialization/resources/admin/resources/clusters/resources/common/types/Datacenter.d.ts index 025b69d77d..7612f32f4e 100644 --- a/sdks/full/typescript/types/serialization/resources/admin/resources/clusters/resources/common/types/Datacenter.d.ts +++ b/sdks/full/typescript/types/serialization/resources/admin/resources/clusters/resources/common/types/Datacenter.d.ts @@ -14,8 +14,8 @@ export declare namespace Datacenter { display_name: string; provider: admin.clusters.Provider.Raw; provider_datacenter_id: string; - provider_api_token?: string | null; pools: admin.clusters.Pool.Raw[]; build_delivery_method: admin.clusters.BuildDeliveryMethod.Raw; + prebakes_enabled: boolean; } } diff --git a/sdks/full/typescript/types/serialization/resources/admin/resources/clusters/resources/common/types/Server.d.ts b/sdks/full/typescript/types/serialization/resources/admin/resources/clusters/resources/common/types/Server.d.ts index cd78962777..fce3834bf7 100644 --- a/sdks/full/typescript/types/serialization/resources/admin/resources/clusters/resources/common/types/Server.d.ts +++ b/sdks/full/typescript/types/serialization/resources/admin/resources/clusters/resources/common/types/Server.d.ts @@ -4,10 +4,13 @@ import * as serializers from "../../../../../../../index"; import * as Rivet from "../../../../../../../../api/index"; import * as core from "../../../../../../../../core"; +import { admin } from "../../../../../../index"; export declare const Server: core.serialization.ObjectSchema; export declare namespace Server { interface Raw { server_id: string; + datacenter_id: string; + pool_type: admin.clusters.PoolType.Raw; public_ip?: string | null; } } diff --git a/sdks/runtime/typescript/archive.tgz b/sdks/runtime/typescript/archive.tgz index 4662cd168d..1d6073c962 100644 --- a/sdks/runtime/typescript/archive.tgz +++ b/sdks/runtime/typescript/archive.tgz @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3481c45cb968bc93a3e39dba7f12bf0d2b55e59cde1cac5263a8ec44752e7ab1 -size 282555 +oid sha256:4390feab195e4570d70e833cd70b6d15ccde2d3fef990e8d9701afb889ffe70b +size 282603 diff --git a/svc/Cargo.lock b/svc/Cargo.lock index 32cd552a84..79782427ab 100644 --- a/svc/Cargo.lock +++ b/svc/Cargo.lock @@ -1081,7 +1081,7 @@ checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.74", ] [[package]] @@ -1778,9 +1778,9 @@ dependencies = [ [[package]] name = "camino" -version = "1.1.7" +version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0ec6b951b160caa93cc0c7b209e5a3bff7aae9062213451ac99493cd844c239" +checksum = "3054fea8a20d8ff3968d5b22cc27501d2b08dc4decdb31b184323f00c5ef23bb" [[package]] name = "captcha-hcaptcha-config-get" @@ -1861,9 +1861,12 @@ dependencies = [ [[package]] name = "cc" -version = "1.1.7" +version = "1.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26a5c3fd7bfa1ce3897a3a3501d362b2d87b7f2583ebcb4a949ec25911025cbc" +checksum = "68064e60dbf1f17005c2fde4d07c16d8baa506fd7ffed8ccab702d93617975c7" +dependencies = [ + "shlex", +] [[package]] name = "cdn-namespace-auth-user-remove" @@ -2249,7 +2252,7 @@ version = "0.1.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.74", ] [[package]] @@ -2292,7 +2295,7 @@ version = "0.1.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.74", ] [[package]] @@ -2577,6 +2580,7 @@ dependencies = [ "acme-lib", "anyhow", "chirp-workflow", + "chrono", "cloudflare", "hex", "http 0.2.12", @@ -2782,15 +2786,15 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpufeatures" -version = "0.2.12" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +checksum = "51e852e6dc9a5bed1fae92dd2375037bf2b768725bf3be87811edee3249d09ad" dependencies = [ "libc", ] @@ -2946,7 +2950,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.74", ] [[package]] @@ -3000,7 +3004,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.72", + "syn 2.0.74", ] [[package]] @@ -3011,7 +3015,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 2.0.72", + "syn 2.0.74", ] [[package]] @@ -3314,7 +3318,7 @@ dependencies = [ "heck 0.4.1", "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.74", ] [[package]] @@ -3730,7 +3734,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.74", ] [[package]] @@ -4311,7 +4315,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.12", - "indexmap 2.3.0", + "indexmap 2.4.0", "slab", "tokio", "tokio-util 0.7.11", @@ -4330,7 +4334,7 @@ dependencies = [ "futures-core", "futures-sink", "http 1.1.0", - "indexmap 2.3.0", + "indexmap 2.4.0", "slab", "tokio", "tokio-util 0.7.11", @@ -4860,9 +4864,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3fc2e30ba82dd1b3911c8de1ffc143c74a914a14e99514d7637e3099df5ea0" +checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c" dependencies = [ "equivalent", "hashbrown 0.14.5", @@ -5105,9 +5109,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.69" +version = "0.3.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" dependencies = [ "wasm-bindgen", ] @@ -5232,9 +5236,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.155" +version = "0.2.156" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +checksum = "a5f43f184355eefb8d17fc948dbecf6c13be3c141f20d834ae842193a448c72a" [[package]] name = "libm" @@ -5269,9 +5273,9 @@ dependencies = [ [[package]] name = "libz-sys" -version = "1.1.18" +version = "1.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c15da26e5af7e25c90b37a2d75cdbf940cf4a55316de9d84c679c9b8bfabf82e" +checksum = "fdc53a7799a7496ebc9fd29f31f7df80e83c9bda5299768af5f9e59eeea74647" dependencies = [ "cc", "libc", @@ -5585,9 +5589,9 @@ dependencies = [ [[package]] name = "mio" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4569e456d394deccd22ce1c1913e6ea0e54519f577285001215d33557431afe4" +checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" dependencies = [ "hermit-abi", "libc", @@ -6332,9 +6336,9 @@ dependencies = [ [[package]] name = "object" -version = "0.36.2" +version = "0.36.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f203fa8daa7bb185f760ae12bd8e097f63d17041dcdcaf675ac54cdf863170e" +checksum = "27b64972346851a39438c60b341ebc01bba47464ae329e55cf343eb93964efd9" dependencies = [ "memchr", ] @@ -6368,7 +6372,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.74", ] [[package]] @@ -6558,7 +6562,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.74", ] [[package]] @@ -6579,7 +6583,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" dependencies = [ "fixedbitset", - "indexmap 2.3.0", + "indexmap 2.4.0", ] [[package]] @@ -6599,7 +6603,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.74", ] [[package]] @@ -6840,7 +6844,7 @@ dependencies = [ "itertools 0.12.1", "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.74", ] [[package]] @@ -7620,7 +7624,7 @@ version = "0.1.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.74", ] [[package]] @@ -7726,7 +7730,7 @@ dependencies = [ "chrono", "futures-util", "global-error", - "indexmap 2.3.0", + "indexmap 2.4.0", "ipnet", "lazy_static", "rand", @@ -8140,9 +8144,9 @@ checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" [[package]] name = "serde" -version = "1.0.204" +version = "1.0.208" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" +checksum = "cff085d2cb684faa248efb494c39b68e522822ac0de72ccf08109abde717cfb2" dependencies = [ "serde_derive", ] @@ -8158,13 +8162,13 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.204" +version = "1.0.208" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" +checksum = "24008e81ff7613ed8e5ba0cfaf24e2c2f1e5b8a0495711e44fcd4882fca62bcf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.74", ] [[package]] @@ -8180,11 +8184,11 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.122" +version = "1.0.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784b6203951c57ff748476b126ccb5e8e2959a5c19e5c617ab1956be3dbc68da" +checksum = "83c8e735a073ccf5be70aa8066aa984eaf2fa000db6c8d0100ae605b366d31ed" dependencies = [ - "indexmap 2.3.0", + "indexmap 2.4.0", "itoa 1.0.11", "memchr", "ryu", @@ -8208,7 +8212,7 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.74", ] [[package]] @@ -8257,7 +8261,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.74", ] [[package]] @@ -8297,6 +8301,12 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "signal-hook-registry" version = "1.4.2" @@ -8461,7 +8471,7 @@ dependencies = [ "futures-util", "hashlink", "hex", - "indexmap 2.3.0", + "indexmap 2.4.0", "ipnetwork", "log", "memchr", @@ -8748,7 +8758,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.72", + "syn 2.0.74", ] [[package]] @@ -8761,7 +8771,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.72", + "syn 2.0.74", ] [[package]] @@ -8783,9 +8793,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.72" +version = "2.0.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af" +checksum = "1fceb41e3d546d0bd83421d3409b1460cc7444cd389341a4c880fe7a042cb3d7" dependencies = [ "proc-macro2", "quote", @@ -9100,7 +9110,7 @@ checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.74", ] [[package]] @@ -9275,7 +9285,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.74", ] [[package]] @@ -9430,7 +9440,7 @@ version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.3.0", + "indexmap 2.4.0", "serde", "serde_spanned", "toml_datetime", @@ -9487,15 +9497,15 @@ dependencies = [ [[package]] name = "tower-layer" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" [[package]] name = "tower-service" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" @@ -9517,7 +9527,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.74", ] [[package]] @@ -9892,9 +9902,9 @@ dependencies = [ [[package]] name = "ureq" -version = "2.10.0" +version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72139d247e5f97a3eff96229a7ae85ead5328a39efe76f8bf5a06313d505b6ea" +checksum = "b74fc6b57825be3373f7054754755f03ac3a8f5d70015ccad699ba2029956f4a" dependencies = [ "base64 0.22.1", "flate2", @@ -10395,34 +10405,35 @@ checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" [[package]] name = "wasm-bindgen" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" dependencies = [ "cfg-if", + "once_cell", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.74", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.42" +version = "0.4.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" +checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed" dependencies = [ "cfg-if", "js-sys", @@ -10432,9 +10443,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -10442,22 +10453,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.74", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" +checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" [[package]] name = "wasm-streams" @@ -10474,9 +10485,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.69" +version = "0.3.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0" dependencies = [ "js-sys", "wasm-bindgen", @@ -10830,7 +10841,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.74", ] [[package]] diff --git a/svc/api/admin/src/route/clusters/datacenters.rs b/svc/api/admin/src/route/clusters/datacenters.rs index f3f9dfb3d1..6a2ee2824a 100644 --- a/svc/api/admin/src/route/clusters/datacenters.rs +++ b/svc/api/admin/src/route/clusters/datacenters.rs @@ -27,7 +27,7 @@ pub async fn list( .await? .datacenters .into_iter() - .map(ApiTryInto::::api_try_into) + .map(ApiTryInto::api_try_into) .collect::>>()?; Ok(models::AdminClustersListDatacentersResponse { datacenters }) diff --git a/svc/api/admin/src/route/clusters/servers.rs b/svc/api/admin/src/route/clusters/servers.rs index 78ca0d3b7e..6380ba900d 100644 --- a/svc/api/admin/src/route/clusters/servers.rs +++ b/svc/api/admin/src/route/clusters/servers.rs @@ -2,7 +2,7 @@ use std::{net::Ipv4Addr, str::FromStr}; use api_helper::{anchor::WatchIndexQuery, ctx::Ctx}; use rivet_api::models; -use rivet_convert::ApiInto; +use rivet_convert::{ApiInto, ApiTryInto}; use rivet_operation::prelude::*; use serde::Deserialize; use serde_json::{json, Value}; @@ -68,13 +68,8 @@ pub async fn list( let servers = servers_res .servers - .iter() - .map(|server| { - GlobalResult::Ok(models::AdminClustersServer { - server_id: server.server_id, - public_ip: server.public_ip.map(|ip| ip.to_string()), - }) - }) + .into_iter() + .map(ApiTryInto::api_try_into) .collect::>>()?; Ok(models::AdminClustersListServersResponse { servers }) @@ -109,3 +104,40 @@ pub async fn destroy( Ok(json!({})) } + +// MARK: GET /clusters/{cluster_id}/servers/lost +pub async fn list_lost( + ctx: Ctx, + cluster_id: Uuid, + _watch_index: WatchIndexQuery, + query: ServerFilterQuery, +) -> GlobalResult { + let servers_res = ctx + .op(cluster::ops::server::lost_list::Input { + filter: query.convert(&ctx, cluster_id).await?, + }) + .await?; + + let servers = servers_res + .servers + .into_iter() + .map(ApiTryInto::api_try_into) + .collect::>>()?; + + Ok(models::AdminClustersListServersResponse { servers }) +} + +// MARK: GET /clusters/{cluster_id}/servers/prune +pub async fn prune( + ctx: Ctx, + cluster_id: Uuid, + _body: serde_json::Value, + query: ServerFilterQuery, +) -> GlobalResult { + ctx.op(cluster::ops::server::prune_with_filter::Input { + filter: query.convert(&ctx, cluster_id).await?, + }) + .await?; + + Ok(json!({})) +} diff --git a/svc/api/admin/src/route/mod.rs b/svc/api/admin/src/route/mod.rs index 7e26c83d66..7e1cc3c798 100644 --- a/svc/api/admin/src/route/mod.rs +++ b/svc/api/admin/src/route/mod.rs @@ -54,6 +54,19 @@ define_router! { ), }, + "clusters" / Uuid / "servers" / "lost": { + GET: clusters::servers::list_lost( + query: clusters::servers::ServerFilterQuery, + ), + }, + + "clusters" / Uuid / "servers" / "prune": { + POST: clusters::servers::prune( + query: clusters::servers::ServerFilterQuery, + body: serde_json::Value, + ), + }, + "clusters" / Uuid / "datacenters": { GET: clusters::datacenters::list(), POST: clusters::datacenters::create( diff --git a/svc/pkg/cluster/Cargo.toml b/svc/pkg/cluster/Cargo.toml index 5f1f1392c4..d8a8eb2e7b 100644 --- a/svc/pkg/cluster/Cargo.toml +++ b/svc/pkg/cluster/Cargo.toml @@ -9,6 +9,7 @@ license = "Apache-2.0" acme-lib = "0.9" anyhow = "1.0" chirp-workflow = { path = "../../../lib/chirp-workflow/core" } +chrono = "0.4" cloudflare = { git = "https://github.com/cloudflare/cloudflare-rs.git", rev = "f14720e42184ee176a97676e85ef2d2d85bc3aae" } http = "0.2" include_dir = "0.7.3" diff --git a/svc/pkg/cluster/src/ops/server/get.rs b/svc/pkg/cluster/src/ops/server/get.rs index 305cd9a001..3942fe6d5d 100644 --- a/svc/pkg/cluster/src/ops/server/get.rs +++ b/svc/pkg/cluster/src/ops/server/get.rs @@ -23,6 +23,7 @@ pub(crate) struct ServerRow { datacenter_id: Uuid, pool_type2: Option>, pool_type: i64, + provider_server_id: Option, vlan_ip: Option, public_ip: Option, cloud_destroy_ts: Option, @@ -41,6 +42,7 @@ impl TryFrom for Server { } else { value.pool_type.try_into()? }, + provider_server_id: value.provider_server_id, vlan_ip: value.vlan_ip, public_ip: value.public_ip, cloud_destroy_ts: value.cloud_destroy_ts, @@ -58,6 +60,7 @@ pub async fn cluster_server_get(ctx: &OperationCtx, input: &Input) -> GlobalResu datacenter_id, pool_type, pool_type2, + provider_server_id, vlan_ip, public_ip, cloud_destroy_ts diff --git a/svc/pkg/cluster/src/ops/server/list.rs b/svc/pkg/cluster/src/ops/server/list.rs index 13fb5e50ce..450a9b9071 100644 --- a/svc/pkg/cluster/src/ops/server/list.rs +++ b/svc/pkg/cluster/src/ops/server/list.rs @@ -26,6 +26,7 @@ pub async fn cluster_server_list(ctx: &OperationCtx, input: &Input) -> GlobalRes s.datacenter_id, s.pool_type, s.pool_type2, + s.provider_server_id, s.vlan_ip, s.public_ip, s.cloud_destroy_ts @@ -33,12 +34,12 @@ pub async fn cluster_server_list(ctx: &OperationCtx, input: &Input) -> GlobalRes JOIN db_cluster.datacenters AS d ON s.datacenter_id = d.datacenter_id WHERE - ($1 OR s.cloud_destroy_ts IS NULL) - AND ($2 IS NULL OR s.server_id = ANY($2)) - AND ($3 IS NULL OR s.datacenter_id = ANY($3)) - AND ($4 IS NULL OR d.cluster_id = ANY($4)) - AND ($5 IS NULL OR s.pool_type2 = ANY($5::JSONB[])) - AND ($6 IS NULL OR s.public_ip = ANY($6)) + ($1 OR s.cloud_destroy_ts IS NULL) AND + ($2 IS NULL OR s.server_id = ANY($2)) AND + ($3 IS NULL OR s.datacenter_id = ANY($3)) AND + ($4 IS NULL OR d.cluster_id = ANY($4)) AND + ($5 IS NULL OR s.pool_type2 = ANY($5::JSONB[])) AND + ($6 IS NULL OR s.public_ip = ANY($6)) ", input.include_destroyed, &input.filter.server_ids, diff --git a/svc/pkg/cluster/src/ops/server/lost_list.rs b/svc/pkg/cluster/src/ops/server/lost_list.rs new file mode 100644 index 0000000000..402caab320 --- /dev/null +++ b/svc/pkg/cluster/src/ops/server/lost_list.rs @@ -0,0 +1,180 @@ +use std::{net::IpAddr, collections::HashSet, convert::{TryFrom, TryInto}}; + +use chirp_workflow::prelude::*; +use linode::util::client; +use reqwest::header; +use serde_json::json; + +use super::get::ServerRow; +use crate::types::{Filter, Server, Provider}; + +#[derive(Deserialize)] +struct GetLinodesResponse { + data: Vec, +} + +#[derive(Deserialize)] +struct Linode { + created: chrono::NaiveDateTime, + label: String, +} + +#[derive(Debug)] +pub struct Input { + pub filter: Filter, +} + +#[derive(Debug)] +pub struct Output { + pub servers: Vec, +} + +/// Fetches deleted servers directly from the cloud providers own APIs and returns existing servers older +/// than 12 hours. +#[operation] +pub async fn cluster_server_lost_list(ctx: &OperationCtx, input: &Input) -> GlobalResult { + let linode_token = util::env::read_secret(&["linode", "token"]).await?; + + let dc_rows = sql_fetch_all!( + [ctx, (i64, Option)] + " + SELECT provider, provider_api_token + FROM db_cluster.datacenters + WHERE + provider_api_token IS NOT NULL AND + ($1 IS NULL OR cluster_id = ANY($1)) + ", + &input.filter.cluster_ids, + ) + .await?; + + let accounts = dc_rows + .iter() + .map(|(provider, provider_api_token)| { + let provider = Provider::try_from(*provider)?; + // Default token if none is set + let provider_api_token = match &provider { + Provider::Linode => provider_api_token + .clone() + .unwrap_or_else(|| linode_token.clone()), + }; + + Ok((provider, provider_api_token)) + }) + .collect::>>()?; + + // Filter by namespace + let filter = json!({ + "label": { + "+contains": format!("{}-", util::env::namespace()), + } + }); + let mut headers = header::HeaderMap::new(); + headers.insert( + "X-Filter", + header::HeaderValue::from_str(&serde_json::to_string(&filter)?)?, + ); + + let mut servers = Vec::new(); + for (provider, api_token) in accounts { + match provider { + Provider::Linode => { + servers.extend( + run_for_linode_account(ctx, &input.filter, &api_token, &headers).await?, + ); + } + } + } + + Ok(Output { servers }) +} + +async fn run_for_linode_account( + ctx: &OperationCtx, + filter: &Filter, + api_token: &str, + headers: &header::HeaderMap, +) -> GlobalResult> { + // Build HTTP client + let client = + client::Client::new_with_headers(Some(api_token.to_string()), headers.clone()).await?; + + let req = client + .inner() + .get("https://api.linode.com/v4/linode/instances") + .query(&[("page_size", 500)]); + + let res = client + .request(req, None, false) + .await? + .json::() + .await?; + + tracing::info!("{} servers in account", res.data.len()); + + let server_ids = res + .data + .into_iter() + // Filter out servers younger than 12 hours + .filter(|linode| { + linode.created.and_utc().timestamp_millis() < ctx.ts() - util::duration::hours(12) + }) + // Parse server ID from linode label + .filter_map(|linode| { + linode + .label + .get(util::env::namespace().len() + 1..) + .map(util::uuid::parse) + }) + .collect::>>()?; + + // Select deleted servers that match the linode api call + let servers = sql_fetch_all!( + [ctx, ServerRow] + " + SELECT + s.server_id, + s.datacenter_id, + s.pool_type, + s.pool_type2, + s.vlan_ip, + s.public_ip, + s.cloud_destroy_ts + FROM db_cluster.servers AS s + JOIN db_cluster.datacenters AS d + ON s.datacenter_id = d.datacenter_id + WHERE + server_id = ANY($1) AND + cloud_destroy_ts IS NOT NULL AND + + ($2 IS NULL OR s.server_id = ANY($2)) AND + ($3 IS NULL OR s.datacenter_id = ANY($3)) AND + ($4 IS NULL OR d.cluster_id = ANY($4)) AND + ($5 IS NULL OR s.pool_type2 = ANY($5::JSONB[])) AND + ($6 IS NULL OR s.public_ip = ANY($6)) + ", + server_ids, + &filter.server_ids, + &filter.datacenter_ids, + &filter.cluster_ids, + filter.pool_types + .as_ref() + .map(|x| x.iter() + .map(serde_json::to_string) + .collect::, _>>() + ).transpose()?, + filter.public_ips + .as_ref() + .map(|x| x.iter() + .cloned() + .map(IpAddr::V4) + .collect::>() + ), + ) + .await? + .into_iter() + .map(TryInto::try_into) + .collect::>>()?; + + Ok(servers) +} diff --git a/svc/pkg/cluster/src/ops/server/mod.rs b/svc/pkg/cluster/src/ops/server/mod.rs index 78cccf9ac3..f2f76a6204 100644 --- a/svc/pkg/cluster/src/ops/server/mod.rs +++ b/svc/pkg/cluster/src/ops/server/mod.rs @@ -1,5 +1,7 @@ pub mod destroy_with_filter; pub mod get; pub mod list; +pub mod lost_list; pub mod resolve_for_ip; pub mod taint_with_filter; +pub mod prune_with_filter; diff --git a/svc/pkg/cluster/src/ops/server/prune_with_filter.rs b/svc/pkg/cluster/src/ops/server/prune_with_filter.rs new file mode 100644 index 0000000000..c5d17afdf3 --- /dev/null +++ b/svc/pkg/cluster/src/ops/server/prune_with_filter.rs @@ -0,0 +1,110 @@ +use std::{convert::TryFrom, collections::HashSet}; + +use chirp_workflow::prelude::*; +use serde_json::json; +use linode::util::{api, client}; +use reqwest::header; + +use crate::{types::{Server, Filter, Provider}}; + +#[derive(Debug)] +pub struct Input { + pub filter: Filter, +} + +#[derive(Debug)] +pub struct Output {} + +#[operation] +pub async fn cluster_server_prune_with_filter( + ctx: &OperationCtx, + input: &Input, +) -> GlobalResult { + let linode_token = util::env::read_secret(&["linode", "token"]).await?; + + let servers_res = ctx + .op(crate::ops::server::lost_list::Input { + filter: input.filter.clone(), + }) + .await?; + + let dc_ids = servers_res + .servers + .iter() + .map(|x| x.server_id) + .collect::>(); + let dc_rows = sql_fetch_all!( + [ctx, (i64, Option)] + " + SELECT provider, provider_api_token + FROM db_cluster.datacenters + WHERE + provider_api_token IS NOT NULL AND + datacenter_id = ANY($1) + ", + dc_ids, + ) + .await?; + + let accounts = dc_rows + .iter() + .map(|(provider, provider_api_token)| { + let provider = Provider::try_from(*provider)?; + // Default token if none is set + let provider_api_token = match &provider { + Provider::Linode => provider_api_token + .clone() + .unwrap_or_else(|| linode_token.clone()), + }; + + Ok((provider, provider_api_token)) + }) + .collect::>>()?; + + // Filter by namespace + let filter = json!({ + "label": { + "+contains": format!("{}-", util::env::namespace()), + } + }); + let mut headers = header::HeaderMap::new(); + headers.insert( + "X-Filter", + header::HeaderValue::from_str(&serde_json::to_string(&filter)?)?, + ); + + for (provider, api_token) in accounts { + match provider { + Provider::Linode => { + run_for_linode_account(&servers_res.servers, &api_token, &headers).await?; + } + } + } + + Ok(Output {}) +} + +async fn run_for_linode_account( + servers: &[Server], + api_token: &str, + headers: &header::HeaderMap, +) -> GlobalResult<()> { + // Build HTTP client + let client = + client::Client::new_with_headers(Some(api_token.to_string()), headers.clone()).await?; + + for server in servers { + let linode_id = unwrap_ref!(server.provider_server_id).parse()?; + let firewalls = api::list_linode_firewalls(&client, linode_id).await?; + + for firewall in firewalls { + api::delete_firewall(&client, firewall.id).await?; + } + + api::delete_instance(&client, linode_id).await?; + + // NOTE: Does not delete ssh keys + } + + Ok(()) +} \ No newline at end of file diff --git a/svc/pkg/cluster/src/types.rs b/svc/pkg/cluster/src/types.rs index d22612bee9..f0e19c21d8 100644 --- a/svc/pkg/cluster/src/types.rs +++ b/svc/pkg/cluster/src/types.rs @@ -32,7 +32,7 @@ pub struct Datacenter { pub create_ts: i64, } -#[derive(Debug, Clone, Serialize, Deserialize, Hash)] +#[derive(Debug, Clone, Serialize, Deserialize, Hash, PartialEq, Eq)] pub enum Provider { Linode, } @@ -150,6 +150,7 @@ pub struct Server { pub server_id: Uuid, pub datacenter_id: Uuid, pub pool_type: PoolType, + pub provider_server_id: Option, pub vlan_ip: Option, pub public_ip: Option, pub cloud_destroy_ts: Option, diff --git a/svc/pkg/linode/src/util/api.rs b/svc/pkg/linode/src/util/api.rs index 5ad17c357f..cf6c9ab342 100644 --- a/svc/pkg/linode/src/util/api.rs +++ b/svc/pkg/linode/src/util/api.rs @@ -383,6 +383,26 @@ pub async fn delete_firewall(client: &Client, firewall_id: u64) -> GlobalResult< .await } +#[derive(Deserialize)] +pub struct ListLinodeFirewallsResponse { + data: Vec, +} + +#[derive(Deserialize)] +pub struct Firewall { + pub id: u64, +} + +pub async fn list_linode_firewalls(client: &Client, linode_id: u64) -> GlobalResult> { + tracing::info!("fetching linode firewalls"); + + let res = client + .get::(&format!("/linode/instances/{linode_id}/firewalls")) + .await?; + + Ok(res.data) +} + pub async fn shut_down(client: &Client, linode_id: u64) -> GlobalResult<()> { tracing::info!("shutting down instance");