Skip to content

Commit ec37e26

Browse files
Jeadieewgeniussgrebnov
authored
Add PVC block storage configuration for scheduler and executor in spidapter (spiceai#9925)
* update app storage API for cloud client * support PVC from spidapter * fix build * Fix lint --------- Co-authored-by: Evgenii Khramkov <evgenii@spice.ai> Co-authored-by: Sergei Grebnov <sergei.grebnov@gmail.com>
1 parent 38a8e28 commit ec37e26

5 files changed

Lines changed: 71 additions & 7 deletions

File tree

bin/spice/src/commands/cloud/client.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -161,9 +161,7 @@ impl CloudClient {
161161
replicas,
162162
image_tag: image_tag.map(String::from),
163163
region: region.map(String::from),
164-
spicepod: None,
165-
resources: None,
166-
executor: None,
164+
..Default::default()
167165
};
168166
self.inner
169167
.update_app(app.id, &request)

crates/spice-cloud-client/src/types.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ pub struct AppExecutor {
5757
pub replicas: Option<i32>,
5858
#[serde(skip_serializing_if = "Option::is_none")]
5959
pub resources: Option<AppResources>,
60+
#[serde(skip_serializing_if = "Option::is_none")]
61+
pub storage_size_gb: Option<f64>,
6062
}
6163

6264
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
@@ -71,6 +73,8 @@ pub struct AppConfig {
7173
pub executor: Option<AppExecutor>,
7274
pub region: Option<String>,
7375
pub node_group: Option<String>,
76+
pub storage_size_gb: Option<f64>,
77+
/// Deprecated: Use `storage_size_gb` instead.
7478
pub storage_claim_size_gb: Option<f64>,
7579
}
7680

@@ -116,7 +120,7 @@ pub struct CreateAppRequest {
116120
pub executor: Option<AppExecutor>,
117121
}
118122

119-
#[derive(Debug, Serialize)]
123+
#[derive(Debug, Serialize, Default)]
120124
pub struct UpdateAppRequest {
121125
#[serde(skip_serializing_if = "Option::is_none")]
122126
pub description: Option<String>,
@@ -134,6 +138,8 @@ pub struct UpdateAppRequest {
134138
pub resources: Option<AppResources>,
135139
#[serde(skip_serializing_if = "Option::is_none")]
136140
pub executor: Option<AppExecutor>,
141+
#[serde(skip_serializing_if = "Option::is_none")]
142+
pub storage_size_gb: Option<f64>,
137143
}
138144

139145
// ============================================================================

tools/spidapter/src/args/mod.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
Copyright 2024-2025 The Spice.ai OSS Authors
2+
Copyright 2024-2026 The Spice.ai OSS Authors
33
44
Licensed under the Apache License, Version 2.0 (the "License");
55
you may not use this file except in compliance with the License.
@@ -103,6 +103,14 @@ pub struct StdioArgs {
103103
#[arg(long, env = "SPIDAPTER_EXECUTOR_MEMORY_REQUEST")]
104104
pub executor_memory_request: Option<String>,
105105

106+
/// PVC block storage size in GB for the Spice Cloud app (scheduler) pod (e.g. `10`).
107+
#[arg(long, env = "SPIDAPTER_APP_STORAGE_SIZE_GB")]
108+
pub app_storage_size_gb: Option<f64>,
109+
110+
/// PVC block storage size in GB for the Spice Cloud executor pod (e.g. `5`).
111+
#[arg(long, env = "SPIDAPTER_EXECUTOR_STORAGE_SIZE_GB")]
112+
pub executor_storage_size_gb: Option<f64>,
113+
106114
/// S3 URL prefix for the spiced scheduler state location (e.g. `s3://bucket/state`).
107115
#[arg(long, env = "SCHEDULER_STATE_LOCATION")]
108116
pub scheduler_state_location: Option<String>,

tools/spidapter/src/commands/mod.rs

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
Copyright 2024-2025 The Spice.ai OSS Authors
2+
Copyright 2024-2026 The Spice.ai OSS Authors
33
44
Licensed under the Apache License, Version 2.0 (the "License");
55
you may not use this file except in compliance with the License.
@@ -34,11 +34,13 @@ pub(crate) struct AppCreateConfig {
3434
pub app_cpu_request: Option<String>,
3535
pub app_memory_request: Option<String>,
3636
pub app_replicas: Option<i32>,
37+
pub app_storage_size_gb: Option<f64>,
3738
pub executor_replicas: i32,
3839
pub executor_memory_limit: Option<String>,
3940
pub executor_cpu_limit: Option<String>,
4041
pub executor_cpu_request: Option<String>,
4142
pub executor_memory_request: Option<String>,
43+
pub executor_storage_size_gb: Option<f64>,
4244
}
4345

4446
pub(crate) fn spice_cloud_base_url(api_url_override: Option<&str>) -> String {
@@ -167,6 +169,7 @@ pub(crate) async fn ensure_spice_cloud_app(
167169
config.executor_cpu_request.as_deref(),
168170
config.executor_memory_request.as_deref(),
169171
)),
172+
storage_size_gb: config.executor_storage_size_gb,
170173
});
171174

172175
let create_result = cloud
@@ -186,11 +189,15 @@ pub(crate) async fn ensure_spice_cloud_app(
186189
.await;
187190

188191
match create_result {
189-
Ok(app) => Ok(app.id),
192+
Ok(app) => {
193+
apply_storage_config(cloud, app.id, config).await?;
194+
Ok(app.id)
195+
}
190196
Err(spice_cloud_client::error::Error::Conflict { .. }) => {
191197
// Race condition — another caller created it; re-fetch
192198
let apps = cloud.list_apps().await?;
193199
if let Some(app) = apps.into_iter().find(|a| a.name == app_name) {
200+
apply_storage_config(cloud, app.id, config).await?;
194201
return Ok(app.id);
195202
}
196203
Err(anyhow::anyhow!(
@@ -203,6 +210,46 @@ pub(crate) async fn ensure_spice_cloud_app(
203210
}
204211
}
205212

213+
/// Apply storage configuration to an app via the update API if any storage
214+
/// sizes are configured.
215+
async fn apply_storage_config(
216+
cloud: &CloudClient,
217+
app_id: i64,
218+
config: &AppCreateConfig,
219+
) -> anyhow::Result<()> {
220+
let has_storage =
221+
config.app_storage_size_gb.is_some() || config.executor_storage_size_gb.is_some();
222+
223+
if !has_storage {
224+
return Ok(());
225+
}
226+
227+
let executor = config.executor_storage_size_gb.map(|size| AppExecutor {
228+
replicas: None,
229+
resources: None,
230+
storage_size_gb: Some(size),
231+
});
232+
233+
cloud
234+
.update_app(
235+
app_id,
236+
&UpdateAppRequest {
237+
description: None,
238+
visibility: None,
239+
replicas: None,
240+
image_tag: None,
241+
region: None,
242+
spicepod: None,
243+
resources: None,
244+
executor,
245+
storage_size_gb: config.app_storage_size_gb,
246+
},
247+
)
248+
.await?;
249+
250+
Ok(())
251+
}
252+
206253
pub(crate) async fn resolve_default_cname(cloud: &CloudClient) -> anyhow::Result<String> {
207254
let regions = cloud.list_regions(None).await?;
208255

@@ -259,6 +306,7 @@ pub(crate) async fn apply_spicepod_to_app(
259306
spicepod: Some(spicepod_yaml.to_string()),
260307
resources: None,
261308
executor: None,
309+
storage_size_gb: None,
262310
},
263311
)
264312
.await?;

tools/spidapter/src/stdio_server.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -599,11 +599,13 @@ async fn provision_spice_cloud_app(
599599
app_cpu_request: args.app_cpu_request.clone(),
600600
app_memory_request: args.app_memory_request.clone(),
601601
app_replicas: args.app_replicas,
602+
app_storage_size_gb: args.app_storage_size_gb,
602603
executor_replicas: args.executor_replicas,
603604
executor_memory_limit: args.executor_memory_limit.clone(),
604605
executor_cpu_limit: args.executor_cpu_limit.clone(),
605606
executor_cpu_request: args.executor_cpu_request.clone(),
606607
executor_memory_request: args.executor_memory_request.clone(),
608+
executor_storage_size_gb: args.executor_storage_size_gb,
607609
};
608610
let app_id = commands::ensure_spice_cloud_app(&cloud, &app_name, &app_create_config).await?;
609611

@@ -1583,6 +1585,8 @@ mod tests {
15831585
executor_cpu_limit: None,
15841586
executor_cpu_request: None,
15851587
executor_memory_request: None,
1588+
app_storage_size_gb: None,
1589+
executor_storage_size_gb: None,
15861590
scheduler_state_location: Some("s3://bucket/state".to_string()),
15871591
aws_region: None,
15881592
cayenne_data_dir: None,

0 commit comments

Comments
 (0)