diff --git a/fern/definition/servers/__package__.yml b/fern/definition/servers/__package__.yml index 8dd2b6cb81..39d5e92dbd 100644 --- a/fern/definition/servers/__package__.yml +++ b/fern/definition/servers/__package__.yml @@ -17,6 +17,18 @@ service: type: uuid response: GetServerResponse + list: + path: "" + method: GET + docs: >- + Lists all servers associated with the token used. Can be filtered by + tags in the query string. + request: + name: GetServersRequest + query-parameters: + tags: optional + response: ListServersResponse + create: path: "" method: POST @@ -44,18 +56,6 @@ service: type: optional response: DestroyServerResponse - list: - path: /list - method: GET - docs: >- - Lists all servers associated with the token used. Can be filtered by - tags in the query string. - request: - name: GetServersRequest - query-parameters: - tags: optional - response: ListServersResponse - types: GetServerResponse: properties: diff --git a/fern/definition/servers/logs.yml b/fern/definition/servers/logs.yml new file mode 100644 index 0000000000..4f3b1088e4 --- /dev/null +++ b/fern/definition/servers/logs.yml @@ -0,0 +1,43 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/fern-api/fern/main/fern.schema.json + +imports: + commons: ../common.yml + uploadCommons: ../upload/common.yml + cloudCommons: ../cloud/common.yml + +service: + auth: true + base-path: /servers + endpoints: + getServerLogs: + path: /{server_id}/logs + method: GET + docs: >- + Returns the logs for a given server. + path-parameters: + server_id: + type: uuid + request: + name: GetServerLogsRequest + query-parameters: + stream: LogStream + watch_index: + docs: A query parameter denoting the requests watch index. + type: optional + response: GetServerLogsResponse + +types: + GetServerLogsResponse: + properties: + lines: + docs: Sorted old to new. + type: list + timestamps: + docs: Sorted old to new. + type: list + watch: commons.WatchResponse + + LogStream: + enum: + - std_out + - std_err diff --git a/infra/tf/vector/vector.tf b/infra/tf/vector/vector.tf index b0d5acf1db..90d3e2c4a2 100644 --- a/infra/tf/vector/vector.tf +++ b/infra/tf/vector/vector.tf @@ -82,6 +82,24 @@ resource "helm_release" "vector" { } } + dynamic_servers = { + type = "filter" + inputs = ["vector", "tcp_json"] + condition = { + type = "vrl" + source = ".source == \"dynamic_servers\"" + } + } + + ds_fix_id = { + type = "remap" + inputs = ["dynamic_servers"] + source = <<-EOF + .server_id = .run_id + del(.run_id) + EOF + } + opengb_worker = { type = "filter" inputs = ["http_json"] @@ -120,6 +138,28 @@ resource "helm_release" "vector" { } } + clickhouse_ds_logs = { + type = "clickhouse" + inputs = ["ds_fix_id"] + compression = "gzip" + database = "db_ds_log" + endpoint = "https://${var.clickhouse_host}:${var.clickhouse_port_https}" + table = "server_logs" + auth = { + strategy = "basic" + user = "vector" + # Escape values for Vector + password = replace(module.secrets.values["clickhouse/users/vector/password"], "$", "$$") + } + tls = local.clickhouse_k8s ? { + ca_file = "/usr/local/share/ca-certificates/clickhouse-ca.crt" + } : {} + batch = { + # Speed up for realtime-ish logs + timeout_secs = 1.0 + } + } + clickhouse_opengb_logs = { type = "clickhouse" inputs = ["opengb_worker"] diff --git a/lib/bolt/Cargo.lock b/lib/bolt/Cargo.lock index 0486b32444..9c6f56949e 100644 --- a/lib/bolt/Cargo.lock +++ b/lib/bolt/Cargo.lock @@ -2794,9 +2794,9 @@ checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "version_check" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "want" diff --git a/lib/job-runner/src/log_shipper.rs b/lib/job-runner/src/log_shipper.rs index 01a11b82c8..3ed285d2db 100644 --- a/lib/job-runner/src/log_shipper.rs +++ b/lib/job-runner/src/log_shipper.rs @@ -36,6 +36,7 @@ pub struct LogShipper { pub job_run_id: String, pub nomad_task_name: String, + pub runner: String, } impl LogShipper { @@ -89,12 +90,12 @@ impl LogShipper { while let Result::Ok(message) = self.msg_rx.recv() { let vector_message = VectorMessage { - source: "job_run", + source: self.runner.as_str(), run_id: self.job_run_id.as_str(), task: self.nomad_task_name.as_str(), stream_type: message.stream_type as u8, ts: message.ts, - message: &message.message, + message: message.message.as_str(), }; serde_json::to_writer(&mut stream, &vector_message)?; @@ -110,7 +111,7 @@ impl LogShipper { /// Vector-compatible message format #[derive(Serialize)] struct VectorMessage<'a> { - source: &'static str, + source: &'a str, run_id: &'a str, task: &'a str, stream_type: u8, diff --git a/lib/job-runner/src/main.rs b/lib/job-runner/src/main.rs index b537c5cb0a..f6ba0bb7fa 100644 --- a/lib/job-runner/src/main.rs +++ b/lib/job-runner/src/main.rs @@ -28,6 +28,7 @@ fn main() -> anyhow::Result<()> { let root_user_enabled = std::env::var("NOMAD_META_root_user_enabled") .context("NOMAD_META_root_user_enabled")? == "1"; + let runner = std::env::var("NOMAD_META_runner").unwrap_or("job_run".to_string()); let (shutdown_tx, shutdown_rx) = mpsc::sync_channel(1); @@ -39,6 +40,7 @@ fn main() -> anyhow::Result<()> { msg_rx, job_run_id, nomad_task_name, + runner, }; let log_shipper_thread = log_shipper.spawn(); @@ -226,15 +228,14 @@ fn ship_logs( for line in stream.lines() { // Throttle if let Err(err) = throttle_short.tick() { - if err.first_throttle_in_window { - if send_message( + if err.first_throttle_in_window + && send_message( &msg_tx, Some(&mut throttle_error), stream_type, format_rate_limit(err.time_remaining), ) { - break; - } + break; } continue; } else if let Err(err) = throttle_long.tick() { diff --git a/proto/backend/ds/log.proto b/proto/backend/ds/log.proto new file mode 100644 index 0000000000..3bbb98be14 --- /dev/null +++ b/proto/backend/ds/log.proto @@ -0,0 +1,19 @@ +syntax = "proto3"; + +package rivet.backend.ds.log; + +import "proto/common.proto"; + +enum StreamType { + STD_OUT = 0; + STD_ERR = 1; +} + +message LogEntry { + // Timestamp the log was received (in nanoseconds). + int64 nts = 1; + + // Message that was logged. + bytes message = 3; +} + diff --git a/scripts/openapi/gen_rust.sh b/scripts/openapi/gen_rust.sh index 7ff3bc1925..d0dfd3314b 100755 --- a/scripts/openapi/gen_rust.sh +++ b/scripts/openapi/gen_rust.sh @@ -21,6 +21,7 @@ docker run --rm \ if [ "$FERN_GROUP" == "full" ]; then # Fix OpenAPI bug (https://github.com/OpenAPITools/openapi-generator/issues/14171) sed -i 's/CloudGamesLogStream/crate::models::CloudGamesLogStream/' "$GEN_PATH_RUST/src/apis/cloud_games_matchmaker_api.rs" + sed -i 's/ServersLogStream/crate::models::ServersLogStream/' "$GEN_PATH_RUST/src/apis/servers_logs_api.rs" sed -i 's/AdminClustersPoolType/crate::models::AdminClustersPoolType/' "$GEN_PATH_RUST/src/apis/admin_clusters_servers_api.rs" # Create variant specifically for the CLI diff --git a/sdks/full/go/servers/client/client.go b/sdks/full/go/servers/client/client.go index da5b21a21f..72a88d1550 100644 --- a/sdks/full/go/servers/client/client.go +++ b/sdks/full/go/servers/client/client.go @@ -16,6 +16,7 @@ import ( core "sdk/core" servers "sdk/servers" builds "sdk/servers/builds" + logs "sdk/servers/logs" ) type Client struct { @@ -24,6 +25,7 @@ type Client struct { header http.Header Builds *builds.Client + Logs *logs.Client } func NewClient(opts ...core.ClientOption) *Client { @@ -36,6 +38,7 @@ func NewClient(opts ...core.ClientOption) *Client { caller: core.NewCaller(options.HTTPClient), header: options.ToHeader(), Builds: builds.NewClient(opts...), + Logs: logs.NewClient(opts...), } } @@ -119,14 +122,22 @@ func (c *Client) Get(ctx context.Context, serverId uuid.UUID) (*servers.GetServe return response, nil } -// Create a new dynamic server. -func (c *Client) Create(ctx context.Context, request *servers.CreateServerRequest) (*servers.CreateServerResponse, error) { +// Lists all servers associated with the token used. Can be filtered by tags in the query string. +func (c *Client) List(ctx context.Context, request *servers.GetServersRequest) (*servers.ListServersResponse, error) { baseURL := "https://api.rivet.gg" if c.baseURL != "" { baseURL = c.baseURL } endpointURL := baseURL + "/" + "servers" + queryParams := make(url.Values) + if request.Tags != nil { + queryParams.Add("tags", fmt.Sprintf("%v", *request.Tags)) + } + if len(queryParams) > 0 { + endpointURL += "?" + queryParams.Encode() + } + errorDecoder := func(statusCode int, body io.Reader) error { raw, err := io.ReadAll(body) if err != nil { @@ -181,14 +192,13 @@ func (c *Client) Create(ctx context.Context, request *servers.CreateServerReques return apiError } - var response *servers.CreateServerResponse + var response *servers.ListServersResponse if err := c.caller.Call( ctx, &core.CallParams{ URL: endpointURL, - Method: http.MethodPost, + Method: http.MethodGet, Headers: c.header, - Request: request, Response: &response, ErrorDecoder: errorDecoder, }, @@ -198,23 +208,13 @@ func (c *Client) Create(ctx context.Context, request *servers.CreateServerReques return response, nil } -// Destroy a dynamic server. -// -// The id of the server to destroy -func (c *Client) Destroy(ctx context.Context, serverId uuid.UUID, request *servers.DestroyServerRequest) (*servers.DestroyServerResponse, error) { +// Create a new dynamic server. +func (c *Client) Create(ctx context.Context, request *servers.CreateServerRequest) (*servers.CreateServerResponse, error) { baseURL := "https://api.rivet.gg" if c.baseURL != "" { baseURL = c.baseURL } - endpointURL := fmt.Sprintf(baseURL+"/"+"servers/%v", serverId) - - queryParams := make(url.Values) - if request.OverrideKillTimeout != nil { - queryParams.Add("override_kill_timeout", fmt.Sprintf("%v", *request.OverrideKillTimeout)) - } - if len(queryParams) > 0 { - endpointURL += "?" + queryParams.Encode() - } + endpointURL := baseURL + "/" + "servers" errorDecoder := func(statusCode int, body io.Reader) error { raw, err := io.ReadAll(body) @@ -270,13 +270,14 @@ func (c *Client) Destroy(ctx context.Context, serverId uuid.UUID, request *serve return apiError } - var response *servers.DestroyServerResponse + var response *servers.CreateServerResponse if err := c.caller.Call( ctx, &core.CallParams{ URL: endpointURL, - Method: http.MethodDelete, + Method: http.MethodPost, Headers: c.header, + Request: request, Response: &response, ErrorDecoder: errorDecoder, }, @@ -286,17 +287,19 @@ func (c *Client) Destroy(ctx context.Context, serverId uuid.UUID, request *serve return response, nil } -// Lists all servers associated with the token used. Can be filtered by tags in the query string. -func (c *Client) List(ctx context.Context, request *servers.GetServersRequest) (*servers.ListServersResponse, error) { +// Destroy a dynamic server. +// +// The id of the server to destroy +func (c *Client) Destroy(ctx context.Context, serverId uuid.UUID, request *servers.DestroyServerRequest) (*servers.DestroyServerResponse, error) { baseURL := "https://api.rivet.gg" if c.baseURL != "" { baseURL = c.baseURL } - endpointURL := baseURL + "/" + "servers/list" + endpointURL := fmt.Sprintf(baseURL+"/"+"servers/%v", serverId) queryParams := make(url.Values) - if request.Tags != nil { - queryParams.Add("tags", fmt.Sprintf("%v", *request.Tags)) + if request.OverrideKillTimeout != nil { + queryParams.Add("override_kill_timeout", fmt.Sprintf("%v", *request.OverrideKillTimeout)) } if len(queryParams) > 0 { endpointURL += "?" + queryParams.Encode() @@ -356,12 +359,12 @@ func (c *Client) List(ctx context.Context, request *servers.GetServersRequest) ( return apiError } - var response *servers.ListServersResponse + var response *servers.DestroyServerResponse if err := c.caller.Call( ctx, &core.CallParams{ URL: endpointURL, - Method: http.MethodGet, + Method: http.MethodDelete, Headers: c.header, Response: &response, ErrorDecoder: errorDecoder, diff --git a/sdks/full/go/servers/logs.go b/sdks/full/go/servers/logs.go new file mode 100644 index 0000000000..a3016bdc26 --- /dev/null +++ b/sdks/full/go/servers/logs.go @@ -0,0 +1,71 @@ +// This file was auto-generated by Fern from our API Definition. + +package servers + +import ( + json "encoding/json" + fmt "fmt" + sdk "sdk" + core "sdk/core" +) + +type GetServerLogsRequest struct { + Stream LogStream `json:"-"` + // A query parameter denoting the requests watch index. + WatchIndex *string `json:"-"` +} + +type GetServerLogsResponse struct { + // Sorted old to new. + Lines []string `json:"lines,omitempty"` + // Sorted old to new. + Timestamps []string `json:"timestamps,omitempty"` + Watch *sdk.WatchResponse `json:"watch,omitempty"` + + _rawJSON json.RawMessage +} + +func (g *GetServerLogsResponse) UnmarshalJSON(data []byte) error { + type unmarshaler GetServerLogsResponse + var value unmarshaler + if err := json.Unmarshal(data, &value); err != nil { + return err + } + *g = GetServerLogsResponse(value) + g._rawJSON = json.RawMessage(data) + return nil +} + +func (g *GetServerLogsResponse) String() string { + if len(g._rawJSON) > 0 { + if value, err := core.StringifyJSON(g._rawJSON); err == nil { + return value + } + } + if value, err := core.StringifyJSON(g); err == nil { + return value + } + return fmt.Sprintf("%#v", g) +} + +type LogStream string + +const ( + LogStreamStdOut LogStream = "std_out" + LogStreamStdErr LogStream = "std_err" +) + +func NewLogStreamFromString(s string) (LogStream, error) { + switch s { + case "std_out": + return LogStreamStdOut, nil + case "std_err": + return LogStreamStdErr, nil + } + var t LogStream + return "", fmt.Errorf("%s is not a valid %T", s, t) +} + +func (l LogStream) Ptr() *LogStream { + return &l +} diff --git a/sdks/full/go/servers/logs/client.go b/sdks/full/go/servers/logs/client.go new file mode 100644 index 0000000000..704a382916 --- /dev/null +++ b/sdks/full/go/servers/logs/client.go @@ -0,0 +1,123 @@ +// This file was auto-generated by Fern from our API Definition. + +package logs + +import ( + bytes "bytes" + context "context" + json "encoding/json" + errors "errors" + fmt "fmt" + uuid "github.com/google/uuid" + io "io" + http "net/http" + url "net/url" + sdk "sdk" + core "sdk/core" + servers "sdk/servers" +) + +type Client struct { + baseURL string + caller *core.Caller + header http.Header +} + +func NewClient(opts ...core.ClientOption) *Client { + options := core.NewClientOptions() + for _, opt := range opts { + opt(options) + } + return &Client{ + baseURL: options.BaseURL, + caller: core.NewCaller(options.HTTPClient), + header: options.ToHeader(), + } +} + +// Returns the logs for a given server. +func (c *Client) GetServerLogs(ctx context.Context, serverId uuid.UUID, request *servers.GetServerLogsRequest) (*servers.GetServerLogsResponse, error) { + baseURL := "https://api.rivet.gg" + if c.baseURL != "" { + baseURL = c.baseURL + } + endpointURL := fmt.Sprintf(baseURL+"/"+"servers/%v/logs", serverId) + + queryParams := make(url.Values) + queryParams.Add("stream", fmt.Sprintf("%v", request.Stream)) + if request.WatchIndex != nil { + queryParams.Add("watch_index", fmt.Sprintf("%v", *request.WatchIndex)) + } + 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 *servers.GetServerLogsResponse + 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 +} diff --git a/sdks/full/openapi/openapi.yml b/sdks/full/openapi/openapi.yml index a573a0e225..4bbc8c7cae 100644 --- a/sdks/full/openapi/openapi.yml +++ b/sdks/full/openapi/openapi.yml @@ -5000,19 +5000,26 @@ paths: $ref: '#/components/schemas/ErrorBody' security: *ref_0 /servers: - post: - description: Create a new dynamic server. - operationId: servers_create + get: + description: >- + Lists all servers associated with the token used. Can be filtered by + tags in the query string. + operationId: servers_list tags: - Servers - parameters: [] + parameters: + - name: tags + in: query + required: false + schema: + type: string responses: '200': description: '' content: application/json: schema: - $ref: '#/components/schemas/ServersCreateServerResponse' + $ref: '#/components/schemas/ServersListServersResponse' '400': description: '' content: @@ -5050,33 +5057,19 @@ paths: schema: $ref: '#/components/schemas/ErrorBody' security: *ref_0 - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/ServersCreateServerRequest' - /servers/list: - get: - description: >- - Lists all servers associated with the token used. Can be filtered by - tags in the query string. - operationId: servers_list + post: + description: Create a new dynamic server. + operationId: servers_create tags: - Servers - parameters: - - name: tags - in: query - required: false - schema: - type: string + parameters: [] responses: '200': description: '' content: application/json: schema: - $ref: '#/components/schemas/ServersListServersResponse' + $ref: '#/components/schemas/ServersCreateServerResponse' '400': description: '' content: @@ -5114,6 +5107,12 @@ paths: schema: $ref: '#/components/schemas/ErrorBody' security: *ref_0 + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ServersCreateServerRequest' /admin/clusters/{cluster_id}/datacenters: get: description: Get datacenters of a cluster @@ -9312,6 +9311,74 @@ paths: schema: $ref: '#/components/schemas/ErrorBody' security: *ref_0 + /servers/{server_id}/logs: + get: + description: Returns the logs for a given server. + operationId: servers_logs_getServerLogs + tags: + - ServersLogs + parameters: + - name: server_id + in: path + required: true + schema: + type: string + format: uuid + - name: stream + in: query + required: true + schema: + $ref: '#/components/schemas/ServersLogStream' + - name: watch_index + in: query + description: A query parameter denoting the requests watch index. + required: false + schema: + type: string + responses: + '200': + description: '' + content: + application/json: + schema: + $ref: '#/components/schemas/ServersGetServerLogsResponse' + '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 components: schemas: AdminLoginRequest: @@ -14118,6 +14185,30 @@ components: ServersHostRouting: type: object properties: {} + ServersGetServerLogsResponse: + type: object + properties: + lines: + type: array + items: + type: string + description: Sorted old to new. + timestamps: + type: array + items: + type: string + description: Sorted old to new. + watch: + $ref: '#/components/schemas/WatchResponse' + required: + - lines + - timestamps + - watch + ServersLogStream: + type: string + enum: + - std_out + - std_err UploadPresignedRequest: type: object description: >- diff --git a/sdks/full/openapi_compat/openapi.yml b/sdks/full/openapi_compat/openapi.yml index d0e5be518a..ea147c29a4 100644 --- a/sdks/full/openapi_compat/openapi.yml +++ b/sdks/full/openapi_compat/openapi.yml @@ -4531,6 +4531,25 @@ components: ServersGameGuardRouting: properties: {} type: object + ServersGetServerLogsResponse: + properties: + lines: + description: Sorted old to new. + items: + type: string + type: array + timestamps: + description: Sorted old to new. + items: + type: string + type: array + watch: + $ref: '#/components/schemas/WatchResponse' + required: + - lines + - timestamps + - watch + type: object ServersGetServerResponse: properties: server: @@ -4561,6 +4580,11 @@ components: required: - servers type: object + ServersLogStream: + enum: + - std_out + - std_err + type: string ServersNetwork: properties: mode: @@ -13506,22 +13530,22 @@ paths: tags: - PortalGames /servers: - post: - description: Create a new dynamic server. - operationId: servers_create - parameters: [] - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/ServersCreateServerRequest' - required: true + get: + description: Lists all servers associated with the token used. Can be filtered + by tags in the query string. + operationId: servers_list + parameters: + - in: query + name: tags + required: false + schema: + type: string responses: '200': content: application/json: schema: - $ref: '#/components/schemas/ServersCreateServerResponse' + $ref: '#/components/schemas/ServersListServersResponse' description: '' '400': content: @@ -13562,23 +13586,22 @@ paths: security: *id001 tags: - Servers - /servers/builds: - get: - description: Lists all builds of the game associated with the token used. Can - be filtered by tags in the query string. - operationId: servers_builds_listBuilds - parameters: - - in: query - name: tags - required: false - schema: - type: string + post: + description: Create a new dynamic server. + operationId: servers_create + parameters: [] + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ServersCreateServerRequest' + required: true responses: '200': content: application/json: schema: - $ref: '#/components/schemas/ServersListBuildsResponse' + $ref: '#/components/schemas/ServersCreateServerResponse' description: '' '400': content: @@ -13618,23 +13641,24 @@ paths: description: '' security: *id001 tags: - - ServersBuilds - post: - description: Creates a new game build for the given game. - operationId: servers_builds_prepareBuild - parameters: [] - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/ServersCreateBuildRequest' - required: true + - Servers + /servers/builds: + get: + description: Lists all builds of the game associated with the token used. Can + be filtered by tags in the query string. + operationId: servers_builds_listBuilds + parameters: + - in: query + name: tags + required: false + schema: + type: string responses: '200': content: application/json: schema: - $ref: '#/components/schemas/ServersCreateBuildResponse' + $ref: '#/components/schemas/ServersListBuildsResponse' description: '' '400': content: @@ -13675,23 +13699,22 @@ paths: security: *id001 tags: - ServersBuilds - /servers/list: - get: - description: Lists all servers associated with the token used. Can be filtered - by tags in the query string. - operationId: servers_list - parameters: - - in: query - name: tags - required: false - schema: - type: string + post: + description: Creates a new game build for the given game. + operationId: servers_builds_prepareBuild + parameters: [] + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ServersCreateBuildRequest' + required: true responses: '200': content: application/json: schema: - $ref: '#/components/schemas/ServersListServersResponse' + $ref: '#/components/schemas/ServersCreateBuildResponse' description: '' '400': content: @@ -13731,7 +13754,7 @@ paths: description: '' security: *id001 tags: - - Servers + - ServersBuilds /servers/uploads/{upload_id}/complete: post: description: Marks an upload as complete. @@ -13964,6 +13987,74 @@ paths: security: *id001 tags: - Servers + /servers/{server_id}/logs: + get: + description: Returns the logs for a given server. + operationId: servers_logs_getServerLogs + parameters: + - in: path + name: server_id + required: true + schema: + format: uuid + type: string + - in: query + name: stream + required: true + schema: + $ref: '#/components/schemas/ServersLogStream' + - description: A query parameter denoting the requests watch index. + in: query + name: watch_index + required: false + schema: + type: string + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/ServersGetServerLogsResponse' + 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: + - ServersLogs servers: - description: Production url: https://api.rivet.gg diff --git a/sdks/full/rust-cli/.openapi-generator/FILES b/sdks/full/rust-cli/.openapi-generator/FILES index 0a29db9a8c..499eb1b382 100644 --- a/sdks/full/rust-cli/.openapi-generator/FILES +++ b/sdks/full/rust-cli/.openapi-generator/FILES @@ -357,9 +357,12 @@ docs/ServersCreateServerPortRequest.md docs/ServersCreateServerRequest.md docs/ServersCreateServerResponse.md docs/ServersDestroyServerResponse.md +docs/ServersGetServerLogsResponse.md docs/ServersGetServerResponse.md docs/ServersListBuildsResponse.md docs/ServersListServersResponse.md +docs/ServersLogStream.md +docs/ServersLogsApi.md docs/ServersNetwork.md docs/ServersNetworkMode.md docs/ServersPort.md @@ -415,6 +418,7 @@ src/apis/provision_datacenters_api.rs src/apis/provision_servers_api.rs src/apis/servers_api.rs src/apis/servers_builds_api.rs +src/apis/servers_logs_api.rs src/lib.rs src/models/admin_clusters_build_delivery_method.rs src/models/admin_clusters_cluster.rs @@ -730,9 +734,11 @@ src/models/servers_create_server_port_request.rs src/models/servers_create_server_request.rs src/models/servers_create_server_response.rs src/models/servers_destroy_server_response.rs +src/models/servers_get_server_logs_response.rs src/models/servers_get_server_response.rs src/models/servers_list_builds_response.rs src/models/servers_list_servers_response.rs +src/models/servers_log_stream.rs src/models/servers_network.rs src/models/servers_network_mode.rs src/models/servers_port.rs diff --git a/sdks/full/rust-cli/README.md b/sdks/full/rust-cli/README.md index 4fecaf0a6e..1d982febf3 100644 --- a/sdks/full/rust-cli/README.md +++ b/sdks/full/rust-cli/README.md @@ -170,10 +170,11 @@ Class | Method | HTTP request | Description *ServersApi* | [**servers_create**](docs/ServersApi.md#servers_create) | **POST** /servers | *ServersApi* | [**servers_destroy**](docs/ServersApi.md#servers_destroy) | **DELETE** /servers/{server_id} | *ServersApi* | [**servers_get**](docs/ServersApi.md#servers_get) | **GET** /servers/{server_id} | -*ServersApi* | [**servers_list**](docs/ServersApi.md#servers_list) | **GET** /servers/list | +*ServersApi* | [**servers_list**](docs/ServersApi.md#servers_list) | **GET** /servers | *ServersBuildsApi* | [**servers_builds_complete_build**](docs/ServersBuildsApi.md#servers_builds_complete_build) | **POST** /servers/uploads/{upload_id}/complete | *ServersBuildsApi* | [**servers_builds_list_builds**](docs/ServersBuildsApi.md#servers_builds_list_builds) | **GET** /servers/builds | *ServersBuildsApi* | [**servers_builds_prepare_build**](docs/ServersBuildsApi.md#servers_builds_prepare_build) | **POST** /servers/builds | +*ServersLogsApi* | [**servers_logs_get_server_logs**](docs/ServersLogsApi.md#servers_logs_get_server_logs) | **GET** /servers/{server_id}/logs | ## Documentation For Models @@ -491,9 +492,11 @@ Class | Method | HTTP request | Description - [ServersCreateServerRequest](docs/ServersCreateServerRequest.md) - [ServersCreateServerResponse](docs/ServersCreateServerResponse.md) - [ServersDestroyServerResponse](docs/ServersDestroyServerResponse.md) + - [ServersGetServerLogsResponse](docs/ServersGetServerLogsResponse.md) - [ServersGetServerResponse](docs/ServersGetServerResponse.md) - [ServersListBuildsResponse](docs/ServersListBuildsResponse.md) - [ServersListServersResponse](docs/ServersListServersResponse.md) + - [ServersLogStream](docs/ServersLogStream.md) - [ServersNetwork](docs/ServersNetwork.md) - [ServersNetworkMode](docs/ServersNetworkMode.md) - [ServersPort](docs/ServersPort.md) diff --git a/sdks/full/rust-cli/docs/ServersApi.md b/sdks/full/rust-cli/docs/ServersApi.md index 40ca6fcb9d..e596b32ffc 100644 --- a/sdks/full/rust-cli/docs/ServersApi.md +++ b/sdks/full/rust-cli/docs/ServersApi.md @@ -7,7 +7,7 @@ Method | HTTP request | Description [**servers_create**](ServersApi.md#servers_create) | **POST** /servers | [**servers_destroy**](ServersApi.md#servers_destroy) | **DELETE** /servers/{server_id} | [**servers_get**](ServersApi.md#servers_get) | **GET** /servers/{server_id} | -[**servers_list**](ServersApi.md#servers_list) | **GET** /servers/list | +[**servers_list**](ServersApi.md#servers_list) | **GET** /servers | diff --git a/sdks/full/rust-cli/docs/ServersGetServerLogsResponse.md b/sdks/full/rust-cli/docs/ServersGetServerLogsResponse.md new file mode 100644 index 0000000000..ed594b4b5f --- /dev/null +++ b/sdks/full/rust-cli/docs/ServersGetServerLogsResponse.md @@ -0,0 +1,13 @@ +# ServersGetServerLogsResponse + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**lines** | **Vec** | Sorted old to new. | +**timestamps** | **Vec** | Sorted old to new. | +**watch** | [**crate::models::WatchResponse**](WatchResponse.md) | | + +[[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/ServersLogStream.md b/sdks/full/rust-cli/docs/ServersLogStream.md new file mode 100644 index 0000000000..9706b84a3a --- /dev/null +++ b/sdks/full/rust-cli/docs/ServersLogStream.md @@ -0,0 +1,10 @@ +# ServersLogStream + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- + +[[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/ServersLogsApi.md b/sdks/full/rust-cli/docs/ServersLogsApi.md new file mode 100644 index 0000000000..ede5b693ee --- /dev/null +++ b/sdks/full/rust-cli/docs/ServersLogsApi.md @@ -0,0 +1,41 @@ +# \ServersLogsApi + +All URIs are relative to *https://api.rivet.gg* + +Method | HTTP request | Description +------------- | ------------- | ------------- +[**servers_logs_get_server_logs**](ServersLogsApi.md#servers_logs_get_server_logs) | **GET** /servers/{server_id}/logs | + + + +## servers_logs_get_server_logs + +> crate::models::ServersGetServerLogsResponse servers_logs_get_server_logs(server_id, stream, watch_index) + + +Returns the logs for a given server. + +### Parameters + + +Name | Type | Description | Required | Notes +------------- | ------------- | ------------- | ------------- | ------------- +**server_id** | **uuid::Uuid** | | [required] | +**stream** | [**ServersLogStream**](.md) | | [required] | +**watch_index** | Option<**String**> | A query parameter denoting the requests watch index. | | + +### Return type + +[**crate::models::ServersGetServerLogsResponse**](ServersGetServerLogsResponse.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) + diff --git a/sdks/full/rust-cli/src/apis/mod.rs b/sdks/full/rust-cli/src/apis/mod.rs index d267ce82f4..11b380d655 100644 --- a/sdks/full/rust-cli/src/apis/mod.rs +++ b/sdks/full/rust-cli/src/apis/mod.rs @@ -131,5 +131,6 @@ pub mod provision_datacenters_api; pub mod provision_servers_api; pub mod servers_api; pub mod servers_builds_api; +pub mod servers_logs_api; pub mod configuration; diff --git a/sdks/full/rust-cli/src/apis/servers_api.rs b/sdks/full/rust-cli/src/apis/servers_api.rs index aa98e6ee7e..003a515e6d 100644 --- a/sdks/full/rust-cli/src/apis/servers_api.rs +++ b/sdks/full/rust-cli/src/apis/servers_api.rs @@ -171,7 +171,7 @@ pub async fn servers_list(configuration: &configuration::Configuration, tags: Op let local_var_client = &local_var_configuration.client; - let local_var_uri_str = format!("{}/servers/list", local_var_configuration.base_path); + let local_var_uri_str = format!("{}/servers", local_var_configuration.base_path); 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) = tags { diff --git a/sdks/full/rust-cli/src/apis/servers_logs_api.rs b/sdks/full/rust-cli/src/apis/servers_logs_api.rs new file mode 100644 index 0000000000..1a2a016527 --- /dev/null +++ b/sdks/full/rust-cli/src/apis/servers_logs_api.rs @@ -0,0 +1,66 @@ +/* + * Rivet API + * + * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + * + * The version of the OpenAPI document: 0.0.1 + * + * Generated by: https://openapi-generator.tech + */ + + +use reqwest; + +use crate::apis::ResponseContent; +use super::{Error, configuration}; + + +/// struct for typed errors of method [`servers_logs_get_server_logs`] +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum ServersLogsGetServerLogsError { + 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), +} + + +/// Returns the logs for a given server. +pub async fn servers_logs_get_server_logs(configuration: &configuration::Configuration, server_id: &str, stream: crate::models::ServersLogStream, watch_index: Option<&str>) -> Result> { + let local_var_configuration = configuration; + + let local_var_client = &local_var_configuration.client; + + let local_var_uri_str = format!("{}/servers/{server_id}/logs", local_var_configuration.base_path, server_id=crate::apis::urlencode(server_id)); + let mut local_var_req_builder = local_var_client.request(reqwest::Method::GET, local_var_uri_str.as_str()); + + local_var_req_builder = local_var_req_builder.query(&[("stream", &stream.to_string())]); + if let Some(ref local_var_str) = watch_index { + local_var_req_builder = local_var_req_builder.query(&[("watch_index", &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)) + } +} + diff --git a/sdks/full/rust-cli/src/models/mod.rs b/sdks/full/rust-cli/src/models/mod.rs index a04299340c..a15d7977dc 100644 --- a/sdks/full/rust-cli/src/models/mod.rs +++ b/sdks/full/rust-cli/src/models/mod.rs @@ -624,12 +624,16 @@ pub mod servers_create_server_response; pub use self::servers_create_server_response::ServersCreateServerResponse; pub mod servers_destroy_server_response; pub use self::servers_destroy_server_response::ServersDestroyServerResponse; +pub mod servers_get_server_logs_response; +pub use self::servers_get_server_logs_response::ServersGetServerLogsResponse; pub mod servers_get_server_response; pub use self::servers_get_server_response::ServersGetServerResponse; pub mod servers_list_builds_response; pub use self::servers_list_builds_response::ServersListBuildsResponse; pub mod servers_list_servers_response; pub use self::servers_list_servers_response::ServersListServersResponse; +pub mod servers_log_stream; +pub use self::servers_log_stream::ServersLogStream; pub mod servers_network; pub use self::servers_network::ServersNetwork; pub mod servers_network_mode; diff --git a/sdks/full/rust-cli/src/models/servers_get_server_logs_response.rs b/sdks/full/rust-cli/src/models/servers_get_server_logs_response.rs new file mode 100644 index 0000000000..dd6df5a770 --- /dev/null +++ b/sdks/full/rust-cli/src/models/servers_get_server_logs_response.rs @@ -0,0 +1,36 @@ +/* + * Rivet API + * + * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + * + * The version of the OpenAPI document: 0.0.1 + * + * Generated by: https://openapi-generator.tech + */ + + + + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +pub struct ServersGetServerLogsResponse { + /// Sorted old to new. + #[serde(rename = "lines")] + pub lines: Vec, + /// Sorted old to new. + #[serde(rename = "timestamps")] + pub timestamps: Vec, + #[serde(rename = "watch")] + pub watch: Box, +} + +impl ServersGetServerLogsResponse { + pub fn new(lines: Vec, timestamps: Vec, watch: crate::models::WatchResponse) -> ServersGetServerLogsResponse { + ServersGetServerLogsResponse { + lines, + timestamps, + watch: Box::new(watch), + } + } +} + + diff --git a/sdks/full/rust-cli/src/models/servers_log_stream.rs b/sdks/full/rust-cli/src/models/servers_log_stream.rs new file mode 100644 index 0000000000..b96bdda215 --- /dev/null +++ b/sdks/full/rust-cli/src/models/servers_log_stream.rs @@ -0,0 +1,39 @@ +/* + * Rivet API + * + * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + * + * The version of the OpenAPI document: 0.0.1 + * + * Generated by: https://openapi-generator.tech + */ + + +/// +#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] +pub enum ServersLogStream { + #[serde(rename = "std_out")] + StdOut, + #[serde(rename = "std_err")] + StdErr, + +} + +impl ToString for ServersLogStream { + fn to_string(&self) -> String { + match self { + Self::StdOut => String::from("std_out"), + Self::StdErr => String::from("std_err"), + } + } +} + +impl Default for ServersLogStream { + fn default() -> ServersLogStream { + Self::StdOut + } +} + + + + diff --git a/sdks/full/rust/.openapi-generator/FILES b/sdks/full/rust/.openapi-generator/FILES index 0a29db9a8c..499eb1b382 100644 --- a/sdks/full/rust/.openapi-generator/FILES +++ b/sdks/full/rust/.openapi-generator/FILES @@ -357,9 +357,12 @@ docs/ServersCreateServerPortRequest.md docs/ServersCreateServerRequest.md docs/ServersCreateServerResponse.md docs/ServersDestroyServerResponse.md +docs/ServersGetServerLogsResponse.md docs/ServersGetServerResponse.md docs/ServersListBuildsResponse.md docs/ServersListServersResponse.md +docs/ServersLogStream.md +docs/ServersLogsApi.md docs/ServersNetwork.md docs/ServersNetworkMode.md docs/ServersPort.md @@ -415,6 +418,7 @@ src/apis/provision_datacenters_api.rs src/apis/provision_servers_api.rs src/apis/servers_api.rs src/apis/servers_builds_api.rs +src/apis/servers_logs_api.rs src/lib.rs src/models/admin_clusters_build_delivery_method.rs src/models/admin_clusters_cluster.rs @@ -730,9 +734,11 @@ src/models/servers_create_server_port_request.rs src/models/servers_create_server_request.rs src/models/servers_create_server_response.rs src/models/servers_destroy_server_response.rs +src/models/servers_get_server_logs_response.rs src/models/servers_get_server_response.rs src/models/servers_list_builds_response.rs src/models/servers_list_servers_response.rs +src/models/servers_log_stream.rs src/models/servers_network.rs src/models/servers_network_mode.rs src/models/servers_port.rs diff --git a/sdks/full/rust/README.md b/sdks/full/rust/README.md index 4fecaf0a6e..1d982febf3 100644 --- a/sdks/full/rust/README.md +++ b/sdks/full/rust/README.md @@ -170,10 +170,11 @@ Class | Method | HTTP request | Description *ServersApi* | [**servers_create**](docs/ServersApi.md#servers_create) | **POST** /servers | *ServersApi* | [**servers_destroy**](docs/ServersApi.md#servers_destroy) | **DELETE** /servers/{server_id} | *ServersApi* | [**servers_get**](docs/ServersApi.md#servers_get) | **GET** /servers/{server_id} | -*ServersApi* | [**servers_list**](docs/ServersApi.md#servers_list) | **GET** /servers/list | +*ServersApi* | [**servers_list**](docs/ServersApi.md#servers_list) | **GET** /servers | *ServersBuildsApi* | [**servers_builds_complete_build**](docs/ServersBuildsApi.md#servers_builds_complete_build) | **POST** /servers/uploads/{upload_id}/complete | *ServersBuildsApi* | [**servers_builds_list_builds**](docs/ServersBuildsApi.md#servers_builds_list_builds) | **GET** /servers/builds | *ServersBuildsApi* | [**servers_builds_prepare_build**](docs/ServersBuildsApi.md#servers_builds_prepare_build) | **POST** /servers/builds | +*ServersLogsApi* | [**servers_logs_get_server_logs**](docs/ServersLogsApi.md#servers_logs_get_server_logs) | **GET** /servers/{server_id}/logs | ## Documentation For Models @@ -491,9 +492,11 @@ Class | Method | HTTP request | Description - [ServersCreateServerRequest](docs/ServersCreateServerRequest.md) - [ServersCreateServerResponse](docs/ServersCreateServerResponse.md) - [ServersDestroyServerResponse](docs/ServersDestroyServerResponse.md) + - [ServersGetServerLogsResponse](docs/ServersGetServerLogsResponse.md) - [ServersGetServerResponse](docs/ServersGetServerResponse.md) - [ServersListBuildsResponse](docs/ServersListBuildsResponse.md) - [ServersListServersResponse](docs/ServersListServersResponse.md) + - [ServersLogStream](docs/ServersLogStream.md) - [ServersNetwork](docs/ServersNetwork.md) - [ServersNetworkMode](docs/ServersNetworkMode.md) - [ServersPort](docs/ServersPort.md) diff --git a/sdks/full/rust/docs/ServersApi.md b/sdks/full/rust/docs/ServersApi.md index 40ca6fcb9d..e596b32ffc 100644 --- a/sdks/full/rust/docs/ServersApi.md +++ b/sdks/full/rust/docs/ServersApi.md @@ -7,7 +7,7 @@ Method | HTTP request | Description [**servers_create**](ServersApi.md#servers_create) | **POST** /servers | [**servers_destroy**](ServersApi.md#servers_destroy) | **DELETE** /servers/{server_id} | [**servers_get**](ServersApi.md#servers_get) | **GET** /servers/{server_id} | -[**servers_list**](ServersApi.md#servers_list) | **GET** /servers/list | +[**servers_list**](ServersApi.md#servers_list) | **GET** /servers | diff --git a/sdks/full/rust/docs/ServersGetServerLogsResponse.md b/sdks/full/rust/docs/ServersGetServerLogsResponse.md new file mode 100644 index 0000000000..ed594b4b5f --- /dev/null +++ b/sdks/full/rust/docs/ServersGetServerLogsResponse.md @@ -0,0 +1,13 @@ +# ServersGetServerLogsResponse + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**lines** | **Vec** | Sorted old to new. | +**timestamps** | **Vec** | Sorted old to new. | +**watch** | [**crate::models::WatchResponse**](WatchResponse.md) | | + +[[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/ServersLogStream.md b/sdks/full/rust/docs/ServersLogStream.md new file mode 100644 index 0000000000..9706b84a3a --- /dev/null +++ b/sdks/full/rust/docs/ServersLogStream.md @@ -0,0 +1,10 @@ +# ServersLogStream + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- + +[[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/ServersLogsApi.md b/sdks/full/rust/docs/ServersLogsApi.md new file mode 100644 index 0000000000..ede5b693ee --- /dev/null +++ b/sdks/full/rust/docs/ServersLogsApi.md @@ -0,0 +1,41 @@ +# \ServersLogsApi + +All URIs are relative to *https://api.rivet.gg* + +Method | HTTP request | Description +------------- | ------------- | ------------- +[**servers_logs_get_server_logs**](ServersLogsApi.md#servers_logs_get_server_logs) | **GET** /servers/{server_id}/logs | + + + +## servers_logs_get_server_logs + +> crate::models::ServersGetServerLogsResponse servers_logs_get_server_logs(server_id, stream, watch_index) + + +Returns the logs for a given server. + +### Parameters + + +Name | Type | Description | Required | Notes +------------- | ------------- | ------------- | ------------- | ------------- +**server_id** | **uuid::Uuid** | | [required] | +**stream** | [**ServersLogStream**](.md) | | [required] | +**watch_index** | Option<**String**> | A query parameter denoting the requests watch index. | | + +### Return type + +[**crate::models::ServersGetServerLogsResponse**](ServersGetServerLogsResponse.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) + diff --git a/sdks/full/rust/src/apis/mod.rs b/sdks/full/rust/src/apis/mod.rs index d267ce82f4..11b380d655 100644 --- a/sdks/full/rust/src/apis/mod.rs +++ b/sdks/full/rust/src/apis/mod.rs @@ -131,5 +131,6 @@ pub mod provision_datacenters_api; pub mod provision_servers_api; pub mod servers_api; pub mod servers_builds_api; +pub mod servers_logs_api; pub mod configuration; diff --git a/sdks/full/rust/src/apis/servers_api.rs b/sdks/full/rust/src/apis/servers_api.rs index aa98e6ee7e..003a515e6d 100644 --- a/sdks/full/rust/src/apis/servers_api.rs +++ b/sdks/full/rust/src/apis/servers_api.rs @@ -171,7 +171,7 @@ pub async fn servers_list(configuration: &configuration::Configuration, tags: Op let local_var_client = &local_var_configuration.client; - let local_var_uri_str = format!("{}/servers/list", local_var_configuration.base_path); + let local_var_uri_str = format!("{}/servers", local_var_configuration.base_path); 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) = tags { diff --git a/sdks/full/rust/src/apis/servers_logs_api.rs b/sdks/full/rust/src/apis/servers_logs_api.rs new file mode 100644 index 0000000000..1a2a016527 --- /dev/null +++ b/sdks/full/rust/src/apis/servers_logs_api.rs @@ -0,0 +1,66 @@ +/* + * Rivet API + * + * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + * + * The version of the OpenAPI document: 0.0.1 + * + * Generated by: https://openapi-generator.tech + */ + + +use reqwest; + +use crate::apis::ResponseContent; +use super::{Error, configuration}; + + +/// struct for typed errors of method [`servers_logs_get_server_logs`] +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum ServersLogsGetServerLogsError { + 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), +} + + +/// Returns the logs for a given server. +pub async fn servers_logs_get_server_logs(configuration: &configuration::Configuration, server_id: &str, stream: crate::models::ServersLogStream, watch_index: Option<&str>) -> Result> { + let local_var_configuration = configuration; + + let local_var_client = &local_var_configuration.client; + + let local_var_uri_str = format!("{}/servers/{server_id}/logs", local_var_configuration.base_path, server_id=crate::apis::urlencode(server_id)); + let mut local_var_req_builder = local_var_client.request(reqwest::Method::GET, local_var_uri_str.as_str()); + + local_var_req_builder = local_var_req_builder.query(&[("stream", &stream.to_string())]); + if let Some(ref local_var_str) = watch_index { + local_var_req_builder = local_var_req_builder.query(&[("watch_index", &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)) + } +} + diff --git a/sdks/full/rust/src/models/mod.rs b/sdks/full/rust/src/models/mod.rs index a04299340c..a15d7977dc 100644 --- a/sdks/full/rust/src/models/mod.rs +++ b/sdks/full/rust/src/models/mod.rs @@ -624,12 +624,16 @@ pub mod servers_create_server_response; pub use self::servers_create_server_response::ServersCreateServerResponse; pub mod servers_destroy_server_response; pub use self::servers_destroy_server_response::ServersDestroyServerResponse; +pub mod servers_get_server_logs_response; +pub use self::servers_get_server_logs_response::ServersGetServerLogsResponse; pub mod servers_get_server_response; pub use self::servers_get_server_response::ServersGetServerResponse; pub mod servers_list_builds_response; pub use self::servers_list_builds_response::ServersListBuildsResponse; pub mod servers_list_servers_response; pub use self::servers_list_servers_response::ServersListServersResponse; +pub mod servers_log_stream; +pub use self::servers_log_stream::ServersLogStream; pub mod servers_network; pub use self::servers_network::ServersNetwork; pub mod servers_network_mode; diff --git a/sdks/full/rust/src/models/servers_get_server_logs_response.rs b/sdks/full/rust/src/models/servers_get_server_logs_response.rs new file mode 100644 index 0000000000..dd6df5a770 --- /dev/null +++ b/sdks/full/rust/src/models/servers_get_server_logs_response.rs @@ -0,0 +1,36 @@ +/* + * Rivet API + * + * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + * + * The version of the OpenAPI document: 0.0.1 + * + * Generated by: https://openapi-generator.tech + */ + + + + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +pub struct ServersGetServerLogsResponse { + /// Sorted old to new. + #[serde(rename = "lines")] + pub lines: Vec, + /// Sorted old to new. + #[serde(rename = "timestamps")] + pub timestamps: Vec, + #[serde(rename = "watch")] + pub watch: Box, +} + +impl ServersGetServerLogsResponse { + pub fn new(lines: Vec, timestamps: Vec, watch: crate::models::WatchResponse) -> ServersGetServerLogsResponse { + ServersGetServerLogsResponse { + lines, + timestamps, + watch: Box::new(watch), + } + } +} + + diff --git a/sdks/full/rust/src/models/servers_log_stream.rs b/sdks/full/rust/src/models/servers_log_stream.rs new file mode 100644 index 0000000000..b96bdda215 --- /dev/null +++ b/sdks/full/rust/src/models/servers_log_stream.rs @@ -0,0 +1,39 @@ +/* + * Rivet API + * + * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + * + * The version of the OpenAPI document: 0.0.1 + * + * Generated by: https://openapi-generator.tech + */ + + +/// +#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] +pub enum ServersLogStream { + #[serde(rename = "std_out")] + StdOut, + #[serde(rename = "std_err")] + StdErr, + +} + +impl ToString for ServersLogStream { + fn to_string(&self) -> String { + match self { + Self::StdOut => String::from("std_out"), + Self::StdErr => String::from("std_err"), + } + } +} + +impl Default for ServersLogStream { + fn default() -> ServersLogStream { + Self::StdOut + } +} + + + + diff --git a/sdks/full/typescript/archive.tgz b/sdks/full/typescript/archive.tgz deleted file mode 100644 index 36b571f48e..0000000000 --- a/sdks/full/typescript/archive.tgz +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:19fd938af83ce03ab70576badbb2d2617e4e13dd3803fc2cf6f86155f72a9cb4 -size 533524 diff --git a/sdks/full/typescript/src/api/resources/servers/client/Client.ts b/sdks/full/typescript/src/api/resources/servers/client/Client.ts deleted file mode 100644 index bac5c4c140..0000000000 --- a/sdks/full/typescript/src/api/resources/servers/client/Client.ts +++ /dev/null @@ -1,602 +0,0 @@ -/** - * This file was auto-generated by Fern from our API Definition. - */ - -import * as environments from "../../../../environments"; -import * as core from "../../../../core"; -import * as Rivet from "../../../index"; -import urlJoin from "url-join"; -import * as serializers from "../../../../serialization/index"; -import * as errors from "../../../../errors/index"; -import { Builds } from "../resources/builds/client/Client"; - -export declare namespace Servers { - interface Options { - environment?: core.Supplier; - token?: core.Supplier; - fetcher?: core.FetchFunction; - } - - interface RequestOptions { - /** The maximum time to wait for a response in seconds. */ - timeoutInSeconds?: number; - /** The number of times to retry the request. Defaults to 2. */ - maxRetries?: number; - /** A hook to abort the request. */ - abortSignal?: AbortSignal; - } -} - -export class Servers { - constructor(protected readonly _options: Servers.Options = {}) {} - - /** - * Gets a dynamic server. - * - * @param {string} serverId - The id of the server to destroy - * @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.servers.get("d5e9c84f-c2b2-4bf4-b4b0-7ffd7a9ffc32") - */ - public async get( - serverId: string, - requestOptions?: Servers.RequestOptions - ): Promise { - const _response = await (this._options.fetcher ?? core.fetcher)({ - url: urlJoin( - (await core.Supplier.get(this._options.environment)) ?? environments.RivetEnvironment.Production, - `/servers/${encodeURIComponent(serverId)}` - ), - method: "GET", - headers: { - Authorization: await this._getAuthorizationHeader(), - }, - contentType: "application/json", - requestType: "json", - timeoutMs: requestOptions?.timeoutInSeconds != null ? requestOptions.timeoutInSeconds * 1000 : 180000, - maxRetries: requestOptions?.maxRetries, - abortSignal: requestOptions?.abortSignal, - }); - if (_response.ok) { - return serializers.servers.GetServerResponse.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, - }); - } - } - - /** - * Create a new dynamic server. - * - * @param {Rivet.servers.CreateServerRequest} 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.servers.create({ - * datacenter: "string", - * tags: { - * "key": "value" - * }, - * imageId: "d5e9c84f-c2b2-4bf4-b4b0-7ffd7a9ffc32", - * arguments: ["string"], - * environment: { - * "string": "string" - * }, - * network: {}, - * resources: {}, - * killTimeout: 1000000, - * webhookUrl: "string" - * }) - */ - public async create( - request: Rivet.servers.CreateServerRequest, - requestOptions?: Servers.RequestOptions - ): Promise { - const _response = await (this._options.fetcher ?? core.fetcher)({ - url: urlJoin( - (await core.Supplier.get(this._options.environment)) ?? environments.RivetEnvironment.Production, - "/servers" - ), - method: "POST", - headers: { - Authorization: await this._getAuthorizationHeader(), - }, - contentType: "application/json", - requestType: "json", - body: serializers.servers.CreateServerRequest.jsonOrThrow(request, { unrecognizedObjectKeys: "strip" }), - timeoutMs: requestOptions?.timeoutInSeconds != null ? requestOptions.timeoutInSeconds * 1000 : 180000, - maxRetries: requestOptions?.maxRetries, - abortSignal: requestOptions?.abortSignal, - }); - if (_response.ok) { - return serializers.servers.CreateServerResponse.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, - }); - } - } - - /** - * Destroy a dynamic server. - * - * @param {string} serverId - The id of the server to destroy - * @param {Rivet.servers.DestroyServerRequest} 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.servers.destroy("d5e9c84f-c2b2-4bf4-b4b0-7ffd7a9ffc32", { - * overrideKillTimeout: 1000000 - * }) - */ - public async destroy( - serverId: string, - request: Rivet.servers.DestroyServerRequest = {}, - requestOptions?: Servers.RequestOptions - ): Promise { - const { overrideKillTimeout } = request; - const _queryParams: Record = {}; - if (overrideKillTimeout != null) { - _queryParams["override_kill_timeout"] = overrideKillTimeout.toString(); - } - - const _response = await (this._options.fetcher ?? core.fetcher)({ - url: urlJoin( - (await core.Supplier.get(this._options.environment)) ?? environments.RivetEnvironment.Production, - `/servers/${encodeURIComponent(serverId)}` - ), - method: "DELETE", - 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.servers.DestroyServerResponse.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, - }); - } - } - - /** - * Lists all servers associated with the token used. Can be filtered by tags in the query string. - * - * @param {Rivet.servers.GetServersRequest} 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.servers.list({ - * tags: "string" - * }) - */ - public async list( - request: Rivet.servers.GetServersRequest = {}, - requestOptions?: Servers.RequestOptions - ): Promise { - const { tags } = request; - const _queryParams: Record = {}; - if (tags != null) { - _queryParams["tags"] = tags; - } - - const _response = await (this._options.fetcher ?? core.fetcher)({ - url: urlJoin( - (await core.Supplier.get(this._options.environment)) ?? environments.RivetEnvironment.Production, - "/servers/list" - ), - 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.servers.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, - }); - } - } - - protected _builds: Builds | undefined; - - public get builds(): Builds { - return (this._builds ??= new Builds(this._options)); - } - - protected async _getAuthorizationHeader(): Promise { - const bearer = await core.Supplier.get(this._options.token); - if (bearer != null) { - return `Bearer ${bearer}`; - } - - return undefined; - } -} diff --git a/sdks/full/typescript/src/api/resources/servers/client/requests/index.ts b/sdks/full/typescript/src/api/resources/servers/client/requests/index.ts deleted file mode 100644 index 54b04a6744..0000000000 --- a/sdks/full/typescript/src/api/resources/servers/client/requests/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { type DestroyServerRequest } from "./DestroyServerRequest"; -export { type GetServersRequest } from "./GetServersRequest"; diff --git a/sdks/full/typescript/src/api/resources/servers/resources/index.ts b/sdks/full/typescript/src/api/resources/servers/resources/index.ts index 0e22c79059..75444c1681 100644 --- a/sdks/full/typescript/src/api/resources/servers/resources/index.ts +++ b/sdks/full/typescript/src/api/resources/servers/resources/index.ts @@ -2,4 +2,7 @@ export * as builds from "./builds"; export * from "./builds/types"; export * as common from "./common"; export * from "./common/types"; +export * as logs from "./logs"; +export * from "./logs/types"; export * from "./builds/client/requests"; +export * from "./logs/client/requests"; diff --git a/sdks/full/typescript/src/api/resources/servers/resources/logs/client/Client.ts b/sdks/full/typescript/src/api/resources/servers/resources/logs/client/Client.ts new file mode 100644 index 0000000000..82ca2b1720 --- /dev/null +++ b/sdks/full/typescript/src/api/resources/servers/resources/logs/client/Client.ts @@ -0,0 +1,166 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ + +import * as environments from "../../../../../../environments"; +import * as core from "../../../../../../core"; +import * as Rivet from "../../../../.."; +import urlJoin from "url-join"; +import * as serializers from "../../../../../../serialization"; +import * as errors from "../../../../../../errors"; + +export declare namespace Logs { + interface Options { + environment?: core.Supplier; + token?: core.Supplier; + fetcher?: core.FetchFunction; + } + + interface RequestOptions { + timeoutInSeconds?: number; + maxRetries?: number; + } +} + +export class Logs { + constructor(protected readonly _options: Logs.Options = {}) {} + + /** + * Returns the logs for a given server. + * @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 getServerLogs( + serverId: string, + request: Rivet.servers.GetServerLogsRequest, + requestOptions?: Logs.RequestOptions + ): Promise { + const { stream, watchIndex } = request; + const _queryParams: Record = {}; + _queryParams["stream"] = stream; + if (watchIndex != null) { + _queryParams["watch_index"] = watchIndex; + } + + const _response = await (this._options.fetcher ?? core.fetcher)({ + url: urlJoin( + (await core.Supplier.get(this._options.environment)) ?? environments.RivetEnvironment.Production, + `/servers/${serverId}/logs` + ), + method: "GET", + 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 await serializers.servers.GetServerLogsResponse.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( + 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) { + return `Bearer ${bearer}`; + } + + return undefined; + } +} diff --git a/sdks/full/typescript/src/api/resources/servers/resources/logs/client/index.ts b/sdks/full/typescript/src/api/resources/servers/resources/logs/client/index.ts new file mode 100644 index 0000000000..415726b7fe --- /dev/null +++ b/sdks/full/typescript/src/api/resources/servers/resources/logs/client/index.ts @@ -0,0 +1 @@ +export * from "./requests"; diff --git a/sdks/full/typescript/src/api/resources/servers/resources/logs/client/requests/GetServerLogsRequest.ts b/sdks/full/typescript/src/api/resources/servers/resources/logs/client/requests/GetServerLogsRequest.ts new file mode 100644 index 0000000000..7ed49654e4 --- /dev/null +++ b/sdks/full/typescript/src/api/resources/servers/resources/logs/client/requests/GetServerLogsRequest.ts @@ -0,0 +1,13 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ + +import * as Rivet from "../../../../../.."; + +export interface GetServerLogsRequest { + stream: Rivet.servers.LogStream; + /** + * A query parameter denoting the requests watch index. + */ + watchIndex?: string; +} diff --git a/sdks/full/typescript/src/api/resources/servers/resources/logs/client/requests/index.ts b/sdks/full/typescript/src/api/resources/servers/resources/logs/client/requests/index.ts new file mode 100644 index 0000000000..e1319b7077 --- /dev/null +++ b/sdks/full/typescript/src/api/resources/servers/resources/logs/client/requests/index.ts @@ -0,0 +1 @@ +export { GetServerLogsRequest } from "./GetServerLogsRequest"; diff --git a/sdks/full/typescript/src/api/resources/servers/resources/logs/index.ts b/sdks/full/typescript/src/api/resources/servers/resources/logs/index.ts new file mode 100644 index 0000000000..c9240f83b4 --- /dev/null +++ b/sdks/full/typescript/src/api/resources/servers/resources/logs/index.ts @@ -0,0 +1,2 @@ +export * from "./types"; +export * from "./client"; diff --git a/sdks/full/typescript/src/serialization/resources/servers/resources/index.ts b/sdks/full/typescript/src/serialization/resources/servers/resources/index.ts index 5b2d30fd99..8786b62a24 100644 --- a/sdks/full/typescript/src/serialization/resources/servers/resources/index.ts +++ b/sdks/full/typescript/src/serialization/resources/servers/resources/index.ts @@ -2,3 +2,5 @@ export * as builds from "./builds"; export * from "./builds/types"; export * as common from "./common"; export * from "./common/types"; +export * as logs from "./logs"; +export * from "./logs/types"; diff --git a/sdks/full/typescript/src/serialization/resources/servers/resources/logs/index.ts b/sdks/full/typescript/src/serialization/resources/servers/resources/logs/index.ts new file mode 100644 index 0000000000..eea524d655 --- /dev/null +++ b/sdks/full/typescript/src/serialization/resources/servers/resources/logs/index.ts @@ -0,0 +1 @@ +export * from "./types"; diff --git a/sdks/runtime/typescript/archive.tgz b/sdks/runtime/typescript/archive.tgz deleted file mode 100644 index 0603d96ee5..0000000000 --- a/sdks/runtime/typescript/archive.tgz +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:1646343b57ad54ab6861ca9469a9657ffae6c8bbe4bcb2b2b75067b3bc1aedfa -size 283075 diff --git a/svc/Cargo.lock b/svc/Cargo.lock index 324c8def62..a8d2baf728 100644 --- a/svc/Cargo.lock +++ b/svc/Cargo.lock @@ -54,7 +54,7 @@ dependencies = [ "getrandom", "once_cell", "version_check", - "zerocopy", + "zerocopy 0.7.35", ] [[package]] @@ -796,6 +796,7 @@ name = "api-servers" version = "0.0.1" dependencies = [ "api-helper", + "base64 0.13.1", "build-create", "build-get", "build-list-for-game", @@ -806,6 +807,7 @@ dependencies = [ "cloud-namespace-token-public-create", "cloud-service-game-token-create", "cluster", + "ds-log-read", "ds-server-create", "ds-server-delete", "ds-server-get", @@ -1561,9 +1563,9 @@ dependencies = [ [[package]] name = "bstr" -version = "1.9.1" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05efc5cfd9110c8416e471df0e96702d58690178e206e61b7173706673c93706" +checksum = "40723b8fb387abc38f4f4a37c09073622e41dd12327033091ef8950659e6dc0c" dependencies = [ "memchr", ] @@ -1651,9 +1653,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.6.1" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a12916984aab3fa6e39d655a33e09c0071eb36d6ab3aea5c2d78551f1df6d952" +checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" dependencies = [ "serde", ] @@ -1753,9 +1755,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.1.6" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2aba8f4e9906c7ce3c73463f62a7f0c65183ada1a2d47e397cc8810827f9694f" +checksum = "26a5c3fd7bfa1ce3897a3a3501d362b2d87b7f2583ebcb4a949ec25911025cbc" [[package]] name = "cdn-namespace-auth-user-remove" @@ -2990,6 +2992,33 @@ version = "0.15.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" +[[package]] +name = "ds-log-export" +version = "0.0.1" +dependencies = [ + "chirp-client", + "chirp-worker", + "reqwest 0.11.27", + "rivet-operation", + "serde", + "sqlx 0.7.4 (git+https://github.com/rivet-gg/sqlx?rev=08d6e61aa0572e7ec557abbedb72cebb96e1ac5b)", + "upload-complete", + "upload-prepare", +] + +[[package]] +name = "ds-log-read" +version = "0.0.1" +dependencies = [ + "chirp-client", + "chirp-worker", + "chrono", + "clickhouse", + "prost 0.10.4", + "rivet-operation", + "serde", +] + [[package]] name = "ds-server-create" version = "0.0.1" @@ -4249,7 +4278,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.12", - "indexmap 2.2.6", + "indexmap 2.3.0", "slab", "tokio", "tokio-util 0.7.11", @@ -4268,7 +4297,7 @@ dependencies = [ "futures-core", "futures-sink", "http 1.1.0", - "indexmap 2.2.6", + "indexmap 2.3.0", "slab", "tokio", "tokio-util 0.7.11", @@ -4792,9 +4821,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.2.6" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +checksum = "de3fc2e30ba82dd1b3911c8de1ffc143c74a914a14e99514d7637e3099df5ea0" dependencies = [ "equivalent", "hashbrown 0.14.5", @@ -5474,11 +5503,10 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "merkle_hash" -version = "3.6.1" +version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fad8dc52477aa6f1751748a5ee1c6d50db7092e8dab1d687840dfa23e2ae4e5" +checksum = "3edd3572d1a7b4e1b7ce5bb3af05405a8aeab2ec04b29d9779e72ad576ce4f38" dependencies = [ - "anyhow", "blake3", "camino", "rayon", @@ -6510,7 +6538,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" dependencies = [ "fixedbitset", - "indexmap 2.2.6", + "indexmap 2.3.0", ] [[package]] @@ -6597,9 +6625,12 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" -version = "0.2.17" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "dee4364d9f3b902ef14fab8a1ddffb783a1cb6b4bba3bfc1fa3922732c7de97f" +dependencies = [ + "zerocopy 0.6.6", +] [[package]] name = "prettyplease" @@ -6966,9 +6997,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.5" +version = "1.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" +checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" dependencies = [ "aho-corasick", "memchr", @@ -8129,11 +8160,12 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.120" +version = "1.0.122" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5" +checksum = "784b6203951c57ff748476b126ccb5e8e2959a5c19e5c617ab1956be3dbc68da" dependencies = [ "itoa 1.0.11", + "memchr", "ryu", "serde", ] @@ -8417,7 +8449,7 @@ dependencies = [ "futures-util", "hashlink", "hex", - "indexmap 2.2.6", + "indexmap 2.3.0", "log", "memchr", "once_cell", @@ -8453,7 +8485,7 @@ dependencies = [ "futures-util", "hashlink", "hex", - "indexmap 2.2.6", + "indexmap 2.3.0", "ipnetwork", "log", "memchr", @@ -9209,9 +9241,9 @@ dependencies = [ [[package]] name = "tokio" -version = "1.39.1" +version = "1.39.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d040ac2b29ab03b09d4129c2f5bbd012a3ac2f79d38ff506a4bf8dd34b0eac8a" +checksum = "daa4fb1bc778bd6f04cbfc4bb2d06a7396a8f299dc33ea1900cedaa316f467b1" dependencies = [ "backtrace", "bytes", @@ -9386,9 +9418,9 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.7" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8fb9f64314842840f1d940ac544da178732128f1c78c21772e876579e0da1db" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" dependencies = [ "serde", ] @@ -9399,7 +9431,7 @@ version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.2.6", + "indexmap 2.3.0", "serde", "serde_spanned", "toml_datetime", @@ -10331,9 +10363,9 @@ checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "version_check" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "want" @@ -10772,13 +10804,34 @@ dependencies = [ "hashlink", ] +[[package]] +name = "zerocopy" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "854e949ac82d619ee9a14c66a1b674ac730422372ccb759ce0c39cabcf2bf8e6" +dependencies = [ + "byteorder", + "zerocopy-derive 0.6.6", +] + [[package]] name = "zerocopy" version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ - "zerocopy-derive", + "zerocopy-derive 0.7.35", +] + +[[package]] +name = "zerocopy-derive" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "125139de3f6b9d625c39e2efdd73d41bdac468ccd556556440e322be0e1bbd91" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", ] [[package]] diff --git a/svc/Cargo.toml b/svc/Cargo.toml index 24a45f058f..5c18538a12 100644 --- a/svc/Cargo.toml +++ b/svc/Cargo.toml @@ -70,6 +70,8 @@ members = [ "pkg/custom-user-avatar/ops/list-for-game", "pkg/custom-user-avatar/ops/upload-complete", "pkg/debug/ops/email-res", + "pkg/ds-log/ops/export", + "pkg/ds-log/ops/read", "pkg/ds/ops/server-create", "pkg/ds/ops/server-delete", "pkg/ds/ops/server-get", diff --git a/svc/api/servers/Cargo.toml b/svc/api/servers/Cargo.toml index aafbc3bd0f..1cf5ba0a42 100644 --- a/svc/api/servers/Cargo.toml +++ b/svc/api/servers/Cargo.toml @@ -21,6 +21,7 @@ rivet-pools = { path = "../../../lib/pools" } s3-util = { path = "../../../lib/s3-util" } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" +base64 = "0.13" tokio = { version = "1.29" } tracing = "0.1" tracing-futures = "0.2" @@ -32,6 +33,7 @@ build-create = { path = "../../pkg/build/ops/create" } build-get = { path = "../../pkg/build/ops/get" } build-list-for-game = { path = "../../pkg/build/ops/list-for-game" } cluster = { path = "../../pkg/cluster" } +ds-log-read = { path = "../../pkg/ds-log/ops/read" } ds-server-create = { path = "../../pkg/ds/ops/server-create" } ds-server-delete = { path = "../../pkg/ds/ops/server-delete" } ds-server-get = { path = "../../pkg/ds/ops/server-get" } diff --git a/svc/api/servers/src/assert.rs b/svc/api/servers/src/assert.rs index 009b938784..541cf6c89d 100644 --- a/svc/api/servers/src/assert.rs +++ b/svc/api/servers/src/assert.rs @@ -61,3 +61,21 @@ pub async fn namespace_for_game( Ok(ns_data.clone()) } + +/// Validates that a server belongs to the given game ID. +/// +/// Throws `NotFound` if server does not exist and `BadRequest` if does not belong to the given +/// game. +pub async fn server_for_game(ctx: &Ctx, server_id: Uuid, game_id: Uuid) -> GlobalResult<()> { + let server_get_res = op!([ctx] ds_server_get { + server_ids: vec![server_id.into()], + }) + .await?; + + // let server_data = unwrap!(server_get_res.servers.first()); + // let server_game_id = unwrap_ref!(server_data.game_id).as_uuid(); + + // ensure_eq!(game_id, server_game_id, "server does not belong to game"); + + Ok(()) +} diff --git a/svc/api/servers/src/route/logs.rs b/svc/api/servers/src/route/logs.rs new file mode 100644 index 0000000000..9bf91e1365 --- /dev/null +++ b/svc/api/servers/src/route/logs.rs @@ -0,0 +1,160 @@ +use api_helper::{ + anchor::{WatchIndexQuery, WatchResponse}, + ctx::Ctx, +}; +use proto::backend::{self, pkg::*}; +use rivet_api::models; +use rivet_operation::prelude::*; +use serde::Deserialize; +use std::time::Duration; + +use crate::{assert, auth::Auth}; + +// MARK: GET /servers/{server_id}/logs +#[derive(Debug, Deserialize)] +pub struct GetServerLogsQuery { + pub stream: models::CloudGamesLogStream, +} + +pub async fn get_logs( + ctx: Ctx, + server_id: Uuid, + watch_index: WatchIndexQuery, + query: GetServerLogsQuery, +) -> GlobalResult { + let game_id = ctx.auth().check_game_service_or_cloud_token().await?; + + // ctx.auth() + // .check_game_read_or_admin(ctx.op_ctx(), game_id) + // .await?; + + // Get start ts + // If no watch: read logs + // If watch: + // loop read logs from index + // wait until start ts + 1 second + + // Determine stream type + let stream_type = match query.stream { + models::CloudGamesLogStream::StdOut => backend::job::log::StreamType::StdOut, + models::CloudGamesLogStream::StdErr => backend::job::log::StreamType::StdErr, + }; + + // Timestamp to start the query at + let before_nts = util::timestamp::now() * 1_000_000; + + // Validate server belongs to game + let _game_ns = assert::server_for_game(&ctx, server_id, game_id).await?; + + // // Get run ID + // let server_id = if let Some(x) = get_server_id(&ctx, game_id, lobby_id).await? { + // x + // } else { + // // Throttle request if watching. This is effectively polling until the lobby is ready. + // if watch_index.to_consumer()?.is_some() { + // tokio::time::sleep(Duration::from_secs(1)).await; + // } + + // // Return empty logs + // return Ok(models::CloudGamesGetLobbyLogsResponse { + // lines: Vec::new(), + // timestamps: Vec::new(), + // watch: WatchResponse::new_as_model(before_nts), + // }); + // }; + + // Handle anchor + let logs_res = if let Some(anchor) = watch_index.as_i64()? { + let query_start = tokio::time::Instant::now(); + + // Poll for new logs + let logs_res = loop { + // Read logs after the timestamp + // + // We read descending in order to get at most 256 of the most recent logs. If we used + // asc, we would be paginating through all the logs which would likely fall behind + // actual stream and strain the database. + // + // We return fewer logs than the non-anchor request since this will be called + // frequently and should not return a significant amount of logs. + let logs_res = op!([ctx] @dont_log_body ds_log_read { + server_id: Some(server_id.into()), + stream_type: stream_type as i32, + count: 64, + order_asc: false, + query: Some(ds_log::read::request::Query::AfterNts(anchor)) + + }) + .await?; + + let list_res = op!([ctx] @dont_log_body ds_log_read { + server_id: Some(server_id.into()), + stream_type: stream_type as i32, + count: 64, + order_asc: false, + query: Some(ds_log::read::request::Query::AfterNts(anchor)) + }) + .await?; + + // Return logs + if !logs_res.entries.is_empty() { + break logs_res; + } + + // Timeout cleanly + if query_start.elapsed().as_millis() > util::watch::DEFAULT_TIMEOUT as u128 { + break ds_log::read::Response { + entries: Vec::new(), + }; + } + + // Throttle request + // + // We don't use `tokio::time::interval` because if the request takes longer than 500 + // ms, we'll enter a tight loop of requests. + tokio::time::sleep(Duration::from_millis(500)).await; + }; + + // Since we're using watch, we don't want this request to return immediately if there's new + // results. Add an artificial timeout in order to prevent a tight loop if there's a high + // log frequency. + tokio::time::sleep_until(query_start + Duration::from_secs(1)).await; + + logs_res + } else { + // Read most recent logs + + op!([ctx] @dont_log_body ds_log_read { + server_id: Some(server_id.into()), + stream_type: stream_type as i32, + count: 256, + order_asc: false, + query: Some(ds_log::read::request::Query::BeforeNts(before_nts)), + }) + .await? + }; + + // Convert logs + let mut lines = logs_res + .entries + .iter() + .map(|entry| base64::encode(&entry.message)) + .collect::>(); + let mut timestamps = logs_res + .entries + .iter() + .map(|x| x.nts / 1_000_000) + .map(util::timestamp::to_string) + .collect::, _>>()?; + + // Order desc + lines.reverse(); + timestamps.reverse(); + + let watch_nts = logs_res.entries.first().map_or(before_nts, |x| x.nts); + Ok(models::ServersGetServerLogsResponse { + lines, + timestamps, + watch: WatchResponse::new_as_model(watch_nts), + }) +} diff --git a/svc/api/servers/src/route/mod.rs b/svc/api/servers/src/route/mod.rs index 9e46216e6e..b8ab9782c2 100644 --- a/svc/api/servers/src/route/mod.rs +++ b/svc/api/servers/src/route/mod.rs @@ -4,6 +4,7 @@ use rivet_api::models; use uuid::Uuid; pub mod builds; +pub mod logs; pub mod servers; pub async fn handle( @@ -22,32 +23,35 @@ pub async fn handle( define_router! { routes: { "" : { + GET: servers::list_servers( + query: servers::ListQuery, + ), POST: servers::create( body: models::ServersCreateServerRequest, ), }, - "" / Uuid : { + Uuid : { GET: servers::get(), DELETE: servers::destroy( query: servers::DeleteQuery, ), }, - "" / "list": { - GET: servers::list_servers( - query: servers::ListQuery, + Uuid / "logs" : { + GET: logs::get_logs( + query: logs::GetServerLogsQuery, ), }, - "" / "builds": { + "builds": { GET: builds::get_builds( query: builds::GetQuery, ), POST: builds::create_build(body: models::ServersCreateBuildRequest), }, - "" / "uploads" / Uuid / "complete": { + "uploads" / Uuid / "complete": { POST: builds::complete_build(body: serde_json::Value), }, }, diff --git a/svc/api/servers/src/route/servers.rs b/svc/api/servers/src/route/servers.rs index 60b536120b..cc2efdcffc 100644 --- a/svc/api/servers/src/route/servers.rs +++ b/svc/api/servers/src/route/servers.rs @@ -1,5 +1,5 @@ use api_helper::{anchor::WatchIndexQuery, ctx::Ctx}; -use proto::backend::{self, pkg::dynamic_servers}; +use proto::backend::{self, pkg::*}; use rivet_api::models; use rivet_convert::{ApiFrom, ApiInto, ApiTryFrom, ApiTryInto}; use rivet_operation::prelude::*; @@ -145,7 +145,7 @@ pub async fn destroy( }) } -// MARK: LIST /servers/list +// MARK: GET /servers/list #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ListQuery { tags: Option, diff --git a/svc/pkg/ds-log/buckets/export/Service.toml b/svc/pkg/ds-log/buckets/export/Service.toml new file mode 100644 index 0000000000..2e70524e37 --- /dev/null +++ b/svc/pkg/ds-log/buckets/export/Service.toml @@ -0,0 +1,8 @@ +[service] +name = "bucket-ds-log-export" + +[runtime] +kind = "s3" +upload_policy = "none" + +[database] diff --git a/svc/pkg/ds-log/db/log/Service.toml b/svc/pkg/ds-log/db/log/Service.toml new file mode 100644 index 0000000000..1efd5199b9 --- /dev/null +++ b/svc/pkg/ds-log/db/log/Service.toml @@ -0,0 +1,7 @@ +[service] +name = "db-ds-log" + +[runtime] +kind = "clickhouse" + +[database] diff --git a/svc/pkg/ds-log/db/log/migrations/20200101000000_init.down.sql b/svc/pkg/ds-log/db/log/migrations/20200101000000_init.down.sql new file mode 100644 index 0000000000..e69de29bb2 diff --git a/svc/pkg/ds-log/db/log/migrations/20200101000000_init.up.sql b/svc/pkg/ds-log/db/log/migrations/20200101000000_init.up.sql new file mode 100644 index 0000000000..260dc8d26d --- /dev/null +++ b/svc/pkg/ds-log/db/log/migrations/20200101000000_init.up.sql @@ -0,0 +1,15 @@ +CREATE TABLE IF NOT EXISTS server_logs ( + server_id UUID, + stream_type UInt8, -- backend::ds::log::StreamType + ts DateTime64 (9), + message String +) ENGINE = ReplicatedMergeTree () +PARTITION BY + toStartOfHour (ts) +ORDER BY ( + server_id, + toUnixTimestamp (ts), + stream_type +) +TTL toDate (ts + toIntervalDay (3)) +SETTINGS index_granularity = 8192, ttl_only_drop_parts = 1; diff --git a/svc/pkg/ds-log/ops/export/Cargo.toml b/svc/pkg/ds-log/ops/export/Cargo.toml new file mode 100644 index 0000000000..67a9e5b4b3 --- /dev/null +++ b/svc/pkg/ds-log/ops/export/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "ds-log-export" +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" } +reqwest = "0.11" +serde = { version = "1.0", features = ["derive"] } + +upload-complete = { path = "../../../upload/ops/complete" } +upload-prepare = { path = "../../../upload/ops/prepare" } + +[dependencies.sqlx] +git = "https://github.com/rivet-gg/sqlx" +rev = "08d6e61aa0572e7ec557abbedb72cebb96e1ac5b" +default-features = false + +[dev-dependencies] +chirp-worker = { path = "../../../../../lib/chirp/worker" } diff --git a/svc/pkg/ds-log/ops/export/Service.toml b/svc/pkg/ds-log/ops/export/Service.toml new file mode 100644 index 0000000000..e3e6b3c016 --- /dev/null +++ b/svc/pkg/ds-log/ops/export/Service.toml @@ -0,0 +1,13 @@ +[service] +name = "ds-log-export" + +[runtime] +kind = "rust" + +[operation] + +[secrets] +"clickhouse/users/chirp/password" = {} + +[databases] +db-ds-log = {} diff --git a/svc/pkg/ds-log/ops/export/src/lib.rs b/svc/pkg/ds-log/ops/export/src/lib.rs new file mode 100644 index 0000000000..a9f7a1d3b8 --- /dev/null +++ b/svc/pkg/ds-log/ops/export/src/lib.rs @@ -0,0 +1,96 @@ +use proto::backend::{self, pkg::*}; +use rivet_operation::prelude::*; + +#[derive(clickhouse::Row, serde::Deserialize)] +struct LogEntry { + message: Vec, +} + +#[operation(name = "ds-log-export")] +pub async fn handle( + ctx: OperationContext, +) -> GlobalResult { + let request_id = unwrap_ref!(ctx.request_id).as_uuid(); + let server_id = unwrap_ref!(ctx.server_id).as_uuid(); + + let stream_type = unwrap!(backend::ds::log::StreamType::from_i32(ctx.stream_type)); + let file_name = match stream_type { + backend::ds::log::StreamType::StdOut => "stdout.txt", + backend::ds::log::StreamType::StdErr => "stderr.txt", + }; + + let mut entries_cursor = ctx + .clickhouse() + .await? + .query(indoc!( + " + SELECT + message + FROM + db_ds_log.server_logs + WHERE + server_id = ? + AND stream_type = ? + ORDER BY + ts + ASC + " + )) + .bind(server_id) + .bind(ctx.stream_type as i8) + .fetch::()?; + + let mut lines = 0; + let mut buf = Vec::new(); + while let Some(mut entry) = entries_cursor.next().await? { + buf.append(&mut entry.message); + buf.push(b'\n'); + lines += 1; + } + + tracing::info!(?lines, bytes = ?buf.len(), "read all logs"); + + // Upload log + let mime = "text/plain"; + let content_length = buf.len(); + let upload_res = op!([ctx] upload_prepare { + bucket: "bucket-ds-log-export".into(), + files: vec![ + backend::upload::PrepareFile { + path: file_name.into(), + mime: Some(mime.into()), + content_length: content_length as u64, + ..Default::default() + }, + ], + }) + .await?; + + let presigned_req = unwrap!(upload_res.presigned_requests.first()); + let res = reqwest::Client::new() + .put(&presigned_req.url) + .body(buf) + .header(reqwest::header::CONTENT_TYPE, mime) + .header(reqwest::header::CONTENT_LENGTH, content_length) + .send() + .await?; + if res.status().is_success() { + tracing::info!("uploaded successfully"); + } else { + let status = res.status(); + let text = res.text().await; + tracing::error!(?status, ?text, "failed to upload"); + bail!("failed to upload"); + } + + op!([ctx] upload_complete { + upload_id: upload_res.upload_id, + bucket: Some("bucket-ds-log-export".into()), + }) + .await?; + + Ok(ds_log::export::Response { + request_id: Some(request_id.into()), + upload_id: upload_res.upload_id, + }) +} diff --git a/svc/pkg/ds-log/ops/export/tests/integration.rs b/svc/pkg/ds-log/ops/export/tests/integration.rs new file mode 100644 index 0000000000..d7d641e21e --- /dev/null +++ b/svc/pkg/ds-log/ops/export/tests/integration.rs @@ -0,0 +1,6 @@ +use chirp_worker::prelude::*; + +#[worker_test] +async fn basic(ctx: TestCtx) { + // TODO: +} diff --git a/svc/pkg/ds-log/ops/read/Cargo.toml b/svc/pkg/ds-log/ops/read/Cargo.toml new file mode 100644 index 0000000000..7b13b8ef13 --- /dev/null +++ b/svc/pkg/ds-log/ops/read/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "ds-log-read" +version = "0.0.1" +edition = "2021" +authors = ["Rivet Gaming, LLC "] +license = "Apache-2.0" + +[dependencies] +chirp-client = { path = "../../../../../lib/chirp/client" } +chrono = "0.4" +clickhouse = { version = "0.11.2", features = ["wa-37420", "uuid"] } +prost = "0.10" +rivet-operation = { path = "../../../../../lib/operation/core" } +serde = { version = "1.0", features = ["derive"] } + +[dev-dependencies] +chirp-worker = { path = "../../../../../lib/chirp/worker" } diff --git a/svc/pkg/ds-log/ops/read/README.md b/svc/pkg/ds-log/ops/read/README.md new file mode 100644 index 0000000000..52f2626ee2 --- /dev/null +++ b/svc/pkg/ds-log/ops/read/README.md @@ -0,0 +1 @@ +# ds-log-read diff --git a/svc/pkg/ds-log/ops/read/Service.toml b/svc/pkg/ds-log/ops/read/Service.toml new file mode 100644 index 0000000000..8a8fe37d14 --- /dev/null +++ b/svc/pkg/ds-log/ops/read/Service.toml @@ -0,0 +1,13 @@ +[service] +name = "ds-log-read" + +[runtime] +kind = "rust" + +[operation] + +[secrets] +"clickhouse/users/chirp/password" = {} + +[databases] +db-ds-log = {} diff --git a/svc/pkg/ds-log/ops/read/src/lib.rs b/svc/pkg/ds-log/ops/read/src/lib.rs new file mode 100644 index 0000000000..7d2def992b --- /dev/null +++ b/svc/pkg/ds-log/ops/read/src/lib.rs @@ -0,0 +1,209 @@ +use proto::backend::{self, pkg::*}; +use rivet_operation::prelude::*; + +#[derive(clickhouse::Row, serde::Deserialize)] +struct LogEntry { + // In nanoseconds + ts: i64, + message: Vec, +} + +#[operation(name = "ds-log-read")] +async fn handle( + ctx: OperationContext, +) -> GlobalResult { + let clickhouse = ctx.clickhouse().await?; + + let server_id = unwrap_ref!(ctx.server_id).as_uuid(); + let req_query = unwrap_ref!(ctx.query); + + let order_by = if ctx.order_asc { "ASC" } else { "DESC" }; + + let entries = match req_query { + ds_log::read::request::Query::All(_) => { + query_all(ctx.body(), &clickhouse, server_id, order_by).await? + } + ds_log::read::request::Query::BeforeNts(nts) => { + query_before_nts(ctx.body(), &clickhouse, server_id, *nts, order_by).await? + } + ds_log::read::request::Query::AfterNts(nts) => { + query_after_nts(ctx.body(), &clickhouse, server_id, *nts, order_by).await? + } + ds_log::read::request::Query::NtsRange(query) => { + query_nts_range( + ctx.body(), + &clickhouse, + server_id, + query.after_nts, + query.before_nts, + order_by, + ) + .await? + } + }; + + Ok(ds_log::read::Response { entries }) +} + +async fn query_all( + req: &ds_log::read::Request, + clickhouse: &ClickHousePool, + run_id: Uuid, + order_by: &str, +) -> GlobalResult> { + let mut entries_cursor = clickhouse + .query(&formatdoc!( + " + SELECT + ts, + message + FROM + db_ds_log.server_logs + WHERE + server_id = ? + AND stream_type = ? + ORDER BY + ts {order_by} + LIMIT + ? + " + )) + .bind(run_id) + .bind(req.stream_type as u8) + .bind(req.count) + .fetch::()?; + + let mut entries = Vec::new(); + while let Some(entry) = entries_cursor.next().await? { + entries.push(convert_entry(entry)); + } + + Ok(entries) +} + +async fn query_before_nts( + req: &ds_log::read::Request, + clickhouse: &ClickHousePool, + run_id: Uuid, + nts: i64, + order_by: &str, +) -> GlobalResult> { + let mut entries_cursor = clickhouse + .query(&formatdoc!( + " + SELECT + ts, + message + FROM + db_ds_log.server_logs + WHERE + server_id = ? + AND stream_type = ? + AND ts < fromUnixTimestamp64Nano(?) + ORDER BY + ts {order_by} + LIMIT + ? + " + )) + .bind(run_id) + .bind(req.stream_type as u8) + .bind(nts) + .bind(req.count) + .fetch::()?; + + let mut entries = Vec::new(); + while let Some(entry) = entries_cursor.next().await? { + entries.push(convert_entry(entry)); + } + + Ok(entries) +} + +async fn query_after_nts( + req: &ds_log::read::Request, + clickhouse: &ClickHousePool, + run_id: Uuid, + nts: i64, + order_by: &str, +) -> GlobalResult> { + let mut entries_cursor = clickhouse + .query(&formatdoc!( + " + SELECT + ts, + message + FROM + db_ds_log.server_logs + WHERE + server_id = ? + AND stream_type = ? + AND ts > fromUnixTimestamp64Nano(?) + ORDER BY + ts {order_by} + LIMIT + ? + " + )) + .bind(run_id) + .bind(req.stream_type as u8) + .bind(nts) + .bind(req.count) + .fetch::()?; + + let mut entries = Vec::new(); + while let Some(entry) = entries_cursor.next().await? { + entries.push(convert_entry(entry)); + } + + Ok(entries) +} + +async fn query_nts_range( + req: &ds_log::read::Request, + clickhouse: &ClickHousePool, + run_id: Uuid, + after_nts: i64, + before_nts: i64, + order_by: &str, +) -> GlobalResult> { + let mut entries_cursor = clickhouse + .query(&formatdoc!( + " + SELECT + ts, + message + FROM + db_ds_log.server_logs + WHERE + run_id = ? + AND stream_type = ? + AND ts > fromUnixTimestamp64Nano(?) + AND ts < fromUnixTimestamp64Nano(?) + ORDER BY + ts {order_by} + LIMIT + ? + " + )) + .bind(run_id) + .bind(req.stream_type as u8) + .bind(after_nts) + .bind(before_nts) + .bind(req.count) + .fetch::()?; + + let mut entries = Vec::new(); + while let Some(entry) = entries_cursor.next().await? { + entries.push(convert_entry(entry)); + } + + Ok(entries) +} + +fn convert_entry(entry: LogEntry) -> backend::ds::log::LogEntry { + backend::ds::log::LogEntry { + nts: entry.ts, + message: entry.message, + } +} diff --git a/svc/pkg/ds-log/ops/read/tests/integration.rs b/svc/pkg/ds-log/ops/read/tests/integration.rs new file mode 100644 index 0000000000..38eae97b29 --- /dev/null +++ b/svc/pkg/ds-log/ops/read/tests/integration.rs @@ -0,0 +1,89 @@ +// use chirp_worker::prelude::*; +// use proto::backend::{self, pkg::*}; + +// /// How many logs to create total. +// const BATCH_SIZE: usize = 64; + +// /// How far aprat messages are created. +// const MESSAGE_INTERVAL: i64 = 1000; + +// #[worker_test] +// async fn basic(ctx: TestCtx) { +// // let now = 100000i64; + +// // todo!(); + +// // let run_id = Uuid::new_v4(); +// // let task = "main".to_string(); +// // let stream_type = backend::ds::log::StreamType::StdOut; + +// // // Insert entries +// // let entries = (0..TS_COUNT) +// // .flat_map(|i| backend::ds::log::LogEntry { +// // ts: now + (i as i64 * MESSAGE_INTERVAL), +// // message: format!("Hello, {i}!").into_bytes(), +// // }) +// // .collect::>(); +// // msg!([ctx] ds_log::msg::entries(&run_id, "stdout") { +// // run_id: Some(run_id.into()), +// // stream_type: stream_type as i32, +// // entries: entries, +// // }) +// // .await +// // .unwrap(); + +// // tokio::time::sleep(Duration::from_secs(1)).await; + +// // // Before ts +// // { +// // let res = op!([ctx] ds_log_read { +// // run_id: Some(run_id.into()), +// // stream_type: stream_type as i32, +// // count: 128, +// // query: Some(ds_log::read::request::Query::BeforeTs(ts: now + 5 * MESSAGE_INTERVAL)), +// // }) +// // .await +// // .unwrap(); +// // assert_eq!(5 + 3, res.entries.len()); +// // for (i, entry) in res.entries.iter().enumerate() { +// // assert_eq!(now + i as i64 * MESSAGE_INTERVAL, entry.ts, "i: {i}"); +// // } +// // } + +// // // After ts +// // { +// // let res = op!([ctx] ds_log_read { +// // run_id: Some(run_id.into()), +// // stream_type: stream_type as i32, +// // count: 128, +// // query: Some(ds_log::read::request::Query::AfterTs(now + 7 * MESSAGE_INTERVAL)), +// // }) +// // .await +// // .unwrap(); +// // assert_eq!(BATCH_SIZE - (7 + 2), res.entries.len()); +// // for (i, entry) in res.entries.iter().enumerate() { +// // assert_eq!( +// // now + ((i - 2) + 8) as i64 * MESSAGE_INTERVAL, +// // entry.ts, +// // "i: {i}" +// // ); +// // } +// // } + +// // // All +// // { +// // let res = op!([ctx] ds_log_read { +// // run_id: Some(run_id.into()), +// // task: +// // stream_type: stream_type as i32, +// // count: 128, +// // query: Some(ds_log::read::request::Query::All(())), +// // }) +// // .await +// // .unwrap(); +// // assert_eq!(BATCH_SIZE, res.entries.len()); +// // for (i, entry) in res.entries.iter().enumerate() { +// // assert_eq!(now + i as i64 * MESSAGE_INTERVAL, entry.ts, "i: {i}"); +// // } +// // } +// } diff --git a/svc/pkg/ds-log/proto/export.proto b/svc/pkg/ds-log/proto/export.proto new file mode 100644 index 0000000000..f402c48cd2 --- /dev/null +++ b/svc/pkg/ds-log/proto/export.proto @@ -0,0 +1,18 @@ +syntax = "proto3"; + +package rivet.backend.pkg.ds_log.export; + +import "proto/common.proto"; +import "proto/backend/ds/log.proto"; + +message Request { + rivet.common.Uuid request_id = 1; + rivet.common.Uuid server_id = 2; + string task = 3; + rivet.backend.ds.log.StreamType stream_type = 4; +} + +message Response { + rivet.common.Uuid request_id = 1; + rivet.common.Uuid upload_id = 2; +} diff --git a/svc/pkg/ds-log/proto/read.proto b/svc/pkg/ds-log/proto/read.proto new file mode 100644 index 0000000000..cc49497639 --- /dev/null +++ b/svc/pkg/ds-log/proto/read.proto @@ -0,0 +1,35 @@ +syntax = "proto3"; + +package rivet.backend.pkg.ds_log.read; + +import "google/protobuf/empty.proto"; +import "proto/backend/ds/log.proto"; +import "proto/common.proto"; + +message Request { + message NtsRangeQuery { + /// Timestamp in nanoseconds + int64 after_nts = 1; + /// Timestamp in nanoseconds + int64 before_nts = 2; + } + + rivet.common.Uuid server_id = 1; + rivet.backend.ds.log.StreamType stream_type = 3; + int64 count = 4; + bool order_asc = 5; + + oneof query { + google.protobuf.Empty all = 101; + /// Timestamp in nanoseconds + int64 before_nts = 102; + /// Timestamp in nanoseconds + int64 after_nts = 103; + NtsRangeQuery nts_range = 104; + } +} + +message Response { + repeated rivet.backend.ds.log.LogEntry entries = 1; +} + diff --git a/svc/pkg/ds/ops/server-create/src/lib.rs b/svc/pkg/ds/ops/server-create/src/lib.rs index 70ced0cbf4..43eba26e58 100644 --- a/svc/pkg/ds/ops/server-create/src/lib.rs +++ b/svc/pkg/ds/ops/server-create/src/lib.rs @@ -627,6 +627,7 @@ pub async fn handle( "vector_socket_addr".into(), "image_artifact_url".into(), "root_user_enabled".into(), + "runner".into(), "user_env".into(), ]), meta_optional: Some(vec!["rivet_test_id".into()]), @@ -1266,6 +1267,10 @@ pub async fn handle( // other locations value: "0".into(), }, + backend::job::Parameter { + key: "runner".into(), + value: "dynamic_servers".into(), + }, backend::job::Parameter { key: "user_env".into(), // other locations diff --git a/svc/pkg/ds/worker/src/workers/nomad_monitor_alloc_plan.rs b/svc/pkg/ds/worker/src/workers/nomad_monitor_alloc_plan.rs index 003a21a106..5bee9ecc65 100644 --- a/svc/pkg/ds/worker/src/workers/nomad_monitor_alloc_plan.rs +++ b/svc/pkg/ds/worker/src/workers/nomad_monitor_alloc_plan.rs @@ -238,7 +238,7 @@ async fn update_db( [ctx, @tx tx] " INSERT INTO - db_dynamic_servers.server_ports ( + db_dynamic_servers.internal_ports ( server_id, nomad_label, nomad_source, diff --git a/svc/pkg/linode/worker/Cargo.toml b/svc/pkg/linode/worker/Cargo.toml deleted file mode 100644 index ced034a613..0000000000 --- a/svc/pkg/linode/worker/Cargo.toml +++ /dev/null @@ -1,25 +0,0 @@ -[package] -name = "linode-worker" -version = "0.0.1" -edition = "2018" -authors = ["Rivet Gaming, LLC "] -license = "Apache-2.0" - -[dependencies] -rivet-convert = { path = "../../../../lib/convert" } -chirp-client = { path = "../../../../lib/chirp/client" } -chirp-worker = { path = "../../../../lib/chirp/worker" } -rivet-health-checks = { path = "../../../../lib/health-checks" } -rivet-metrics = { path = "../../../../lib/metrics" } -rivet-runtime = { path = "../../../../lib/runtime" } -util-linode = { package = "rivet-util-linode", path = "../util" } - -cluster = { path = "../../cluster" } - -[dependencies.sqlx] -git = "https://github.com/rivet-gg/sqlx" -rev = "08d6e61aa0572e7ec557abbedb72cebb96e1ac5b" -default-features = false - -[dev-dependencies] -chirp-worker = { path = "../../../../lib/chirp/worker" } diff --git a/svc/pkg/linode/worker/Service.toml b/svc/pkg/linode/worker/Service.toml deleted file mode 100644 index 8c99c8e864..0000000000 --- a/svc/pkg/linode/worker/Service.toml +++ /dev/null @@ -1,11 +0,0 @@ -[service] -name = "linode-worker" - -[runtime] -kind = "rust" - -[consumer] - -[secrets] -"linode/token" = { optional = true } -"ssh/server/private_key_openssh" = {} diff --git a/svc/pkg/mm/worker/src/workers/lobby_create/mod.rs b/svc/pkg/mm/worker/src/workers/lobby_create/mod.rs index 3bac84cf86..a594349e4b 100644 --- a/svc/pkg/mm/worker/src/workers/lobby_create/mod.rs +++ b/svc/pkg/mm/worker/src/workers/lobby_create/mod.rs @@ -735,6 +735,10 @@ async fn create_docker_job( key: "root_user_enabled".into(), value: if mm_game_config.root_user_enabled { "1" } else { "0" }.into() }, + backend::job::Parameter { + key: "runner".into(), + value: "job_run".into() + }, ].into_iter() .chain(ctx.parameters.clone()) .collect(), diff --git a/svc/pkg/mm/worker/src/workers/lobby_create/nomad_job.rs b/svc/pkg/mm/worker/src/workers/lobby_create/nomad_job.rs index ab6bd8c097..e96d6aa7d8 100644 --- a/svc/pkg/mm/worker/src/workers/lobby_create/nomad_job.rs +++ b/svc/pkg/mm/worker/src/workers/lobby_create/nomad_job.rs @@ -405,6 +405,7 @@ pub fn gen_lobby_docker_job( "max_players_direct".into(), "max_players_party".into(), "root_user_enabled".into(), + "runner".into(), ]), meta_optional: Some(vec!["rivet_test_id".into()]), })),