mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-09-29 01:42:21 +00:00
feat: remove volumes from environment settings
Drop the `volumes` field and `EnvironmentVolumeSettings` type from the environment/sandbox configuration model across the whole stack: - OpenAPI: remove `volumes` from Environment, Create/Replace requests, RunEnvironmentSettings, and EnvironmentSettings; delete the EnvironmentVolumeSettings schema. - Generated clients: regenerate Rust types and TypeScript models; drop the EnvironmentVolumeSettings model and its exports. - Config/env: remove the volumes layer, settings->layer conversion, and TOML serialization in fabro-config and fabro-environment. - Sandbox/server/workflow: drop volume plumbing in fabro-sandbox (incl. Daytona), run manifest, and start operation. - Migration: legacy daytona volumes are now reported unsupported rather than migrated. - Docs and tests updated to match. cargo check --workspace passes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
f8fdb5c2f4
commit
6e9d7e4079
32 changed files with 70 additions and 412 deletions
|
|
@ -258,7 +258,7 @@ On a same-machine setup, `settings.toml` is the shared machine-default layer und
|
|||
|
||||
On a remote setup, the client bundles workflow, project, and user config into the run manifest. The server then layers those bundled client configs over its own local defaults for run-shaped fields. Server-owned values like `[server.storage]`, `[server.api]`, `[server.web]`, and `[server.scheduler]` always come from the server machine's own `settings.toml` or `fabro server start` flags.
|
||||
|
||||
Merge rules follow the normative matrix: TOML `[run.inputs]` tables replace wholesale, CLI `-I` / `--input` values replayed from run manifests merge per key at highest precedence, environment `env` and `labels` merge by key, environment `volumes` replace as a whole list, `[run.prepare.steps]` replaces whole-list, and `[[run.hooks]]` merge by optional `id`. Most other fields use "higher-precedence wins" field-wise merging.
|
||||
Merge rules follow the normative matrix: TOML `[run.inputs]` tables replace wholesale, CLI `-I` / `--input` values replayed from run manifests merge per key at highest precedence, environment `env` and `labels` merge by key, `[run.prepare.steps]` replaces whole-list, and `[[run.hooks]]` merge by optional `id`. Most other fields use "higher-precedence wins" field-wise merging.
|
||||
|
||||
### `[server.logging]` section
|
||||
|
||||
|
|
|
|||
|
|
@ -6316,7 +6316,6 @@ components:
|
|||
- network
|
||||
- lifecycle
|
||||
- labels
|
||||
- volumes
|
||||
- env
|
||||
properties:
|
||||
id:
|
||||
|
|
@ -6340,10 +6339,6 @@ components:
|
|||
$ref: "#/components/schemas/EnvironmentLifecycleSettings"
|
||||
labels:
|
||||
$ref: "#/components/schemas/StringMap"
|
||||
volumes:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/EnvironmentVolumeSettings"
|
||||
env:
|
||||
type: object
|
||||
additionalProperties:
|
||||
|
|
@ -6361,7 +6356,6 @@ components:
|
|||
- network
|
||||
- lifecycle
|
||||
- labels
|
||||
- volumes
|
||||
- env
|
||||
properties:
|
||||
id:
|
||||
|
|
@ -6380,10 +6374,6 @@ components:
|
|||
$ref: "#/components/schemas/EnvironmentLifecycleSettings"
|
||||
labels:
|
||||
$ref: "#/components/schemas/StringMap"
|
||||
volumes:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/EnvironmentVolumeSettings"
|
||||
env:
|
||||
type: object
|
||||
additionalProperties:
|
||||
|
|
@ -6400,7 +6390,6 @@ components:
|
|||
- network
|
||||
- lifecycle
|
||||
- labels
|
||||
- volumes
|
||||
- env
|
||||
properties:
|
||||
provider:
|
||||
|
|
@ -6415,10 +6404,6 @@ components:
|
|||
$ref: "#/components/schemas/EnvironmentLifecycleSettings"
|
||||
labels:
|
||||
$ref: "#/components/schemas/StringMap"
|
||||
volumes:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/EnvironmentVolumeSettings"
|
||||
env:
|
||||
type: object
|
||||
additionalProperties:
|
||||
|
|
@ -13269,7 +13254,7 @@ components:
|
|||
|
||||
RunEnvironmentSettings:
|
||||
type: object
|
||||
required: [id, provider, image, resources, network, lifecycle, labels, volumes, env]
|
||||
required: [id, provider, image, resources, network, lifecycle, labels, env]
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
|
|
@ -13285,10 +13270,6 @@ components:
|
|||
$ref: "#/components/schemas/EnvironmentLifecycleSettings"
|
||||
labels:
|
||||
$ref: "#/components/schemas/StringMap"
|
||||
volumes:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/EnvironmentVolumeSettings"
|
||||
env:
|
||||
type: object
|
||||
additionalProperties:
|
||||
|
|
@ -13296,7 +13277,7 @@ components:
|
|||
|
||||
EnvironmentSettings:
|
||||
type: object
|
||||
required: [provider, image, resources, network, lifecycle, labels, volumes, env]
|
||||
required: [provider, image, resources, network, lifecycle, labels, env]
|
||||
properties:
|
||||
provider:
|
||||
$ref: "#/components/schemas/EnvironmentProvider"
|
||||
|
|
@ -13310,10 +13291,6 @@ components:
|
|||
$ref: "#/components/schemas/EnvironmentLifecycleSettings"
|
||||
labels:
|
||||
$ref: "#/components/schemas/StringMap"
|
||||
volumes:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/EnvironmentVolumeSettings"
|
||||
env:
|
||||
type: object
|
||||
additionalProperties:
|
||||
|
|
@ -13373,17 +13350,6 @@ components:
|
|||
auto_stop:
|
||||
type: ["string", "null"]
|
||||
|
||||
EnvironmentVolumeSettings:
|
||||
type: object
|
||||
required: [id, mount_path, subpath]
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
mount_path:
|
||||
type: string
|
||||
subpath:
|
||||
type: ["string", "null"]
|
||||
|
||||
DockerfileSource:
|
||||
oneOf:
|
||||
- $ref: "#/components/schemas/DockerfileSourceInline"
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ description: "Reusable named execution environments for workflow runs"
|
|||
|
||||
Fabro separates **environments** from **sandboxes**:
|
||||
|
||||
- An **environment** is reusable desired configuration: provider, image, resources, network, lifecycle, labels, volumes, and environment variables.
|
||||
- An **environment** is reusable desired configuration: provider, image, resources, network, lifecycle, labels, and environment variables.
|
||||
- A **sandbox** is the concrete runtime instance Fabro creates for a run from the selected environment.
|
||||
|
||||
<Warning>
|
||||
|
|
@ -52,11 +52,6 @@ auto_stop = "30m"
|
|||
[environments.fabro-dev.labels]
|
||||
repo = "fabro-sh/fabro"
|
||||
|
||||
[[environments.fabro-dev.volumes]]
|
||||
id = "vol-agent-state"
|
||||
mount_path = "/home/daytona/agent-state"
|
||||
subpath = "auth"
|
||||
|
||||
[environments.fabro-dev.env]
|
||||
NODE_ENV = "development"
|
||||
```
|
||||
|
|
@ -74,7 +69,7 @@ memory = "32GB"
|
|||
preserve = true
|
||||
```
|
||||
|
||||
`env` and `labels` merge by key. `volumes` replace as a whole list when set at a higher-precedence layer.
|
||||
`env` and `labels` merge by key.
|
||||
|
||||
## Selecting an environment from the CLI
|
||||
|
||||
|
|
@ -122,7 +117,6 @@ stop_on_terminal = true
|
|||
| `network.mode = "block"` | Error | Docker `none` network | Daytona block |
|
||||
| `network.mode = "cidr_allow_list"` | Error | Error | Daytona CIDR allow-list |
|
||||
| `labels` | Warning; ignored | Warning; ignored | Daytona labels |
|
||||
| `volumes` | Warning; ignored | Warning; ignored | Daytona volume mounts |
|
||||
| `lifecycle.auto_stop` | Warning; ignored | Warning; ignored | Daytona auto-stop |
|
||||
| `env` | Process environment overlay | Container environment | Sandbox environment |
|
||||
|
||||
|
|
@ -191,11 +185,3 @@ mode = "cidr_allow_list"
|
|||
allow = ["208.80.154.232/32", "10.0.0.0/8"]
|
||||
```
|
||||
|
||||
Daytona volumes reference existing provider-managed volumes:
|
||||
|
||||
```toml
|
||||
[[environments.cloud.volumes]]
|
||||
id = "vol-agent-state"
|
||||
mount_path = "/home/daytona/agent-state"
|
||||
subpath = "agent-auth"
|
||||
```
|
||||
|
|
|
|||
|
|
@ -282,7 +282,6 @@ memory = "8GB"
|
|||
| `lifecycle.stop_on_terminal` | Stop the sandbox when the run reaches a terminal state. |
|
||||
| `lifecycle.auto_stop` | Daytona auto-stop duration, such as `"30m"`. |
|
||||
| `labels` | Provider labels. Merge by key across layers. |
|
||||
| `volumes` | Provider volume hints. Lists replace wholesale across layers. |
|
||||
| `env` | Environment variables passed to command and agent execution. Merge by key across layers. |
|
||||
|
||||
When `provider = "local"`, Fabro runs directly in the resolved working
|
||||
|
|
@ -560,7 +559,7 @@ provider = "daytona"
|
|||
dockerfile = { path = "Dockerfile" }
|
||||
```
|
||||
|
||||
Project defaults and workflow config values merge per the normative merge matrix: most fields merge by field (higher-precedence wins per key), TOML `run.inputs` tables replace wholesale, CLI input flags merge per key at highest precedence, environment `env` and `labels` merge by key, environment `volumes` replace as a whole list, and `run.prepare.steps` replaces whole-list.
|
||||
Project defaults and workflow config values merge per the normative merge matrix: most fields merge by field (higher-precedence wins per key), TOML `run.inputs` tables replace wholesale, CLI input flags merge per key at highest precedence, environment `env` and `labels` merge by key, and `run.prepare.steps` replaces whole-list.
|
||||
|
||||
### Machine defaults
|
||||
|
||||
|
|
|
|||
|
|
@ -36,7 +36,6 @@ fn environment_settings_json() -> serde_json::Value {
|
|||
"auto_stop": null
|
||||
},
|
||||
"labels": {},
|
||||
"volumes": [],
|
||||
"env": {}
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -955,8 +955,7 @@ fn attach_json_errors_without_prompting_for_human_input() {
|
|||
"cpu": null,
|
||||
"disk": null,
|
||||
"memory": null
|
||||
},
|
||||
"volumes": []
|
||||
}
|
||||
},
|
||||
"execution": {
|
||||
"approval": "prompt",
|
||||
|
|
|
|||
|
|
@ -183,7 +183,6 @@ fn inspect_resolves_selector_via_server_endpoint() {
|
|||
"auto_stop": null
|
||||
},
|
||||
"labels": {},
|
||||
"volumes": [],
|
||||
"env": {}
|
||||
},
|
||||
"notifications": {},
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use std::path::Path;
|
|||
use std::str::FromStr;
|
||||
|
||||
use fabro_types::settings::run::EnvironmentProvider;
|
||||
use toml_edit::{ArrayOfTables, DocumentMut, Item, Table, Value};
|
||||
use toml_edit::{DocumentMut, Item, Table, Value};
|
||||
|
||||
use crate::{Error, Result};
|
||||
|
||||
|
|
@ -205,7 +205,6 @@ fn migrate_daytona(sandbox: &Table, env: &mut Table, unsupported: &mut Vec<Strin
|
|||
}
|
||||
}
|
||||
"snapshot" => migrate_daytona_snapshot(item, env, unsupported),
|
||||
"volumes" => copy_array_of_tables_with_volume_id(item, env, unsupported),
|
||||
_ => item_path_keys(&format!("run.sandbox.daytona.{key}"), item, unsupported),
|
||||
}
|
||||
}
|
||||
|
|
@ -291,50 +290,6 @@ fn copy_table(source: &Item, target: &mut Table) {
|
|||
}
|
||||
}
|
||||
|
||||
fn copy_array_of_tables_with_volume_id(
|
||||
source: &Item,
|
||||
target: &mut Table,
|
||||
unsupported: &mut Vec<String>,
|
||||
) {
|
||||
let Some(volumes) = source.as_array_of_tables() else {
|
||||
unsupported.push("run.sandbox.daytona.volumes".to_string());
|
||||
return;
|
||||
};
|
||||
|
||||
let mut migrated = ArrayOfTables::new();
|
||||
for volume in volumes {
|
||||
let mut migrated_volume = Table::new();
|
||||
let mut has_id = false;
|
||||
let mut has_mount_path = false;
|
||||
for (key, item) in volume {
|
||||
match key {
|
||||
"volume_id" => {
|
||||
has_id = true;
|
||||
migrated_volume["id"] = item.clone();
|
||||
}
|
||||
"mount_path" => {
|
||||
has_mount_path = true;
|
||||
migrated_volume["mount_path"] = item.clone();
|
||||
}
|
||||
"subpath" => migrated_volume["subpath"] = item.clone(),
|
||||
_ => item_path_keys(
|
||||
&format!("run.sandbox.daytona.volumes.{key}"),
|
||||
item,
|
||||
unsupported,
|
||||
),
|
||||
}
|
||||
}
|
||||
if !has_id {
|
||||
unsupported.push("run.sandbox.daytona.volumes.volume_id".to_string());
|
||||
}
|
||||
if !has_mount_path {
|
||||
unsupported.push("run.sandbox.daytona.volumes.mount_path".to_string());
|
||||
}
|
||||
migrated.push(migrated_volume);
|
||||
}
|
||||
target["volumes"] = Item::ArrayOfTables(migrated);
|
||||
}
|
||||
|
||||
fn item_path_keys(prefix: &str, item: &Item, out: &mut Vec<String>) {
|
||||
if let Some(table) = item.as_table() {
|
||||
if table.is_empty() {
|
||||
|
|
@ -418,7 +373,7 @@ provider = "daytona"
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn daytona_snapshot_labels_lifecycle_and_volumes_migrate() {
|
||||
fn daytona_snapshot_labels_and_lifecycle_migrate() {
|
||||
let migrated = migrate(
|
||||
r#"
|
||||
_version = 1
|
||||
|
|
@ -442,11 +397,6 @@ cpu = 8
|
|||
memory = "16GB"
|
||||
disk = "20GB"
|
||||
dockerfile = { path = "Dockerfile" }
|
||||
|
||||
[[run.sandbox.daytona.volumes]]
|
||||
volume_id = "vol_auth"
|
||||
mount_path = "/home/daytona/.config"
|
||||
subpath = "agents"
|
||||
"#,
|
||||
);
|
||||
|
||||
|
|
@ -486,10 +436,30 @@ subpath = "agents"
|
|||
resolved.env.get("NODE_ENV").map(InterpString::as_source),
|
||||
Some("development".to_string())
|
||||
);
|
||||
assert_eq!(resolved.volumes.len(), 1);
|
||||
assert_eq!(resolved.volumes[0].id, "vol_auth");
|
||||
assert_eq!(resolved.volumes[0].mount_path, "/home/daytona/.config");
|
||||
assert_eq!(resolved.volumes[0].subpath.as_deref(), Some("agents"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn daytona_volumes_are_reported_unsupported() {
|
||||
let err = migrate_contents(
|
||||
r#"
|
||||
_version = 1
|
||||
|
||||
[run.sandbox]
|
||||
provider = "daytona"
|
||||
|
||||
[[run.sandbox.daytona.volumes]]
|
||||
volume_id = "vol_auth"
|
||||
mount_path = "/home/daytona/.config"
|
||||
"#,
|
||||
Path::new("settings.toml"),
|
||||
)
|
||||
.expect_err("daytona volumes can no longer be migrated");
|
||||
|
||||
let message = err.to_string();
|
||||
assert!(
|
||||
message.contains("run.sandbox.daytona.volumes"),
|
||||
"message was: {message}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ use fabro_types::settings::{Duration, InterpString, Size};
|
|||
|
||||
use super::LogFilter;
|
||||
use super::cli::{CliAuthLayer, CliLoggingLayer, CliTargetLayer};
|
||||
use super::environment::{EnvironmentDockerfileLayer, EnvironmentVolumeLayer};
|
||||
use super::environment::EnvironmentDockerfileLayer;
|
||||
use super::llm::{CostRates, CredentialRef, HeaderValueRef, ReasoningEffortFeature};
|
||||
use super::run::{
|
||||
HookAgentMarker, HookEntry, HookTlsMode, InterviewProviderLayer, ModelRefOrSplice,
|
||||
|
|
@ -45,12 +45,6 @@ impl<T: Combine> Combine for Option<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl Combine for Option<Vec<EnvironmentVolumeLayer>> {
|
||||
fn combine(self, other: Self) -> Self {
|
||||
self.or(other)
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_combine_or_option {
|
||||
($($ty:ty),+ $(,)?) => {
|
||||
$(
|
||||
|
|
|
|||
|
|
@ -21,8 +21,6 @@ pub struct EnvironmentLayer {
|
|||
pub lifecycle: Option<EnvironmentLifecycleLayer>,
|
||||
#[serde(default, skip_serializing_if = "StickyMap::is_empty")]
|
||||
pub labels: StickyMap<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub volumes: Option<Vec<EnvironmentVolumeLayer>>,
|
||||
#[serde(default, skip_serializing_if = "StickyMap::is_empty")]
|
||||
pub env: StickyMap<InterpString>,
|
||||
}
|
||||
|
|
@ -42,8 +40,6 @@ pub struct RunEnvironmentLayer {
|
|||
pub lifecycle: Option<EnvironmentLifecycleLayer>,
|
||||
#[serde(default, skip_serializing_if = "StickyMap::is_empty")]
|
||||
pub labels: StickyMap<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub volumes: Option<Vec<EnvironmentVolumeLayer>>,
|
||||
#[serde(default, skip_serializing_if = "StickyMap::is_empty")]
|
||||
pub env: StickyMap<InterpString>,
|
||||
}
|
||||
|
|
@ -58,7 +54,6 @@ impl RunEnvironmentLayer {
|
|||
network: self.network,
|
||||
lifecycle: self.lifecycle,
|
||||
labels: self.labels,
|
||||
volumes: self.volumes,
|
||||
env: self.env,
|
||||
}
|
||||
}
|
||||
|
|
@ -117,15 +112,6 @@ pub struct EnvironmentLifecycleLayer {
|
|||
pub auto_stop: Option<Duration>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct EnvironmentVolumeLayer {
|
||||
pub id: String,
|
||||
pub mount_path: String,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub subpath: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(untagged, deny_unknown_fields)]
|
||||
pub enum EnvironmentDockerfileLayer {
|
||||
|
|
|
|||
|
|
@ -18,8 +18,7 @@ pub use cli::{
|
|||
pub(crate) use combine::Combine;
|
||||
pub use environment::{
|
||||
EnvironmentDockerfileLayer, EnvironmentImageLayer, EnvironmentLayer, EnvironmentLifecycleLayer,
|
||||
EnvironmentNetworkLayer, EnvironmentResourcesLayer, EnvironmentVolumeLayer,
|
||||
RunEnvironmentLayer,
|
||||
EnvironmentNetworkLayer, EnvironmentResourcesLayer, RunEnvironmentLayer,
|
||||
};
|
||||
pub use llm::{
|
||||
CostRates, CredentialRef, CredentialRefParseError, HeaderValueRef, LlmLayer, ModelControls,
|
||||
|
|
|
|||
|
|
@ -44,21 +44,21 @@ pub use layers::{
|
|||
CliAuthLayer, CliExecAgentLayer, CliExecLayer, CliExecModelLayer, CliLayer, CliLoggingLayer,
|
||||
CliOutputLayer, CliTargetLayer, CliUpdatesLayer, CostRates, CredentialRef,
|
||||
CredentialRefParseError, EnvironmentDockerfileLayer, EnvironmentImageLayer, EnvironmentLayer,
|
||||
EnvironmentLifecycleLayer, EnvironmentNetworkLayer, EnvironmentResourcesLayer,
|
||||
EnvironmentVolumeLayer, GitAuthorLayer, GithubIntegrationLayer, HeaderValueRef,
|
||||
HookAgentMarker, HookEntry, HookTlsMode, IntegrationWebhooksLayer, InterviewProviderLayer,
|
||||
InterviewsLayer, LlmLayer, LlmModelFeatures, LlmModelLimits, LogFilter, McpEntryLayer,
|
||||
MergeMap, ModelControls, ModelCostTable, ModelRefOrSplice, ModelSettings,
|
||||
NotificationProviderLayer, NotificationRouteLayer, ObjectStoreLocalLayer, ObjectStoreS3Layer,
|
||||
PrepareStep, ProjectLayer, ProviderSettings, ReasoningEffortFeature, ReplaceMap, RunAgentLayer,
|
||||
RunArtifactsLayer, RunCheckpointLayer, RunCloneLayer, RunEnvironmentLayer, RunExecutionLayer,
|
||||
RunGitLayer, RunGoalLayer, RunIntegrationsGithubLayer, RunIntegrationsLayer, RunLayer,
|
||||
RunMetaBranchLayer, RunModelControlsLayer, RunModelLayer, RunPrepareLayer, RunPullRequestLayer,
|
||||
RunRunBranchLayer, RunScmLayer, ScmGitHubLayer, ServerApiLayer, ServerArtifactsLayer,
|
||||
ServerAuthGithubLayer, ServerAuthLayer, ServerIntegrationsLayer, ServerLayer,
|
||||
ServerListenLayer, ServerLoggingLayer, ServerSandboxLayer, ServerSandboxProviderLayer,
|
||||
ServerSandboxProvidersLayer, ServerSchedulerLayer, ServerSlateDbLayer, ServerStorageLayer,
|
||||
ServerWebLayer, SettingsLayer, SlackIntegrationLayer, StickyMap, StringOrSplice, WorkflowLayer,
|
||||
EnvironmentLifecycleLayer, EnvironmentNetworkLayer, EnvironmentResourcesLayer, GitAuthorLayer,
|
||||
GithubIntegrationLayer, HeaderValueRef, HookAgentMarker, HookEntry, HookTlsMode,
|
||||
IntegrationWebhooksLayer, InterviewProviderLayer, InterviewsLayer, LlmLayer, LlmModelFeatures,
|
||||
LlmModelLimits, LogFilter, McpEntryLayer, MergeMap, ModelControls, ModelCostTable,
|
||||
ModelRefOrSplice, ModelSettings, NotificationProviderLayer, NotificationRouteLayer,
|
||||
ObjectStoreLocalLayer, ObjectStoreS3Layer, PrepareStep, ProjectLayer, ProviderSettings,
|
||||
ReasoningEffortFeature, ReplaceMap, RunAgentLayer, RunArtifactsLayer, RunCheckpointLayer,
|
||||
RunCloneLayer, RunEnvironmentLayer, RunExecutionLayer, RunGitLayer, RunGoalLayer,
|
||||
RunIntegrationsGithubLayer, RunIntegrationsLayer, RunLayer, RunMetaBranchLayer,
|
||||
RunModelControlsLayer, RunModelLayer, RunPrepareLayer, RunPullRequestLayer, RunRunBranchLayer,
|
||||
RunScmLayer, ScmGitHubLayer, ServerApiLayer, ServerArtifactsLayer, ServerAuthGithubLayer,
|
||||
ServerAuthLayer, ServerIntegrationsLayer, ServerLayer, ServerListenLayer, ServerLoggingLayer,
|
||||
ServerSandboxLayer, ServerSandboxProviderLayer, ServerSandboxProvidersLayer,
|
||||
ServerSchedulerLayer, ServerSlateDbLayer, ServerStorageLayer, ServerWebLayer, SettingsLayer,
|
||||
SlackIntegrationLayer, StickyMap, StringOrSplice, WorkflowLayer,
|
||||
};
|
||||
pub use logging::{resolve_log_destination, resolve_log_destination_with_env};
|
||||
pub use parse::ParseError;
|
||||
|
|
|
|||
|
|
@ -1,15 +1,14 @@
|
|||
use fabro_types::settings::run::{
|
||||
DockerfileSource, EnvironmentImageSettings, EnvironmentLifecycleSettings,
|
||||
EnvironmentNetworkMode, EnvironmentNetworkSettings, EnvironmentProvider,
|
||||
EnvironmentResourcesSettings, EnvironmentSettings, EnvironmentVolumeSettings,
|
||||
RunEnvironmentSettings,
|
||||
EnvironmentResourcesSettings, EnvironmentSettings, RunEnvironmentSettings,
|
||||
};
|
||||
|
||||
use super::ResolveError;
|
||||
use crate::{
|
||||
Combine, EnvironmentDockerfileLayer, EnvironmentImageLayer, EnvironmentLayer,
|
||||
EnvironmentLifecycleLayer, EnvironmentNetworkLayer, EnvironmentResourcesLayer,
|
||||
EnvironmentVolumeLayer, MergeMap, RunEnvironmentLayer,
|
||||
EnvironmentLifecycleLayer, EnvironmentNetworkLayer, EnvironmentResourcesLayer, MergeMap,
|
||||
RunEnvironmentLayer,
|
||||
};
|
||||
|
||||
pub(crate) fn resolve_run_environment(
|
||||
|
|
@ -77,7 +76,6 @@ fn resolve_environment_fields(
|
|||
network: resolve_network(layer.network.as_ref(), &format!("{path}.network"), errors),
|
||||
lifecycle: resolve_lifecycle(layer.lifecycle.as_ref()),
|
||||
labels: layer.labels.clone().into_inner(),
|
||||
volumes: resolve_volumes(layer.volumes.as_deref()),
|
||||
env: layer.env.clone().into_inner(),
|
||||
};
|
||||
validate_daytona_image_settings(&environment, path, errors);
|
||||
|
|
@ -174,18 +172,6 @@ fn resolve_lifecycle(layer: Option<&EnvironmentLifecycleLayer>) -> EnvironmentLi
|
|||
}
|
||||
}
|
||||
|
||||
fn resolve_volumes(layers: Option<&[EnvironmentVolumeLayer]>) -> Vec<EnvironmentVolumeSettings> {
|
||||
layers
|
||||
.unwrap_or(&[])
|
||||
.iter()
|
||||
.map(|volume| EnvironmentVolumeSettings {
|
||||
id: volume.id.clone(),
|
||||
mount_path: volume.mount_path.clone(),
|
||||
subpath: volume.subpath.clone(),
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn dockerfile_source(dockerfile: &EnvironmentDockerfileLayer) -> DockerfileSource {
|
||||
match dockerfile {
|
||||
EnvironmentDockerfileLayer::Inline(text) => DockerfileSource::Inline(text.clone()),
|
||||
|
|
|
|||
|
|
@ -127,11 +127,6 @@ auto_stop = "30m"
|
|||
[environments.fabro-dev.labels]
|
||||
repo = "fabro-sh/fabro"
|
||||
|
||||
[[environments.fabro-dev.volumes]]
|
||||
id = "vol_auth"
|
||||
mount_path = "/home/daytona/.config"
|
||||
subpath = "agents"
|
||||
|
||||
[environments.fabro-dev.env]
|
||||
NODE_ENV = "development"
|
||||
"#,
|
||||
|
|
@ -170,10 +165,6 @@ NODE_ENV = "development"
|
|||
environment.labels.get("repo").map(String::as_str),
|
||||
Some("fabro-sh/fabro")
|
||||
);
|
||||
assert_eq!(environment.volumes.len(), 1);
|
||||
assert_eq!(environment.volumes[0].id, "vol_auth");
|
||||
assert_eq!(environment.volumes[0].mount_path, "/home/daytona/.config");
|
||||
assert_eq!(environment.volumes[0].subpath.as_deref(), Some("agents"));
|
||||
assert_eq!(
|
||||
environment
|
||||
.env
|
||||
|
|
|
|||
|
|
@ -3,17 +3,17 @@ use std::path::Path;
|
|||
|
||||
use fabro_config::{
|
||||
EnvironmentDockerfileLayer, EnvironmentImageLayer, EnvironmentLayer, EnvironmentLifecycleLayer,
|
||||
EnvironmentNetworkLayer, EnvironmentResourcesLayer, EnvironmentVolumeLayer, StickyMap,
|
||||
EnvironmentNetworkLayer, EnvironmentResourcesLayer, StickyMap,
|
||||
};
|
||||
use fabro_types::settings::InterpString;
|
||||
use fabro_types::settings::run::{
|
||||
DockerfileSource, EnvironmentImageSettings, EnvironmentLifecycleSettings,
|
||||
EnvironmentNetworkMode, EnvironmentNetworkSettings, EnvironmentResourcesSettings,
|
||||
EnvironmentSettings, EnvironmentVolumeSettings,
|
||||
EnvironmentSettings,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tokio::fs;
|
||||
use toml_edit::{Array, ArrayOfTables, DocumentMut, Item, Table, Value, value};
|
||||
use toml_edit::{Array, DocumentMut, Item, Table, Value, value};
|
||||
|
||||
use crate::{
|
||||
EnvironmentId, EnvironmentRevision, EnvironmentStoreError, EnvironmentValidationError,
|
||||
|
|
@ -114,9 +114,6 @@ pub(crate) fn canonical_bytes(layer: &EnvironmentLayer) -> String {
|
|||
append_lifecycle(doc.as_table_mut(), lifecycle);
|
||||
}
|
||||
append_string_map(doc.as_table_mut(), "labels", &layer.labels);
|
||||
if let Some(volumes) = layer.volumes.as_deref() {
|
||||
append_volumes(doc.as_table_mut(), volumes);
|
||||
}
|
||||
append_interp_map(doc.as_table_mut(), "env", &layer.env);
|
||||
doc.to_string()
|
||||
}
|
||||
|
|
@ -188,7 +185,6 @@ fn environment_settings_to_layer(settings: &EnvironmentSettings) -> EnvironmentL
|
|||
network: network_settings_to_layer(&settings.network),
|
||||
lifecycle: lifecycle_settings_to_layer(&settings.lifecycle),
|
||||
labels: StickyMap::from(settings.labels.clone()),
|
||||
volumes: volumes_settings_to_layer(&settings.volumes),
|
||||
env: StickyMap::from(settings.env.clone()),
|
||||
}
|
||||
}
|
||||
|
|
@ -248,23 +244,6 @@ fn lifecycle_settings_to_layer(
|
|||
})
|
||||
}
|
||||
|
||||
fn volumes_settings_to_layer(
|
||||
settings: &[EnvironmentVolumeSettings],
|
||||
) -> Option<Vec<EnvironmentVolumeLayer>> {
|
||||
if settings.is_empty() {
|
||||
return None;
|
||||
}
|
||||
Some(settings.iter().map(volume_settings_to_layer).collect())
|
||||
}
|
||||
|
||||
fn volume_settings_to_layer(settings: &EnvironmentVolumeSettings) -> EnvironmentVolumeLayer {
|
||||
EnvironmentVolumeLayer {
|
||||
id: settings.id.clone(),
|
||||
mount_path: settings.mount_path.clone(),
|
||||
subpath: settings.subpath.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
fn append_image(root: &mut Table, image: &EnvironmentImageLayer) {
|
||||
let table = ensure_table(root, &["image"]);
|
||||
if let Some(docker) = image.docker.as_deref() {
|
||||
|
|
@ -339,23 +318,6 @@ fn append_interp_map(root: &mut Table, name: &str, map: &StickyMap<InterpString>
|
|||
}
|
||||
}
|
||||
|
||||
fn append_volumes(root: &mut Table, volumes: &[EnvironmentVolumeLayer]) {
|
||||
if volumes.is_empty() {
|
||||
return;
|
||||
}
|
||||
let mut array = ArrayOfTables::new();
|
||||
for volume in volumes {
|
||||
let mut table = Table::new();
|
||||
table["id"] = value(volume.id.as_str());
|
||||
table["mount_path"] = value(volume.mount_path.as_str());
|
||||
if let Some(subpath) = volume.subpath.as_deref() {
|
||||
table["subpath"] = value(subpath);
|
||||
}
|
||||
array.push(table);
|
||||
}
|
||||
root["volumes"] = Item::ArrayOfTables(array);
|
||||
}
|
||||
|
||||
fn ensure_table<'a>(root: &'a mut Table, path: &[&str]) -> &'a mut Table {
|
||||
let mut current = root;
|
||||
for key in path {
|
||||
|
|
|
|||
|
|
@ -466,7 +466,6 @@ mod tests {
|
|||
network: EnvironmentNetworkSettings::default(),
|
||||
lifecycle: EnvironmentLifecycleSettings::default(),
|
||||
labels: HashMap::new(),
|
||||
volumes: Vec::new(),
|
||||
env: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,21 +16,12 @@ use serde::{Deserialize, Serialize};
|
|||
pub struct DaytonaSettings {
|
||||
pub auto_stop_interval: Option<i32>,
|
||||
pub labels: Option<HashMap<String, String>>,
|
||||
#[serde(default)]
|
||||
pub volumes: Vec<DaytonaVolumeMount>,
|
||||
pub snapshot: Option<DaytonaSnapshotSettings>,
|
||||
pub network: Option<DaytonaNetwork>,
|
||||
#[serde(default)]
|
||||
pub skip_clone: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
|
||||
pub struct DaytonaVolumeMount {
|
||||
pub volume_id: String,
|
||||
pub mount_path: String,
|
||||
pub subpath: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum DaytonaNetwork {
|
||||
Block,
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ pub const REQUIRED_DAYTONA_PERMISSIONS: &[Permissions] = &[
|
|||
|
||||
pub use crate::config::{
|
||||
DaytonaNetwork, DaytonaSettings as DaytonaConfig,
|
||||
DaytonaSnapshotSettings as DaytonaSnapshotConfig, DaytonaVolumeMount, DockerfileSource,
|
||||
DaytonaSnapshotSettings as DaytonaSnapshotConfig, DockerfileSource,
|
||||
};
|
||||
|
||||
pub mod snapshot_identity {
|
||||
|
|
@ -173,20 +173,6 @@ fn perm_wire_str(permission: Permissions) -> &'static str {
|
|||
}
|
||||
}
|
||||
|
||||
fn volume_mounts_for_create(config: &DaytonaConfig) -> Option<Vec<daytona_sdk::VolumeMount>> {
|
||||
(!config.volumes.is_empty()).then(|| {
|
||||
config
|
||||
.volumes
|
||||
.iter()
|
||||
.map(|volume| daytona_sdk::VolumeMount {
|
||||
volume_id: volume.volume_id.clone(),
|
||||
mount_path: volume.mount_path.clone(),
|
||||
subpath: volume.subpath.clone(),
|
||||
})
|
||||
.collect()
|
||||
})
|
||||
}
|
||||
|
||||
/// Build a [`daytona_sdk::Client`], forwarding an optional API key from the
|
||||
/// vault so the SDK doesn't have to rely on `DAYTONA_API_KEY` being in the
|
||||
/// process environment.
|
||||
|
|
@ -555,7 +541,6 @@ impl DaytonaSandbox {
|
|||
ephemeral: Some(false),
|
||||
network_block_all,
|
||||
network_allow_list,
|
||||
volumes: volume_mounts_for_create(&self.config),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
|
@ -2368,45 +2353,6 @@ mod tests {
|
|||
assert!(config.snapshot.is_none());
|
||||
assert!(config.auto_stop_interval.is_none());
|
||||
assert!(config.labels.is_none());
|
||||
assert!(config.volumes.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parses_volume_mounts_from_config() {
|
||||
let config: DaytonaConfig = toml::from_str(
|
||||
r#"
|
||||
[[volumes]]
|
||||
volume_id = "vol_auth"
|
||||
mount_path = "/home/daytona/.config"
|
||||
subpath = "agents"
|
||||
"#,
|
||||
)
|
||||
.expect("volume config should parse");
|
||||
|
||||
assert_eq!(config.volumes, vec![DaytonaVolumeMount {
|
||||
volume_id: "vol_auth".to_string(),
|
||||
mount_path: "/home/daytona/.config".to_string(),
|
||||
subpath: Some("agents".to_string()),
|
||||
}]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn maps_volume_mounts_to_daytona_create_params() {
|
||||
let config = DaytonaConfig {
|
||||
volumes: vec![DaytonaVolumeMount {
|
||||
volume_id: "vol_auth".to_string(),
|
||||
mount_path: "/home/daytona/.config".to_string(),
|
||||
subpath: Some("agents".to_string()),
|
||||
}],
|
||||
..DaytonaConfig::default()
|
||||
};
|
||||
|
||||
let volumes = volume_mounts_for_create(&config).expect("volumes should map");
|
||||
|
||||
assert_eq!(volumes.len(), 1);
|
||||
assert_eq!(volumes[0].volume_id, "vol_auth");
|
||||
assert_eq!(volumes[0].mount_path, "/home/daytona/.config");
|
||||
assert_eq!(volumes[0].subpath.as_deref(), Some("agents"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
|
|
@ -9,8 +9,7 @@ use fabro_types::settings::run::{EnvironmentNetworkMode, RunEnvironmentSettings}
|
|||
|
||||
#[cfg(feature = "daytona")]
|
||||
use crate::config::{
|
||||
DaytonaNetwork, DaytonaSnapshotSettings, DaytonaVolumeMount,
|
||||
DockerfileSource as SandboxDockerfileSource,
|
||||
DaytonaNetwork, DaytonaSnapshotSettings, DockerfileSource as SandboxDockerfileSource,
|
||||
};
|
||||
#[cfg(feature = "daytona")]
|
||||
use crate::daytona::DaytonaConfig;
|
||||
|
|
@ -29,15 +28,6 @@ pub fn daytona_config_from_environment(
|
|||
.auto_stop
|
||||
.map(|duration| duration_to_minutes_i32(duration.as_std())),
|
||||
labels: (!settings.labels.is_empty()).then(|| settings.labels.clone()),
|
||||
volumes: settings
|
||||
.volumes
|
||||
.iter()
|
||||
.map(|volume| DaytonaVolumeMount {
|
||||
volume_id: volume.id.clone(),
|
||||
mount_path: volume.mount_path.clone(),
|
||||
subpath: volume.subpath.clone(),
|
||||
})
|
||||
.collect(),
|
||||
snapshot: settings
|
||||
.image
|
||||
.dockerfile
|
||||
|
|
|
|||
|
|
@ -696,9 +696,6 @@ fn environment_capability_warnings(resolved_run: &RunNamespace) -> Vec<String> {
|
|||
{
|
||||
warnings.push("local provider ignores resource limits".to_string());
|
||||
}
|
||||
if !environment.volumes.is_empty() {
|
||||
warnings.push("local provider ignores volume mounts".to_string());
|
||||
}
|
||||
if !environment.labels.is_empty() {
|
||||
warnings.push("local provider ignores labels".to_string());
|
||||
}
|
||||
|
|
@ -710,9 +707,6 @@ fn environment_capability_warnings(resolved_run: &RunNamespace) -> Vec<String> {
|
|||
if environment.resources.disk.is_some() {
|
||||
warnings.push("docker provider ignores disk resource limits".to_string());
|
||||
}
|
||||
if !environment.volumes.is_empty() {
|
||||
warnings.push("docker provider ignores volume mounts".to_string());
|
||||
}
|
||||
if !environment.labels.is_empty() {
|
||||
warnings.push("docker provider ignores labels".to_string());
|
||||
}
|
||||
|
|
@ -1545,27 +1539,6 @@ enabled = {clone_enabled}
|
|||
(prepared, resolved)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn runtime_daytona_config_preserves_volume_mounts() {
|
||||
let settings = fabro_types::settings::run::RunEnvironmentSettings::from_environment(
|
||||
"cloud".to_string(),
|
||||
fabro_types::settings::run::EnvironmentSettings {
|
||||
volumes: vec![fabro_types::settings::run::EnvironmentVolumeSettings {
|
||||
id: "vol_auth".to_string(),
|
||||
mount_path: "/home/daytona/.config".to_string(),
|
||||
subpath: Some("agents".to_string()),
|
||||
}],
|
||||
..fabro_types::settings::run::EnvironmentSettings::default()
|
||||
},
|
||||
);
|
||||
|
||||
let config = daytona_config_from_environment(&settings, false);
|
||||
|
||||
assert_eq!(config.volumes.len(), 1);
|
||||
assert_eq!(config.volumes[0].volume_id, "vol_auth");
|
||||
assert_eq!(config.volumes[0].mount_path, "/home/daytona/.config");
|
||||
assert_eq!(config.volumes[0].subpath.as_deref(), Some("agents"));
|
||||
}
|
||||
#[test]
|
||||
fn prepare_manifest_accepts_project_environment_catalog_definitions() {
|
||||
let mut manifest = minimal_manifest();
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use fabro_types::settings::InterpString;
|
|||
use fabro_types::settings::run::{
|
||||
DockerfileSource, EnvironmentImageSettings, EnvironmentLifecycleSettings,
|
||||
EnvironmentNetworkSettings, EnvironmentProvider, EnvironmentResourcesSettings,
|
||||
EnvironmentSettings, EnvironmentVolumeSettings,
|
||||
EnvironmentSettings,
|
||||
};
|
||||
use serde::de::IgnoredAny;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
|
@ -39,7 +39,6 @@ struct CreateEnvironmentRequest {
|
|||
network: EnvironmentNetworkSettings,
|
||||
lifecycle: EnvironmentLifecycleSettings,
|
||||
labels: HashMap<String, String>,
|
||||
volumes: Vec<EnvironmentVolumeSettings>,
|
||||
env: HashMap<String, InterpString>,
|
||||
}
|
||||
|
||||
|
|
@ -52,7 +51,6 @@ struct ReplaceEnvironmentRequest {
|
|||
network: EnvironmentNetworkSettings,
|
||||
lifecycle: EnvironmentLifecycleSettings,
|
||||
labels: HashMap<String, String>,
|
||||
volumes: Vec<EnvironmentVolumeSettings>,
|
||||
env: HashMap<String, InterpString>,
|
||||
}
|
||||
|
||||
|
|
@ -88,7 +86,6 @@ impl CreateEnvironmentRequest {
|
|||
network: self.network,
|
||||
lifecycle: self.lifecycle,
|
||||
labels: self.labels,
|
||||
volumes: self.volumes,
|
||||
env: self.env,
|
||||
},
|
||||
})
|
||||
|
|
@ -104,7 +101,6 @@ impl ReplaceEnvironmentRequest {
|
|||
network: self.network,
|
||||
lifecycle: self.lifecycle,
|
||||
labels: self.labels,
|
||||
volumes: self.volumes,
|
||||
env: self.env,
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,7 +34,6 @@ fn environment_settings(provider: &str) -> Value {
|
|||
"auto_stop": null
|
||||
},
|
||||
"labels": {},
|
||||
"volumes": [],
|
||||
"env": {}
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,13 +36,13 @@ pub use public_url::{
|
|||
pub use run::{
|
||||
ArtifactsSettings, DockerfileSource, EnvironmentImageSettings, EnvironmentLifecycleSettings,
|
||||
EnvironmentNetworkMode, EnvironmentNetworkSettings, EnvironmentProvider,
|
||||
EnvironmentResourcesSettings, EnvironmentSettings, EnvironmentVolumeSettings,
|
||||
GitAuthorSettings, HookDefinition, HookType, InterviewProviderSettings, McpServerSettings,
|
||||
McpTransport, NotificationProviderSettings, NotificationRouteSettings, PullRequestSettings,
|
||||
RunAgentSettings, RunCheckpointSettings, RunEnvironmentSettings, RunExecutionSettings,
|
||||
RunGitSettings, RunGoal, RunIntegrationsGithubSettings, RunIntegrationsSettings,
|
||||
RunInterviewsSettings, RunModelControls, RunModelSettings, RunNamespace, RunPrepareSettings,
|
||||
RunScmSettings, ScmGitHubSettings, TlsMode,
|
||||
EnvironmentResourcesSettings, EnvironmentSettings, GitAuthorSettings, HookDefinition, HookType,
|
||||
InterviewProviderSettings, McpServerSettings, McpTransport, NotificationProviderSettings,
|
||||
NotificationRouteSettings, PullRequestSettings, RunAgentSettings, RunCheckpointSettings,
|
||||
RunEnvironmentSettings, RunExecutionSettings, RunGitSettings, RunGoal,
|
||||
RunIntegrationsGithubSettings, RunIntegrationsSettings, RunInterviewsSettings,
|
||||
RunModelControls, RunModelSettings, RunNamespace, RunPrepareSettings, RunScmSettings,
|
||||
ScmGitHubSettings, TlsMode,
|
||||
};
|
||||
pub use server::{
|
||||
GithubIntegrationSettings, IntegrationWebhooksSettings, LogDestination, ObjectStoreSettings,
|
||||
|
|
|
|||
|
|
@ -260,11 +260,6 @@ where
|
|||
substitute_dockerfile_source(&mut environment.image.dockerfile, lookup)?;
|
||||
substitute_string_vec(&mut environment.network.allow, lookup)?;
|
||||
substitute_string_map(&mut environment.labels, lookup)?;
|
||||
for volume in &mut environment.volumes {
|
||||
substitute_string(&mut volume.id, lookup)?;
|
||||
substitute_string(&mut volume.mount_path, lookup)?;
|
||||
substitute_option_string(&mut volume.subpath, lookup)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -309,8 +304,8 @@ mod run_namespace_variable_substitution_tests {
|
|||
|
||||
use super::{
|
||||
ArtifactsSettings, DockerfileSource, EnvironmentImageSettings, EnvironmentNetworkMode,
|
||||
EnvironmentNetworkSettings, EnvironmentVolumeSettings, HookDefinition, HookEvent, HookType,
|
||||
InterpString, McpHttpProtocol, McpServerSettings, McpTransport, RunCheckpointSettings,
|
||||
EnvironmentNetworkSettings, HookDefinition, HookEvent, HookType, InterpString,
|
||||
McpHttpProtocol, McpServerSettings, McpTransport, RunCheckpointSettings,
|
||||
RunEnvironmentSettings, RunGoal, RunNamespace, RunPrepareSettings,
|
||||
};
|
||||
|
||||
|
|
@ -428,11 +423,6 @@ mod run_namespace_variable_substitution_tests {
|
|||
allow: vec!["{{ vars.CIDR }}".to_string()],
|
||||
},
|
||||
labels: HashMap::from([("deploy-env".to_string(), "{{ vars.ENV }}".to_string())]),
|
||||
volumes: vec![EnvironmentVolumeSettings {
|
||||
id: "vol_{{ vars.ENV }}".to_string(),
|
||||
mount_path: "/mnt/{{ vars.ENV }}".to_string(),
|
||||
subpath: Some("cache/{{ vars.ENV }}".to_string()),
|
||||
}],
|
||||
..RunEnvironmentSettings::default()
|
||||
},
|
||||
artifacts: ArtifactsSettings {
|
||||
|
|
@ -464,12 +454,6 @@ mod run_namespace_variable_substitution_tests {
|
|||
run.environment.labels.get("deploy-env").map(String::as_str),
|
||||
Some("prod")
|
||||
);
|
||||
assert_eq!(run.environment.volumes[0].id, "vol_prod");
|
||||
assert_eq!(run.environment.volumes[0].mount_path, "/mnt/prod");
|
||||
assert_eq!(
|
||||
run.environment.volumes[0].subpath.as_deref(),
|
||||
Some("cache/prod")
|
||||
);
|
||||
assert_eq!(run.artifacts.include, vec!["reports/prod/**"]);
|
||||
}
|
||||
}
|
||||
|
|
@ -803,13 +787,6 @@ impl Default for EnvironmentLifecycleSettings {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
|
||||
pub struct EnvironmentVolumeSettings {
|
||||
pub id: String,
|
||||
pub mount_path: String,
|
||||
pub subpath: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct EnvironmentSettings {
|
||||
pub provider: EnvironmentProvider,
|
||||
|
|
@ -818,7 +795,6 @@ pub struct EnvironmentSettings {
|
|||
pub network: EnvironmentNetworkSettings,
|
||||
pub lifecycle: EnvironmentLifecycleSettings,
|
||||
pub labels: HashMap<String, String>,
|
||||
pub volumes: Vec<EnvironmentVolumeSettings>,
|
||||
pub env: HashMap<String, InterpString>,
|
||||
}
|
||||
|
||||
|
|
@ -831,7 +807,6 @@ impl Default for EnvironmentSettings {
|
|||
network: EnvironmentNetworkSettings::default(),
|
||||
lifecycle: EnvironmentLifecycleSettings::default(),
|
||||
labels: HashMap::new(),
|
||||
volumes: Vec::new(),
|
||||
env: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
|
@ -846,7 +821,6 @@ pub struct RunEnvironmentSettings {
|
|||
pub network: EnvironmentNetworkSettings,
|
||||
pub lifecycle: EnvironmentLifecycleSettings,
|
||||
pub labels: HashMap<String, String>,
|
||||
pub volumes: Vec<EnvironmentVolumeSettings>,
|
||||
pub env: HashMap<String, InterpString>,
|
||||
}
|
||||
|
||||
|
|
@ -861,7 +835,6 @@ impl RunEnvironmentSettings {
|
|||
network: environment.network,
|
||||
lifecycle: environment.lifecycle,
|
||||
labels: environment.labels,
|
||||
volumes: environment.volumes,
|
||||
env: environment.env,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1122,9 +1122,8 @@ mod tests {
|
|||
|
||||
use chrono::Utc;
|
||||
use fabro_config::{
|
||||
EnvironmentImageLayer, EnvironmentNetworkLayer, EnvironmentResourcesLayer,
|
||||
EnvironmentVolumeLayer, RunCloneLayer, RunEnvironmentLayer, RunExecutionLayer, RunLayer,
|
||||
StickyMap, WorkflowSettingsBuilder,
|
||||
EnvironmentImageLayer, EnvironmentNetworkLayer, EnvironmentResourcesLayer, RunCloneLayer,
|
||||
RunEnvironmentLayer, RunExecutionLayer, RunLayer, StickyMap, WorkflowSettingsBuilder,
|
||||
};
|
||||
use fabro_store::Database;
|
||||
use fabro_types::settings::run::RunMode;
|
||||
|
|
@ -1353,28 +1352,6 @@ reasoning = false
|
|||
assert_eq!(config.env_vars, vec!["NODE_ENV=test"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn runtime_daytona_config_preserves_volume_mounts() {
|
||||
let settings = settings_from_run_layer(RunLayer {
|
||||
environment: Some(RunEnvironmentLayer {
|
||||
volumes: Some(vec![EnvironmentVolumeLayer {
|
||||
id: "vol_auth".to_string(),
|
||||
mount_path: "/home/daytona/.config".to_string(),
|
||||
subpath: Some("agents".to_string()),
|
||||
}]),
|
||||
..RunEnvironmentLayer::default()
|
||||
}),
|
||||
..RunLayer::default()
|
||||
});
|
||||
|
||||
let config = resolve_daytona_config(&settings.run);
|
||||
|
||||
assert_eq!(config.volumes.len(), 1);
|
||||
assert_eq!(config.volumes[0].volume_id, "vol_auth");
|
||||
assert_eq!(config.volumes[0].mount_path, "/home/daytona/.config");
|
||||
assert_eq!(config.volumes[0].subpath.as_deref(), Some("agents"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn start_record_git_options_honor_disabled_run_branch() {
|
||||
let mut settings = WorkflowSettings::default();
|
||||
|
|
|
|||
|
|
@ -131,7 +131,6 @@ models/environment-network-settings.ts
|
|||
models/environment-provider.ts
|
||||
models/environment-resources-settings.ts
|
||||
models/environment-settings.ts
|
||||
models/environment-volume-settings.ts
|
||||
models/environment.ts
|
||||
models/error-response-entry.ts
|
||||
models/error-response.ts
|
||||
|
|
|
|||
|
|
@ -28,9 +28,6 @@ import type { EnvironmentProvider } from './environment-provider';
|
|||
// May contain unused imports in some cases
|
||||
// @ts-ignore
|
||||
import type { EnvironmentResourcesSettings } from './environment-resources-settings';
|
||||
// May contain unused imports in some cases
|
||||
// @ts-ignore
|
||||
import type { EnvironmentVolumeSettings } from './environment-volume-settings';
|
||||
|
||||
/**
|
||||
* Request body for creating a server-managed environment.
|
||||
|
|
@ -43,6 +40,5 @@ export interface CreateEnvironmentRequest {
|
|||
'network': EnvironmentNetworkSettings;
|
||||
'lifecycle': EnvironmentLifecycleSettings;
|
||||
'labels': { [key: string]: string; };
|
||||
'volumes': Array<EnvironmentVolumeSettings>;
|
||||
'env': { [key: string]: string; };
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,9 +28,6 @@ import type { EnvironmentProvider } from './environment-provider';
|
|||
// May contain unused imports in some cases
|
||||
// @ts-ignore
|
||||
import type { EnvironmentResourcesSettings } from './environment-resources-settings';
|
||||
// May contain unused imports in some cases
|
||||
// @ts-ignore
|
||||
import type { EnvironmentVolumeSettings } from './environment-volume-settings';
|
||||
|
||||
export interface EnvironmentSettings {
|
||||
'provider': EnvironmentProvider;
|
||||
|
|
@ -39,6 +36,5 @@ export interface EnvironmentSettings {
|
|||
'network': EnvironmentNetworkSettings;
|
||||
'lifecycle': EnvironmentLifecycleSettings;
|
||||
'labels': { [key: string]: string; };
|
||||
'volumes': Array<EnvironmentVolumeSettings>;
|
||||
'env': { [key: string]: string; };
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,9 +28,6 @@ import type { EnvironmentProvider } from './environment-provider';
|
|||
// May contain unused imports in some cases
|
||||
// @ts-ignore
|
||||
import type { EnvironmentResourcesSettings } from './environment-resources-settings';
|
||||
// May contain unused imports in some cases
|
||||
// @ts-ignore
|
||||
import type { EnvironmentVolumeSettings } from './environment-volume-settings';
|
||||
|
||||
/**
|
||||
* Public server-managed environment definition.
|
||||
|
|
@ -47,6 +44,5 @@ export interface Environment {
|
|||
'network': EnvironmentNetworkSettings;
|
||||
'lifecycle': EnvironmentLifecycleSettings;
|
||||
'labels': { [key: string]: string; };
|
||||
'volumes': Array<EnvironmentVolumeSettings>;
|
||||
'env': { [key: string]: string; };
|
||||
}
|
||||
|
|
|
|||
|
|
@ -105,7 +105,6 @@ export * from './environment-network-settings';
|
|||
export * from './environment-provider';
|
||||
export * from './environment-resources-settings';
|
||||
export * from './environment-settings';
|
||||
export * from './environment-volume-settings';
|
||||
export * from './error-response';
|
||||
export * from './error-response-entry';
|
||||
export * from './event-envelope';
|
||||
|
|
|
|||
|
|
@ -28,9 +28,6 @@ import type { EnvironmentProvider } from './environment-provider';
|
|||
// May contain unused imports in some cases
|
||||
// @ts-ignore
|
||||
import type { EnvironmentResourcesSettings } from './environment-resources-settings';
|
||||
// May contain unused imports in some cases
|
||||
// @ts-ignore
|
||||
import type { EnvironmentVolumeSettings } from './environment-volume-settings';
|
||||
|
||||
/**
|
||||
* Request body for replacing a server-managed environment. The path id is authoritative.
|
||||
|
|
@ -42,6 +39,5 @@ export interface ReplaceEnvironmentRequest {
|
|||
'network': EnvironmentNetworkSettings;
|
||||
'lifecycle': EnvironmentLifecycleSettings;
|
||||
'labels': { [key: string]: string; };
|
||||
'volumes': Array<EnvironmentVolumeSettings>;
|
||||
'env': { [key: string]: string; };
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,9 +28,6 @@ import type { EnvironmentProvider } from './environment-provider';
|
|||
// May contain unused imports in some cases
|
||||
// @ts-ignore
|
||||
import type { EnvironmentResourcesSettings } from './environment-resources-settings';
|
||||
// May contain unused imports in some cases
|
||||
// @ts-ignore
|
||||
import type { EnvironmentVolumeSettings } from './environment-volume-settings';
|
||||
|
||||
export interface RunEnvironmentSettings {
|
||||
'id': string;
|
||||
|
|
@ -40,6 +37,5 @@ export interface RunEnvironmentSettings {
|
|||
'network': EnvironmentNetworkSettings;
|
||||
'lifecycle': EnvironmentLifecycleSettings;
|
||||
'labels': { [key: string]: string; };
|
||||
'volumes': Array<EnvironmentVolumeSettings>;
|
||||
'env': { [key: string]: string; };
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue