Skip to main content

quantum_sdk/
compute.rs

1use serde::{Deserialize, Serialize};
2
3use crate::client::Client;
4use crate::error::Result;
5use crate::keys::StatusResponse;
6
7/// A compute instance template describing available GPU configurations.
8#[derive(Debug, Clone, Deserialize)]
9pub struct ComputeTemplate {
10    /// Template identifier (e.g. "a100-80gb", "h100-sxm").
11    pub id: String,
12
13    /// Human-readable name.
14    #[serde(default)]
15    pub name: Option<String>,
16
17    /// GPU type description.
18    #[serde(default)]
19    pub gpu: Option<String>,
20
21    /// Number of GPUs.
22    #[serde(default)]
23    pub gpu_count: Option<i32>,
24
25    /// VRAM per GPU in GB.
26    #[serde(default)]
27    pub vram_gb: Option<i32>,
28
29    /// CPU cores.
30    #[serde(default)]
31    pub vcpus: Option<i32>,
32
33    /// RAM in GB.
34    #[serde(default)]
35    pub ram_gb: Option<i32>,
36
37    /// Price per hour in USD.
38    #[serde(default)]
39    pub price_per_hour_usd: Option<f64>,
40
41    /// Available zones.
42    #[serde(default)]
43    pub zones: Option<Vec<String>>,
44}
45
46/// Response from listing compute templates.
47#[derive(Debug, Clone, Deserialize)]
48pub struct TemplatesResponse {
49    /// Available compute templates.
50    pub templates: Vec<ComputeTemplate>,
51}
52
53/// Request body for provisioning a compute instance.
54#[derive(Debug, Clone, Serialize, Default)]
55pub struct ProvisionRequest {
56    /// Template ID to provision.
57    pub template: String,
58
59    /// Preferred zone (e.g. "us-central1-a").
60    #[serde(skip_serializing_if = "Option::is_none")]
61    pub zone: Option<String>,
62
63    /// Use spot/preemptible pricing.
64    #[serde(skip_serializing_if = "Option::is_none")]
65    pub spot: Option<bool>,
66
67    /// Auto-teardown after N minutes of inactivity.
68    #[serde(skip_serializing_if = "Option::is_none")]
69    pub auto_teardown_minutes: Option<i32>,
70
71    /// SSH public key for access.
72    #[serde(skip_serializing_if = "Option::is_none")]
73    pub ssh_public_key: Option<String>,
74}
75
76/// Response from provisioning a compute instance.
77#[derive(Debug, Clone, Deserialize)]
78pub struct ProvisionResponse {
79    /// Instance identifier.
80    pub instance_id: String,
81
82    /// Current instance status.
83    pub status: String,
84
85    /// Template that was provisioned.
86    #[serde(default)]
87    pub template: Option<String>,
88
89    /// Zone the instance was placed in.
90    #[serde(default)]
91    pub zone: Option<String>,
92
93    /// SSH connection address.
94    #[serde(default)]
95    pub ssh_address: Option<String>,
96
97    /// Estimated price per hour.
98    #[serde(default)]
99    pub price_per_hour_usd: Option<f64>,
100}
101
102/// A running compute instance.
103#[derive(Debug, Clone, Deserialize)]
104pub struct ComputeInstance {
105    /// Instance identifier.
106    pub id: String,
107
108    /// Current status (e.g. "running", "provisioning", "stopped").
109    pub status: String,
110
111    /// Template used.
112    #[serde(default)]
113    pub template: Option<String>,
114
115    /// Zone.
116    #[serde(default)]
117    pub zone: Option<String>,
118
119    /// SSH connection address.
120    #[serde(default)]
121    pub ssh_address: Option<String>,
122
123    /// Creation timestamp.
124    #[serde(default)]
125    pub created_at: Option<String>,
126
127    /// Price per hour.
128    #[serde(default)]
129    pub price_per_hour_usd: Option<f64>,
130
131    /// Auto-teardown setting in minutes.
132    #[serde(default)]
133    pub auto_teardown_minutes: Option<i32>,
134}
135
136/// Response from listing compute instances.
137#[derive(Debug, Clone, Deserialize)]
138pub struct InstancesResponse {
139    /// Running compute instances.
140    pub instances: Vec<ComputeInstance>,
141}
142
143/// Response from getting a single compute instance.
144#[derive(Debug, Clone, Deserialize)]
145pub struct InstanceResponse {
146    /// The compute instance details.
147    pub instance: ComputeInstance,
148}
149
150/// Response from deleting a compute instance.
151#[derive(Debug, Clone, Deserialize)]
152pub struct DeleteResponse {
153    /// Status message.
154    pub status: String,
155
156    /// Instance that was deleted.
157    #[serde(default)]
158    pub instance_id: Option<String>,
159}
160
161/// Request body for adding an SSH key to an instance.
162#[derive(Debug, Clone, Serialize, Default)]
163pub struct SSHKeyRequest {
164    /// SSH public key to add.
165    pub ssh_public_key: String,
166}
167
168/// Request for querying compute billing from BigQuery.
169#[derive(Debug, Clone, Serialize, Default)]
170pub struct BillingRequest {
171    /// Filter by instance ID.
172    #[serde(skip_serializing_if = "Option::is_none")]
173    pub instance_id: Option<String>,
174
175    /// Start date for billing period (ISO 8601).
176    #[serde(skip_serializing_if = "Option::is_none")]
177    pub start_date: Option<String>,
178
179    /// End date for billing period (ISO 8601).
180    #[serde(skip_serializing_if = "Option::is_none")]
181    pub end_date: Option<String>,
182}
183
184/// A single billing line item from BigQuery.
185#[derive(Debug, Clone, Deserialize)]
186pub struct BillingEntry {
187    /// Instance identifier.
188    pub instance_id: String,
189
190    /// Instance name.
191    #[serde(default)]
192    pub instance_name: Option<String>,
193
194    /// Total cost in USD.
195    pub cost_usd: f64,
196
197    /// Usage duration in hours.
198    #[serde(default)]
199    pub usage_hours: Option<f64>,
200
201    /// SKU description (e.g. "N1 Predefined Instance Core").
202    #[serde(default)]
203    pub sku_description: Option<String>,
204
205    /// Billing period start.
206    #[serde(default)]
207    pub start_time: Option<String>,
208
209    /// Billing period end.
210    #[serde(default)]
211    pub end_time: Option<String>,
212}
213
214/// Response from billing query.
215#[derive(Debug, Clone, Deserialize)]
216pub struct BillingResponse {
217    /// Individual billing entries.
218    pub entries: Vec<BillingEntry>,
219
220    /// Total cost across all entries.
221    pub total_cost_usd: f64,
222}
223
224impl Client {
225    /// Lists available compute templates (GPU configurations and pricing).
226    pub async fn compute_templates(&self) -> Result<TemplatesResponse> {
227        let (resp, _meta) = self
228            .get_json::<TemplatesResponse>("/qai/v1/compute/templates")
229            .await?;
230        Ok(resp)
231    }
232
233    /// Provisions a new GPU compute instance.
234    pub async fn compute_provision(&self, req: &ProvisionRequest) -> Result<ProvisionResponse> {
235        let (resp, _meta) = self
236            .post_json::<ProvisionRequest, ProvisionResponse>("/qai/v1/compute/provision", req)
237            .await?;
238        Ok(resp)
239    }
240
241    /// Lists all compute instances for the account.
242    pub async fn compute_instances(&self) -> Result<InstancesResponse> {
243        let (resp, _meta) = self
244            .get_json::<InstancesResponse>("/qai/v1/compute/instances")
245            .await?;
246        Ok(resp)
247    }
248
249    /// Gets details for a specific compute instance.
250    pub async fn compute_instance(&self, id: &str) -> Result<InstanceResponse> {
251        let path = format!("/qai/v1/compute/instance/{id}");
252        let (resp, _meta) = self.get_json::<InstanceResponse>(&path).await?;
253        Ok(resp)
254    }
255
256    /// Deletes (tears down) a compute instance.
257    pub async fn compute_delete(&self, id: &str) -> Result<DeleteResponse> {
258        let path = format!("/qai/v1/compute/instance/{id}");
259        let (resp, _meta) = self.delete_json::<DeleteResponse>(&path).await?;
260        Ok(resp)
261    }
262
263    /// Adds an SSH public key to a running compute instance.
264    pub async fn compute_ssh_key(&self, id: &str, req: &SSHKeyRequest) -> Result<StatusResponse> {
265        let path = format!("/qai/v1/compute/instance/{id}/ssh-key");
266        let (resp, _meta) = self
267            .post_json::<SSHKeyRequest, StatusResponse>(&path, req)
268            .await?;
269        Ok(resp)
270    }
271
272    /// Sends a keepalive to prevent auto-teardown of a compute instance.
273    pub async fn compute_keepalive(&self, id: &str) -> Result<StatusResponse> {
274        let path = format!("/qai/v1/compute/instance/{id}/keepalive");
275        let (resp, _meta) = self
276            .post_json::<serde_json::Value, StatusResponse>(&path, &serde_json::json!({}))
277            .await?;
278        Ok(resp)
279    }
280
281    /// Queries compute billing from BigQuery via the QAI backend.
282    pub async fn compute_billing(&self, req: &BillingRequest) -> Result<BillingResponse> {
283        let (resp, _meta) = self
284            .post_json::<BillingRequest, BillingResponse>("/qai/v1/compute/billing", req)
285            .await?;
286        Ok(resp)
287    }
288}