From 05f044e0bfbb26ee1ed179075df970798e465d96 Mon Sep 17 00:00:00 2001 From: Nathan Flurry Date: Fri, 31 May 2024 23:18:46 +0000 Subject: [PATCH] feat(api-admin): add server destroy endpoint --- fern/definition/admin/clusters/servers.yml | 10 ++ lib/bolt/cli/src/commands/cluster/mod.rs | 52 +++++++ sdks/full/go/admin/clusters/servers.go | 7 + sdks/full/go/admin/clusters/servers/client.go | 92 ++++++++++++ sdks/full/go/types.go | 1 + sdks/full/openapi/openapi.yml | 75 ++++++++++ sdks/full/openapi_compat/openapi.yml | 75 ++++++++++ sdks/full/rust-cli/README.md | 1 + .../rust-cli/docs/AdminClustersServersApi.md | 33 +++++ sdks/full/rust-cli/docs/ErrorBody.md | 1 + .../src/apis/admin_clusters_servers_api.rs | 55 +++++++ sdks/full/rust-cli/src/models/error_body.rs | 5 +- sdks/full/rust/README.md | 1 + .../full/rust/docs/AdminClustersServersApi.md | 33 +++++ sdks/full/rust/docs/ErrorBody.md | 1 + .../src/apis/admin_clusters_servers_api.rs | 55 +++++++ sdks/full/rust/src/models/error_body.rs | 5 +- sdks/full/typescript/archive.tgz | 4 +- .../resources/servers/client/Client.ts | 134 ++++++++++++++++++ .../client/requests/DestroyServersRequest.ts | 12 ++ .../servers/client/requests/index.ts | 1 + .../api/resources/common/types/ErrorBody.ts | 1 + .../resources/common/types/ErrorBody.ts | 2 + .../resources/servers/client/Client.d.ts | 9 ++ .../servers/client/requests/index.d.ts | 1 + .../api/resources/common/types/ErrorBody.d.ts | 1 + .../resources/common/types/ErrorBody.d.ts | 1 + sdks/runtime/go/types.go | 1 + sdks/runtime/openapi/openapi.yml | 3 + sdks/runtime/openapi_compat/openapi.yml | 3 + sdks/runtime/rust/docs/ErrorBody.md | 1 + sdks/runtime/rust/src/models/error_body.rs | 5 +- sdks/runtime/typescript/archive.tgz | 4 +- .../api/resources/common/types/ErrorBody.ts | 1 + .../resources/common/types/ErrorBody.ts | 2 + svc/Cargo.lock | 12 ++ svc/Cargo.toml | 1 + svc/api/admin/Cargo.toml | 1 + svc/api/admin/src/route/clusters/servers.rs | 17 +++ svc/api/admin/src/route/mod.rs | 7 + .../ops/server-destroy-with-filter/Cargo.toml | 18 +++ .../server-destroy-with-filter/Service.toml | 7 + .../ops/server-destroy-with-filter/src/lib.rs | 59 ++++++++ .../tests/integration.rs | 6 + .../types/server-destroy-with-filter.proto | 14 ++ 45 files changed, 823 insertions(+), 7 deletions(-) create mode 100644 sdks/full/typescript/src/api/resources/admin/resources/clusters/resources/servers/client/requests/DestroyServersRequest.ts create mode 100644 svc/pkg/cluster/ops/server-destroy-with-filter/Cargo.toml create mode 100644 svc/pkg/cluster/ops/server-destroy-with-filter/Service.toml create mode 100644 svc/pkg/cluster/ops/server-destroy-with-filter/src/lib.rs create mode 100644 svc/pkg/cluster/ops/server-destroy-with-filter/tests/integration.rs create mode 100644 svc/pkg/cluster/types/server-destroy-with-filter.proto diff --git a/fern/definition/admin/clusters/servers.yml b/fern/definition/admin/clusters/servers.yml index 09e9a57e8..55530b7a7 100644 --- a/fern/definition/admin/clusters/servers.yml +++ b/fern/definition/admin/clusters/servers.yml @@ -31,6 +31,16 @@ service: datacenter: optional pool: optional public_ip: optional + destroy: + path: /destroy + method: POST + request: + name: DestroyServersRequest + query-parameters: + server_id: optional + datacenter: optional + pool: optional + public_ip: optional types: ListServersResponse: diff --git a/lib/bolt/cli/src/commands/cluster/mod.rs b/lib/bolt/cli/src/commands/cluster/mod.rs index 568318af9..c730a7028 100644 --- a/lib/bolt/cli/src/commands/cluster/mod.rs +++ b/lib/bolt/cli/src/commands/cluster/mod.rs @@ -34,6 +34,20 @@ pub enum SubCommand { #[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 @@ -140,6 +154,44 @@ impl SubCommand { ) .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, diff --git a/sdks/full/go/admin/clusters/servers.go b/sdks/full/go/admin/clusters/servers.go index abc9675ce..f97bbee9b 100644 --- a/sdks/full/go/admin/clusters/servers.go +++ b/sdks/full/go/admin/clusters/servers.go @@ -8,6 +8,13 @@ import ( core "sdk/core" ) +type DestroyServersRequest struct { + ServerId *string `json:"-"` + Datacenter *string `json:"-"` + Pool *PoolType `json:"-"` + PublicIp *string `json:"-"` +} + type ListServersRequest 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 fd669f4f1..3b710dcd3 100644 --- a/sdks/full/go/admin/clusters/servers/client.go +++ b/sdks/full/go/admin/clusters/servers/client.go @@ -220,3 +220,95 @@ func (c *Client) Taint(ctx context.Context, clusterId uuid.UUID, request *cluste } return nil } + +func (c *Client) Destroy(ctx context.Context, clusterId uuid.UUID, request *clusters.DestroyServersRequest) error { + baseURL := "https://api.rivet.gg" + if c.baseURL != "" { + baseURL = c.baseURL + } + endpointURL := fmt.Sprintf(baseURL+"/"+"admin/clusters/%v/servers/destroy", 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/types.go b/sdks/full/go/types.go index 873fa4db0..96541884b 100644 --- a/sdks/full/go/types.go +++ b/sdks/full/go/types.go @@ -50,6 +50,7 @@ func (e *EmptyObject) String() string { type ErrorBody struct { Code string `json:"code"` Message string `json:"message"` + RayId string `json:"ray_id"` Documentation *string `json:"documentation,omitempty"` Metadata *ErrorMetadata `json:"metadata,omitempty"` diff --git a/sdks/full/openapi/openapi.yml b/sdks/full/openapi/openapi.yml index fec893e32..d038fc41a 100644 --- a/sdks/full/openapi/openapi.yml +++ b/sdks/full/openapi/openapi.yml @@ -5204,6 +5204,78 @@ paths: schema: $ref: '#/components/schemas/ErrorBody' security: *ref_0 + /admin/clusters/{cluster_id}/servers/destroy: + post: + operationId: admin_clusters_servers_destroy + 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. @@ -11997,6 +12069,8 @@ components: type: string message: type: string + ray_id: + type: string documentation: type: string metadata: @@ -12004,6 +12078,7 @@ components: required: - code - message + - ray_id GameHandle: type: object properties: diff --git a/sdks/full/openapi_compat/openapi.yml b/sdks/full/openapi_compat/openapi.yml index 381a25156..b5b025c46 100644 --- a/sdks/full/openapi_compat/openapi.yml +++ b/sdks/full/openapi_compat/openapi.yml @@ -2658,9 +2658,12 @@ components: type: string metadata: $ref: '#/components/schemas/ErrorMetadata' + ray_id: + type: string required: - code - message + - ray_id type: object ErrorMetadata: description: Unstructured metadata relating to an error. Must be manually parsed. @@ -4818,6 +4821,78 @@ paths: security: *id001 tags: - AdminClustersServers + /admin/clusters/{cluster_id}/servers/destroy: + post: + operationId: admin_clusters_servers_destroy + 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 3abccb224..794695035 100644 --- a/sdks/full/rust-cli/README.md +++ b/sdks/full/rust-cli/README.md @@ -31,6 +31,7 @@ Class | Method | HTTP request | Description *AdminClustersDatacentersApi* | [**admin_clusters_datacenters_create**](docs/AdminClustersDatacentersApi.md#admin_clusters_datacenters_create) | **POST** /admin/clusters/{cluster_id}/datacenters | *AdminClustersDatacentersApi* | [**admin_clusters_datacenters_list**](docs/AdminClustersDatacentersApi.md#admin_clusters_datacenters_list) | **GET** /admin/clusters/{cluster_id}/datacenters | *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_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 | diff --git a/sdks/full/rust-cli/docs/AdminClustersServersApi.md b/sdks/full/rust-cli/docs/AdminClustersServersApi.md index 820ace864..78a82f917 100644 --- a/sdks/full/rust-cli/docs/AdminClustersServersApi.md +++ b/sdks/full/rust-cli/docs/AdminClustersServersApi.md @@ -4,11 +4,44 @@ All URIs are relative to *https://api.rivet.gg* 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_taint**](AdminClustersServersApi.md#admin_clusters_servers_taint) | **POST** /admin/clusters/{cluster_id}/servers/taint | +## admin_clusters_servers_destroy + +> admin_clusters_servers_destroy(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_list > crate::models::AdminClustersListServersResponse admin_clusters_servers_list(cluster_id, server_id, datacenter, pool, public_ip) diff --git a/sdks/full/rust-cli/docs/ErrorBody.md b/sdks/full/rust-cli/docs/ErrorBody.md index 11d49aafe..53e465941 100644 --- a/sdks/full/rust-cli/docs/ErrorBody.md +++ b/sdks/full/rust-cli/docs/ErrorBody.md @@ -8,6 +8,7 @@ Name | Type | Description | Notes **documentation** | Option<**String**> | | [optional] **message** | **String** | | **metadata** | Option<[**serde_json::Value**](.md)> | Unstructured metadata relating to an error. Must be manually parsed. | [optional] +**ray_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/src/apis/admin_clusters_servers_api.rs b/sdks/full/rust-cli/src/apis/admin_clusters_servers_api.rs index 7c0e2c1f3..1bf403175 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 @@ -15,6 +15,19 @@ use crate::apis::ResponseContent; use super::{Error, configuration}; +/// struct for typed errors of method [`admin_clusters_servers_destroy`] +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum AdminClustersServersDestroyError { + 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_list`] #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(untagged)] @@ -42,6 +55,48 @@ pub enum AdminClustersServersTaintError { } +pub async fn admin_clusters_servers_destroy(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/destroy", 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_list(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; diff --git a/sdks/full/rust-cli/src/models/error_body.rs b/sdks/full/rust-cli/src/models/error_body.rs index e8cb91e27..1ad1d6233 100644 --- a/sdks/full/rust-cli/src/models/error_body.rs +++ b/sdks/full/rust-cli/src/models/error_body.rs @@ -22,15 +22,18 @@ pub struct ErrorBody { /// Unstructured metadata relating to an error. Must be manually parsed. #[serde(rename = "metadata", default, with = "::serde_with::rust::double_option", skip_serializing_if = "Option::is_none")] pub metadata: Option>, + #[serde(rename = "ray_id")] + pub ray_id: String, } impl ErrorBody { - pub fn new(code: String, message: String) -> ErrorBody { + pub fn new(code: String, message: String, ray_id: String) -> ErrorBody { ErrorBody { code, documentation: None, message, metadata: None, + ray_id, } } } diff --git a/sdks/full/rust/README.md b/sdks/full/rust/README.md index 3abccb224..794695035 100644 --- a/sdks/full/rust/README.md +++ b/sdks/full/rust/README.md @@ -31,6 +31,7 @@ Class | Method | HTTP request | Description *AdminClustersDatacentersApi* | [**admin_clusters_datacenters_create**](docs/AdminClustersDatacentersApi.md#admin_clusters_datacenters_create) | **POST** /admin/clusters/{cluster_id}/datacenters | *AdminClustersDatacentersApi* | [**admin_clusters_datacenters_list**](docs/AdminClustersDatacentersApi.md#admin_clusters_datacenters_list) | **GET** /admin/clusters/{cluster_id}/datacenters | *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_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 | diff --git a/sdks/full/rust/docs/AdminClustersServersApi.md b/sdks/full/rust/docs/AdminClustersServersApi.md index 820ace864..78a82f917 100644 --- a/sdks/full/rust/docs/AdminClustersServersApi.md +++ b/sdks/full/rust/docs/AdminClustersServersApi.md @@ -4,11 +4,44 @@ All URIs are relative to *https://api.rivet.gg* 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_taint**](AdminClustersServersApi.md#admin_clusters_servers_taint) | **POST** /admin/clusters/{cluster_id}/servers/taint | +## admin_clusters_servers_destroy + +> admin_clusters_servers_destroy(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_list > crate::models::AdminClustersListServersResponse admin_clusters_servers_list(cluster_id, server_id, datacenter, pool, public_ip) diff --git a/sdks/full/rust/docs/ErrorBody.md b/sdks/full/rust/docs/ErrorBody.md index 11d49aafe..53e465941 100644 --- a/sdks/full/rust/docs/ErrorBody.md +++ b/sdks/full/rust/docs/ErrorBody.md @@ -8,6 +8,7 @@ Name | Type | Description | Notes **documentation** | Option<**String**> | | [optional] **message** | **String** | | **metadata** | Option<[**serde_json::Value**](.md)> | Unstructured metadata relating to an error. Must be manually parsed. | [optional] +**ray_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/src/apis/admin_clusters_servers_api.rs b/sdks/full/rust/src/apis/admin_clusters_servers_api.rs index 7c0e2c1f3..1bf403175 100644 --- a/sdks/full/rust/src/apis/admin_clusters_servers_api.rs +++ b/sdks/full/rust/src/apis/admin_clusters_servers_api.rs @@ -15,6 +15,19 @@ use crate::apis::ResponseContent; use super::{Error, configuration}; +/// struct for typed errors of method [`admin_clusters_servers_destroy`] +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum AdminClustersServersDestroyError { + 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_list`] #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(untagged)] @@ -42,6 +55,48 @@ pub enum AdminClustersServersTaintError { } +pub async fn admin_clusters_servers_destroy(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/destroy", 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_list(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; diff --git a/sdks/full/rust/src/models/error_body.rs b/sdks/full/rust/src/models/error_body.rs index e8cb91e27..1ad1d6233 100644 --- a/sdks/full/rust/src/models/error_body.rs +++ b/sdks/full/rust/src/models/error_body.rs @@ -22,15 +22,18 @@ pub struct ErrorBody { /// Unstructured metadata relating to an error. Must be manually parsed. #[serde(rename = "metadata", default, with = "::serde_with::rust::double_option", skip_serializing_if = "Option::is_none")] pub metadata: Option>, + #[serde(rename = "ray_id")] + pub ray_id: String, } impl ErrorBody { - pub fn new(code: String, message: String) -> ErrorBody { + pub fn new(code: String, message: String, ray_id: String) -> ErrorBody { ErrorBody { code, documentation: None, message, metadata: None, + ray_id, } } } diff --git a/sdks/full/typescript/archive.tgz b/sdks/full/typescript/archive.tgz index debca6583..e69de07fa 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:33099a9a53151c8183723b13166dc46499f385288b8805cd48a88d671113a4e5 -size 640123 +oid sha256:8dc40597e77d7a688c1d61d68a044e68e85dbb9c37740e09ea238ca6a97524af +size 640371 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 68f2d5a1b..9b40d260d 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 @@ -299,6 +299,140 @@ export class Servers { } } + /** + * @throws {@link Rivet.InternalError} + * @throws {@link Rivet.RateLimitError} + * @throws {@link Rivet.ForbiddenError} + * @throws {@link Rivet.UnauthorizedError} + * @throws {@link Rivet.NotFoundError} + * @throws {@link Rivet.BadRequestError} + */ + public async destroy( + clusterId: string, + request: Rivet.admin.clusters.DestroyServersRequest = {}, + 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/${clusterId}/servers/destroy` + ), + method: "POST", + headers: { + Authorization: await this._getAuthorizationHeader(), + }, + contentType: "application/json", + queryParameters: _queryParams, + timeoutMs: requestOptions?.timeoutInSeconds != null ? requestOptions.timeoutInSeconds * 1000 : 180000, + maxRetries: requestOptions?.maxRetries, + }); + if (_response.ok) { + return; + } + + if (_response.error.reason === "status-code") { + switch (_response.error.statusCode) { + case 500: + throw new Rivet.InternalError( + await serializers.ErrorBody.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }) + ); + case 429: + throw new Rivet.RateLimitError( + await serializers.ErrorBody.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }) + ); + case 403: + throw new Rivet.ForbiddenError( + await serializers.ErrorBody.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }) + ); + case 408: + throw new Rivet.UnauthorizedError( + await serializers.ErrorBody.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }) + ); + case 404: + throw new Rivet.NotFoundError( + await serializers.ErrorBody.parseOrThrow(_response.error.body, { + unrecognizedObjectKeys: "passthrough", + allowUnrecognizedUnionMembers: true, + allowUnrecognizedEnumValues: true, + skipValidation: true, + breadcrumbsPrefix: ["response"], + }) + ); + case 400: + throw new Rivet.BadRequestError( + await 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() { 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/DestroyServersRequest.ts b/sdks/full/typescript/src/api/resources/admin/resources/clusters/resources/servers/client/requests/DestroyServersRequest.ts new file mode 100644 index 000000000..e773fd140 --- /dev/null +++ b/sdks/full/typescript/src/api/resources/admin/resources/clusters/resources/servers/client/requests/DestroyServersRequest.ts @@ -0,0 +1,12 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ + +import * as Rivet from "../../../../../../../.."; + +export interface DestroyServersRequest { + 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 5f1cf7b61..800cc433e 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,2 +1,3 @@ export { ListServersRequest } from "./ListServersRequest"; export { TaintServersRequest } from "./TaintServersRequest"; +export { DestroyServersRequest } from "./DestroyServersRequest"; diff --git a/sdks/full/typescript/src/api/resources/common/types/ErrorBody.ts b/sdks/full/typescript/src/api/resources/common/types/ErrorBody.ts index 8e7c2514d..e820bea2e 100644 --- a/sdks/full/typescript/src/api/resources/common/types/ErrorBody.ts +++ b/sdks/full/typescript/src/api/resources/common/types/ErrorBody.ts @@ -7,6 +7,7 @@ import * as Rivet from "../../.."; export interface ErrorBody { code: string; message: string; + rayId: string; documentation?: string; metadata?: Rivet.ErrorMetadata | undefined; } diff --git a/sdks/full/typescript/src/serialization/resources/common/types/ErrorBody.ts b/sdks/full/typescript/src/serialization/resources/common/types/ErrorBody.ts index 522f9d39b..c36a596cf 100644 --- a/sdks/full/typescript/src/serialization/resources/common/types/ErrorBody.ts +++ b/sdks/full/typescript/src/serialization/resources/common/types/ErrorBody.ts @@ -10,6 +10,7 @@ export const ErrorBody: core.serialization.ObjectSchema (await import("../../..")).ErrorMetadata).optional(), }); @@ -18,6 +19,7 @@ export declare namespace ErrorBody { interface Raw { code: string; message: string; + ray_id: string; documentation?: string | null; metadata?: (serializers.ErrorMetadata.Raw | undefined) | null; } 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 92d279631..988f2184a 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 @@ -36,5 +36,14 @@ export declare class Servers { * @throws {@link Rivet.BadRequestError} */ taint(clusterId: string, request?: Rivet.admin.clusters.TaintServersRequest, requestOptions?: Servers.RequestOptions): Promise; + /** + * @throws {@link Rivet.InternalError} + * @throws {@link Rivet.RateLimitError} + * @throws {@link Rivet.ForbiddenError} + * @throws {@link Rivet.UnauthorizedError} + * @throws {@link Rivet.NotFoundError} + * @throws {@link Rivet.BadRequestError} + */ + destroy(clusterId: string, request?: Rivet.admin.clusters.DestroyServersRequest, 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 5f1cf7b61..800cc433e 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,2 +1,3 @@ export { ListServersRequest } from "./ListServersRequest"; export { TaintServersRequest } from "./TaintServersRequest"; +export { DestroyServersRequest } from "./DestroyServersRequest"; diff --git a/sdks/full/typescript/types/api/resources/common/types/ErrorBody.d.ts b/sdks/full/typescript/types/api/resources/common/types/ErrorBody.d.ts index baa38f1f8..0a7f8111e 100644 --- a/sdks/full/typescript/types/api/resources/common/types/ErrorBody.d.ts +++ b/sdks/full/typescript/types/api/resources/common/types/ErrorBody.d.ts @@ -5,6 +5,7 @@ import * as Rivet from "../../.."; export interface ErrorBody { code: string; message: string; + rayId: string; documentation?: string; metadata?: Rivet.ErrorMetadata | undefined; } diff --git a/sdks/full/typescript/types/serialization/resources/common/types/ErrorBody.d.ts b/sdks/full/typescript/types/serialization/resources/common/types/ErrorBody.d.ts index db1ce38c7..5999c4f0c 100644 --- a/sdks/full/typescript/types/serialization/resources/common/types/ErrorBody.d.ts +++ b/sdks/full/typescript/types/serialization/resources/common/types/ErrorBody.d.ts @@ -9,6 +9,7 @@ export declare namespace ErrorBody { interface Raw { code: string; message: string; + ray_id: string; documentation?: string | null; metadata?: (serializers.ErrorMetadata.Raw | undefined) | null; } diff --git a/sdks/runtime/go/types.go b/sdks/runtime/go/types.go index 83f85d878..fefe11d8c 100644 --- a/sdks/runtime/go/types.go +++ b/sdks/runtime/go/types.go @@ -14,6 +14,7 @@ type DisplayName = string type ErrorBody struct { Code string `json:"code"` Message string `json:"message"` + RayId string `json:"ray_id"` Documentation *string `json:"documentation,omitempty"` Metadata *ErrorMetadata `json:"metadata,omitempty"` diff --git a/sdks/runtime/openapi/openapi.yml b/sdks/runtime/openapi/openapi.yml index 371d3df1a..fe701e23b 100644 --- a/sdks/runtime/openapi/openapi.yml +++ b/sdks/runtime/openapi/openapi.yml @@ -1474,6 +1474,8 @@ components: type: string message: type: string + ray_id: + type: string documentation: type: string metadata: @@ -1481,6 +1483,7 @@ components: required: - code - message + - ray_id GeoCoord: type: object description: Geographical coordinates for a location on Planet Earth. diff --git a/sdks/runtime/openapi_compat/openapi.yml b/sdks/runtime/openapi_compat/openapi.yml index bf0383bc2..69615373a 100644 --- a/sdks/runtime/openapi_compat/openapi.yml +++ b/sdks/runtime/openapi_compat/openapi.yml @@ -37,9 +37,12 @@ components: type: string metadata: $ref: '#/components/schemas/ErrorMetadata' + ray_id: + type: string required: - code - message + - ray_id type: object ErrorMetadata: description: Unstructured metadata relating to an error. Must be manually parsed. diff --git a/sdks/runtime/rust/docs/ErrorBody.md b/sdks/runtime/rust/docs/ErrorBody.md index 11d49aafe..53e465941 100644 --- a/sdks/runtime/rust/docs/ErrorBody.md +++ b/sdks/runtime/rust/docs/ErrorBody.md @@ -8,6 +8,7 @@ Name | Type | Description | Notes **documentation** | Option<**String**> | | [optional] **message** | **String** | | **metadata** | Option<[**serde_json::Value**](.md)> | Unstructured metadata relating to an error. Must be manually parsed. | [optional] +**ray_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/runtime/rust/src/models/error_body.rs b/sdks/runtime/rust/src/models/error_body.rs index e8cb91e27..1ad1d6233 100644 --- a/sdks/runtime/rust/src/models/error_body.rs +++ b/sdks/runtime/rust/src/models/error_body.rs @@ -22,15 +22,18 @@ pub struct ErrorBody { /// Unstructured metadata relating to an error. Must be manually parsed. #[serde(rename = "metadata", default, with = "::serde_with::rust::double_option", skip_serializing_if = "Option::is_none")] pub metadata: Option>, + #[serde(rename = "ray_id")] + pub ray_id: String, } impl ErrorBody { - pub fn new(code: String, message: String) -> ErrorBody { + pub fn new(code: String, message: String, ray_id: String) -> ErrorBody { ErrorBody { code, documentation: None, message, metadata: None, + ray_id, } } } diff --git a/sdks/runtime/typescript/archive.tgz b/sdks/runtime/typescript/archive.tgz index fb45057e6..1465a8aba 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:c7d3c9fa927cdb76d6e31bb0839b642eb445bd0dbb9f0755aec3c37c4f609415 -size 371475 +oid sha256:23d4df8597c22c0ca25a2d61d02f76de775dbe477d8a9b992c4cab8db7113dbc +size 371647 diff --git a/sdks/runtime/typescript/src/api/resources/common/types/ErrorBody.ts b/sdks/runtime/typescript/src/api/resources/common/types/ErrorBody.ts index 8e7c2514d..e820bea2e 100644 --- a/sdks/runtime/typescript/src/api/resources/common/types/ErrorBody.ts +++ b/sdks/runtime/typescript/src/api/resources/common/types/ErrorBody.ts @@ -7,6 +7,7 @@ import * as Rivet from "../../.."; export interface ErrorBody { code: string; message: string; + rayId: string; documentation?: string; metadata?: Rivet.ErrorMetadata | undefined; } diff --git a/sdks/runtime/typescript/src/serialization/resources/common/types/ErrorBody.ts b/sdks/runtime/typescript/src/serialization/resources/common/types/ErrorBody.ts index 522f9d39b..c36a596cf 100644 --- a/sdks/runtime/typescript/src/serialization/resources/common/types/ErrorBody.ts +++ b/sdks/runtime/typescript/src/serialization/resources/common/types/ErrorBody.ts @@ -10,6 +10,7 @@ export const ErrorBody: core.serialization.ObjectSchema (await import("../../..")).ErrorMetadata).optional(), }); @@ -18,6 +19,7 @@ export declare namespace ErrorBody { interface Raw { code: string; message: string; + ray_id: string; documentation?: string | null; metadata?: (serializers.ErrorMetadata.Raw | undefined) | null; } diff --git a/svc/Cargo.lock b/svc/Cargo.lock index 5a818034e..29ecbf57e 100644 --- a/svc/Cargo.lock +++ b/svc/Cargo.lock @@ -107,6 +107,7 @@ dependencies = [ "cluster-datacenter-resolve-for-name-id", "cluster-get", "cluster-list", + "cluster-server-destroy-with-filter", "cluster-server-get", "cluster-server-list", "http 0.2.12", @@ -2556,6 +2557,17 @@ dependencies = [ "sqlx", ] +[[package]] +name = "cluster-server-destroy-with-filter" +version = "0.0.1" +dependencies = [ + "chirp-client", + "chirp-worker", + "cluster-server-list", + "rivet-operation", + "sqlx", +] + [[package]] name = "cluster-server-get" version = "0.0.1" diff --git a/svc/Cargo.toml b/svc/Cargo.toml index 87936aaae..e133d3da7 100644 --- a/svc/Cargo.toml +++ b/svc/Cargo.toml @@ -69,6 +69,7 @@ members = [ "pkg/cluster/ops/get-for-game", "pkg/cluster/ops/list", "pkg/cluster/ops/resolve-for-name-id", + "pkg/cluster/ops/server-destroy-with-filter", "pkg/cluster/ops/server-get", "pkg/cluster/ops/server-list", "pkg/cluster/ops/server-resolve-for-ip", diff --git a/svc/api/admin/Cargo.toml b/svc/api/admin/Cargo.toml index 3ae843f79..d06d4be36 100644 --- a/svc/api/admin/Cargo.toml +++ b/svc/api/admin/Cargo.toml @@ -44,6 +44,7 @@ util-mm = { package = "rivet-util-mm", path = "../../pkg/mm/util" } cluster-get = { path = "../../pkg/cluster/ops/get" } cluster-list = { path = "../../pkg/cluster/ops/list" } cluster-server-get = { path = "../../pkg/cluster/ops/server-get" } +cluster-server-destroy-with-filter = { path = "../../pkg/cluster/ops/server-destroy-with-filter" } cluster-server-list = { path = "../../pkg/cluster/ops/server-list" } cluster-datacenter-list = { path = "../../pkg/cluster/ops/datacenter-list" } cluster-datacenter-get = { path = "../../pkg/cluster/ops/datacenter-get" } diff --git a/svc/api/admin/src/route/clusters/servers.rs b/svc/api/admin/src/route/clusters/servers.rs index 6fe5b6373..f0a8110f2 100644 --- a/svc/api/admin/src/route/clusters/servers.rs +++ b/svc/api/admin/src/route/clusters/servers.rs @@ -109,3 +109,20 @@ pub async fn taint( Ok(json!({})) } + +// MARK: GET /clusters/{cluster_id}/servers/destroy +pub async fn destroy( + ctx: Ctx, + cluster_id: Uuid, + _body: serde_json::Value, + query: ServerFilterQuery, +) -> GlobalResult { + let filter = query.convert_to_proto(&ctx, cluster_id).await?; + + op!([ctx] cluster_server_destroy_with_filter { + filter: Some(filter) + }) + .await?; + + Ok(json!({})) +} diff --git a/svc/api/admin/src/route/mod.rs b/svc/api/admin/src/route/mod.rs index ffbd7e813..7e26c83d6 100644 --- a/svc/api/admin/src/route/mod.rs +++ b/svc/api/admin/src/route/mod.rs @@ -47,6 +47,13 @@ define_router! { ), }, + "clusters" / Uuid / "servers" / "destroy": { + POST: clusters::servers::destroy( + 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/ops/server-destroy-with-filter/Cargo.toml b/svc/pkg/cluster/ops/server-destroy-with-filter/Cargo.toml new file mode 100644 index 000000000..4e4ebfa27 --- /dev/null +++ b/svc/pkg/cluster/ops/server-destroy-with-filter/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "cluster-server-destroy-with-filter" +version = "0.0.1" +edition = "2021" +authors = ["Rivet Gaming, LLC "] +license = "Apache-2.0" + +[dependencies] +chirp-client = { path = "../../../../../lib/chirp/client" } +rivet-operation = { path = "../../../../../lib/operation/core" } +cluster-server-list = { path = "../server-list" } + +[dependencies.sqlx] +version = "0.7" +default-features = false + +[dev-dependencies] +chirp-worker = { path = "../../../../../lib/chirp/worker" } diff --git a/svc/pkg/cluster/ops/server-destroy-with-filter/Service.toml b/svc/pkg/cluster/ops/server-destroy-with-filter/Service.toml new file mode 100644 index 000000000..12aba4dd1 --- /dev/null +++ b/svc/pkg/cluster/ops/server-destroy-with-filter/Service.toml @@ -0,0 +1,7 @@ +[service] +name = "cluster-server-destroy-with-filter" + +[runtime] +kind = "rust" + +[operation] diff --git a/svc/pkg/cluster/ops/server-destroy-with-filter/src/lib.rs b/svc/pkg/cluster/ops/server-destroy-with-filter/src/lib.rs new file mode 100644 index 000000000..696452eec --- /dev/null +++ b/svc/pkg/cluster/ops/server-destroy-with-filter/src/lib.rs @@ -0,0 +1,59 @@ +use proto::backend::pkg::*; +use rivet_operation::prelude::*; +use std::collections::HashSet; + +#[operation(name = "cluster-server-destroy-with-filter")] +pub async fn handle( + ctx: OperationContext, +) -> GlobalResult { + let filter = unwrap!(ctx.filter.clone()); + + let servers_res = op!([ctx] cluster_server_list { + filter: Some(filter) + }) + .await?; + + // Flag as destroyed + let server_ids = servers_res + .servers + .iter() + .filter_map(|x| x.server_id) + .map(|x| x.as_uuid()) + .collect::>(); + sql_execute!( + [ctx] + " + UPDATE db_cluster.servers + SET cloud_destroy_ts = $2 + WHERE server_id = ANY($1) + ", + &server_ids, + util::timestamp::now(), + ) + .await?; + + // Destroy server + for server_id in &server_ids { + msg!([ctx] cluster::msg::server_destroy(server_id) { + server_id: Some(server_id.clone().into()), + force: false, + }) + .await?; + } + + // Trigger scale event + let dc_ids = servers_res + .servers + .iter() + .filter_map(|x| x.datacenter_id) + .map(|x| x.as_uuid()) + .collect::>(); + for dc_id in dc_ids { + msg!([ctx] cluster::msg::datacenter_scale(dc_id) { + datacenter_id: Some(dc_id.into()), + }) + .await?; + } + + Ok(cluster::server_destroy_with_filter::Response {}) +} diff --git a/svc/pkg/cluster/ops/server-destroy-with-filter/tests/integration.rs b/svc/pkg/cluster/ops/server-destroy-with-filter/tests/integration.rs new file mode 100644 index 000000000..d7d641e21 --- /dev/null +++ b/svc/pkg/cluster/ops/server-destroy-with-filter/tests/integration.rs @@ -0,0 +1,6 @@ +use chirp_worker::prelude::*; + +#[worker_test] +async fn basic(ctx: TestCtx) { + // TODO: +} diff --git a/svc/pkg/cluster/types/server-destroy-with-filter.proto b/svc/pkg/cluster/types/server-destroy-with-filter.proto new file mode 100644 index 000000000..7dec0b41c --- /dev/null +++ b/svc/pkg/cluster/types/server-destroy-with-filter.proto @@ -0,0 +1,14 @@ +syntax = "proto3"; + +package rivet.backend.pkg.cluster.server_destroy_with_filter; + +import "proto/common.proto"; +import "proto/backend/cluster.proto"; + +message Request { + rivet.backend.cluster.ServerFilter filter = 1; +} + +message Response { + +}