feat(wfe-core): root_workflow_id, SharedVolume, configurable shell, StepExecutionContext.definition
This commit is contained in:
@@ -240,6 +240,7 @@ impl WorkflowExecutor {
|
|||||||
persistence_data: workflow.execution_pointers[idx].persistence_data.as_ref(),
|
persistence_data: workflow.execution_pointers[idx].persistence_data.as_ref(),
|
||||||
step,
|
step,
|
||||||
workflow: &workflow,
|
workflow: &workflow,
|
||||||
|
definition: Some(definition),
|
||||||
cancellation_token,
|
cancellation_token,
|
||||||
host_context,
|
host_context,
|
||||||
log_sink: self.log_sink.as_deref(),
|
log_sink: self.log_sink.as_deref(),
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ pub use service::{
|
|||||||
ReadinessCheck, ReadinessProbe, ServiceDefinition, ServiceEndpoint, ServicePort,
|
ReadinessCheck, ReadinessProbe, ServiceDefinition, ServiceEndpoint, ServicePort,
|
||||||
};
|
};
|
||||||
pub use status::{PointerStatus, WorkflowStatus};
|
pub use status::{PointerStatus, WorkflowStatus};
|
||||||
pub use workflow_definition::{StepOutcome, WorkflowDefinition, WorkflowStep};
|
pub use workflow_definition::{SharedVolume, StepOutcome, WorkflowDefinition, WorkflowStep};
|
||||||
pub use workflow_instance::WorkflowInstance;
|
pub use workflow_instance::WorkflowInstance;
|
||||||
|
|
||||||
/// Serde helper for `Option<Duration>` as milliseconds.
|
/// Serde helper for `Option<Duration>` as milliseconds.
|
||||||
|
|||||||
@@ -6,6 +6,37 @@ use super::condition::StepCondition;
|
|||||||
use super::error_behavior::ErrorBehavior;
|
use super::error_behavior::ErrorBehavior;
|
||||||
use super::service::ServiceDefinition;
|
use super::service::ServiceDefinition;
|
||||||
|
|
||||||
|
/// Declaration of a volume that persists across every step in a workflow
|
||||||
|
/// run, including sub-workflows started via `type: workflow` steps. Backends
|
||||||
|
/// that support it (currently just Kubernetes) provision a single volume
|
||||||
|
/// per top-level workflow instance and mount it on every step container at
|
||||||
|
/// `mount_path`. Sub-workflows see the same volume because they share the
|
||||||
|
/// parent's isolation domain (namespace, in the K8s case).
|
||||||
|
///
|
||||||
|
/// Declared once on the top-level workflow (e.g. `ci`) that orchestrates
|
||||||
|
/// the sub-workflows. Declarations on non-root workflows are ignored in
|
||||||
|
/// favor of the root's declaration.
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||||
|
pub struct SharedVolume {
|
||||||
|
/// Absolute path the volume is mounted at inside every step container.
|
||||||
|
/// Typical value: `/workspace`.
|
||||||
|
pub mount_path: String,
|
||||||
|
/// Optional size override (e.g. `"20Gi"`). When unset the backend falls
|
||||||
|
/// back to its configured default (ClusterConfig::default_shared_volume_size
|
||||||
|
/// for the Kubernetes executor).
|
||||||
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
|
pub size: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for SharedVolume {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
mount_path: "/workspace".to_string(),
|
||||||
|
size: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A compiled workflow definition ready for execution.
|
/// A compiled workflow definition ready for execution.
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct WorkflowDefinition {
|
pub struct WorkflowDefinition {
|
||||||
@@ -26,6 +57,12 @@ pub struct WorkflowDefinition {
|
|||||||
/// Infrastructure services required by this workflow (databases, caches, etc.).
|
/// Infrastructure services required by this workflow (databases, caches, etc.).
|
||||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||||
pub services: Vec<ServiceDefinition>,
|
pub services: Vec<ServiceDefinition>,
|
||||||
|
/// When set, the backend provisions a single persistent volume for the
|
||||||
|
/// top-level workflow instance and mounts it on every step container.
|
||||||
|
/// All sub-workflows inherit the same volume through their shared
|
||||||
|
/// namespace/isolation domain. Sub-workflow declarations are ignored.
|
||||||
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
|
pub shared_volume: Option<SharedVolume>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WorkflowDefinition {
|
impl WorkflowDefinition {
|
||||||
@@ -39,6 +76,7 @@ impl WorkflowDefinition {
|
|||||||
default_error_behavior: ErrorBehavior::default(),
|
default_error_behavior: ErrorBehavior::default(),
|
||||||
default_error_retry_interval: None,
|
default_error_retry_interval: None,
|
||||||
services: Vec::new(),
|
services: Vec::new(),
|
||||||
|
shared_volume: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,18 @@ pub struct WorkflowInstance {
|
|||||||
/// `id` in lookup APIs. Empty when the instance has not yet been
|
/// `id` in lookup APIs. Empty when the instance has not yet been
|
||||||
/// persisted (the host fills it in before the first insert).
|
/// persisted (the host fills it in before the first insert).
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
/// UUID of the top-level ancestor workflow. `None` on the root
|
||||||
|
/// (user-started) workflow; set to the parent's `root_workflow_id`
|
||||||
|
/// (or the parent's `id` if the parent is itself a root) on every
|
||||||
|
/// `SubWorkflowStep`-created child.
|
||||||
|
///
|
||||||
|
/// Used by the Kubernetes executor to place all workflows in a tree
|
||||||
|
/// under a single namespace — siblings started via `type: workflow`
|
||||||
|
/// steps share the parent's namespace and any provisioned shared
|
||||||
|
/// volume. Backends that don't care about workflow topology can
|
||||||
|
/// ignore this field.
|
||||||
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
|
pub root_workflow_id: Option<String>,
|
||||||
pub workflow_definition_id: String,
|
pub workflow_definition_id: String,
|
||||||
pub version: u32,
|
pub version: u32,
|
||||||
pub description: Option<String>,
|
pub description: Option<String>,
|
||||||
@@ -36,6 +48,10 @@ impl WorkflowInstance {
|
|||||||
id: uuid::Uuid::new_v4().to_string(),
|
id: uuid::Uuid::new_v4().to_string(),
|
||||||
// Filled in by WorkflowHost::start_workflow before persisting.
|
// Filled in by WorkflowHost::start_workflow before persisting.
|
||||||
name: String::new(),
|
name: String::new(),
|
||||||
|
// None by default — caller (HostContextImpl) sets this when
|
||||||
|
// starting a sub-workflow so children share the parent tree's
|
||||||
|
// namespace/volume.
|
||||||
|
root_workflow_id: None,
|
||||||
workflow_definition_id: workflow_definition_id.into(),
|
workflow_definition_id: workflow_definition_id.into(),
|
||||||
version,
|
version,
|
||||||
description: None,
|
description: None,
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ mod test_helpers {
|
|||||||
workflow: &'a WorkflowInstance,
|
workflow: &'a WorkflowInstance,
|
||||||
) -> StepExecutionContext<'a> {
|
) -> StepExecutionContext<'a> {
|
||||||
StepExecutionContext {
|
StepExecutionContext {
|
||||||
|
definition: None,
|
||||||
item: None,
|
item: None,
|
||||||
execution_pointer: pointer,
|
execution_pointer: pointer,
|
||||||
persistence_data: pointer.persistence_data.as_ref(),
|
persistence_data: pointer.persistence_data.as_ref(),
|
||||||
|
|||||||
@@ -123,8 +123,18 @@ impl StepBody for SubWorkflowStep {
|
|||||||
} else {
|
} else {
|
||||||
serde_json::json!({})
|
serde_json::json!({})
|
||||||
};
|
};
|
||||||
|
// Inherit the parent's root — or, if the parent is itself a root
|
||||||
|
// (has no root set), use the parent's own id as the root for the
|
||||||
|
// child. This makes every descendant of a top-level ci run share
|
||||||
|
// the same root_workflow_id and therefore the same namespace and
|
||||||
|
// shared volume on backends that care.
|
||||||
|
let parent_root = context
|
||||||
|
.workflow
|
||||||
|
.root_workflow_id
|
||||||
|
.clone()
|
||||||
|
.or_else(|| Some(context.workflow.id.clone()));
|
||||||
let child_instance_id = host
|
let child_instance_id = host
|
||||||
.start_workflow(&self.workflow_id, self.version, child_data)
|
.start_workflow(&self.workflow_id, self.version, child_data, parent_root)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok(ExecutionResult::wait_for_event(
|
Ok(ExecutionResult::wait_for_event(
|
||||||
@@ -171,6 +181,7 @@ mod tests {
|
|||||||
definition_id: &str,
|
definition_id: &str,
|
||||||
version: u32,
|
version: u32,
|
||||||
data: serde_json::Value,
|
data: serde_json::Value,
|
||||||
|
_parent_root_workflow_id: Option<String>,
|
||||||
) -> std::pin::Pin<Box<dyn std::future::Future<Output = crate::Result<String>> + Send + '_>>
|
) -> std::pin::Pin<Box<dyn std::future::Future<Output = crate::Result<String>> + Send + '_>>
|
||||||
{
|
{
|
||||||
let def_id = definition_id.to_string();
|
let def_id = definition_id.to_string();
|
||||||
@@ -191,6 +202,7 @@ mod tests {
|
|||||||
_definition_id: &str,
|
_definition_id: &str,
|
||||||
_version: u32,
|
_version: u32,
|
||||||
_data: serde_json::Value,
|
_data: serde_json::Value,
|
||||||
|
_parent_root_workflow_id: Option<String>,
|
||||||
) -> std::pin::Pin<Box<dyn std::future::Future<Output = crate::Result<String>> + Send + '_>>
|
) -> std::pin::Pin<Box<dyn std::future::Future<Output = crate::Result<String>> + Send + '_>>
|
||||||
{
|
{
|
||||||
Box::pin(async {
|
Box::pin(async {
|
||||||
@@ -208,6 +220,7 @@ mod tests {
|
|||||||
host: &'a dyn HostContext,
|
host: &'a dyn HostContext,
|
||||||
) -> StepExecutionContext<'a> {
|
) -> StepExecutionContext<'a> {
|
||||||
StepExecutionContext {
|
StepExecutionContext {
|
||||||
|
definition: None,
|
||||||
item: None,
|
item: None,
|
||||||
execution_pointer: pointer,
|
execution_pointer: pointer,
|
||||||
persistence_data: pointer.persistence_data.as_ref(),
|
persistence_data: pointer.persistence_data.as_ref(),
|
||||||
|
|||||||
@@ -59,6 +59,11 @@ impl WorkflowRepository for InMemoryPersistenceProvider {
|
|||||||
};
|
};
|
||||||
let mut stored = instance.clone();
|
let mut stored = instance.clone();
|
||||||
stored.id = id.clone();
|
stored.id = id.clone();
|
||||||
|
// Fall back to UUID when the caller didn't assign a human name, so
|
||||||
|
// name-based lookups work (the UUID is always unique).
|
||||||
|
if stored.name.is_empty() {
|
||||||
|
stored.name = id.clone();
|
||||||
|
}
|
||||||
self.workflows.write().await.insert(id.clone(), stored);
|
self.workflows.write().await.insert(id.clone(), stored);
|
||||||
Ok(id)
|
Ok(id)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ mod tests {
|
|||||||
let pointer = ExecutionPointer::new(0);
|
let pointer = ExecutionPointer::new(0);
|
||||||
let step = WorkflowStep::new(0, "test_step");
|
let step = WorkflowStep::new(0, "test_step");
|
||||||
let ctx = StepExecutionContext {
|
let ctx = StepExecutionContext {
|
||||||
|
definition: None,
|
||||||
item: None,
|
item: None,
|
||||||
execution_pointer: &pointer,
|
execution_pointer: &pointer,
|
||||||
persistence_data: None,
|
persistence_data: None,
|
||||||
@@ -82,6 +83,7 @@ mod tests {
|
|||||||
let pointer = ExecutionPointer::new(0);
|
let pointer = ExecutionPointer::new(0);
|
||||||
let step = WorkflowStep::new(0, "test_step");
|
let step = WorkflowStep::new(0, "test_step");
|
||||||
let ctx = StepExecutionContext {
|
let ctx = StepExecutionContext {
|
||||||
|
definition: None,
|
||||||
item: None,
|
item: None,
|
||||||
execution_pointer: &pointer,
|
execution_pointer: &pointer,
|
||||||
persistence_data: None,
|
persistence_data: None,
|
||||||
|
|||||||
@@ -2,7 +2,9 @@ use async_trait::async_trait;
|
|||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use serde::de::DeserializeOwned;
|
use serde::de::DeserializeOwned;
|
||||||
|
|
||||||
use crate::models::{ExecutionPointer, ExecutionResult, WorkflowInstance, WorkflowStep};
|
use crate::models::{
|
||||||
|
ExecutionPointer, ExecutionResult, WorkflowDefinition, WorkflowInstance, WorkflowStep,
|
||||||
|
};
|
||||||
|
|
||||||
/// Marker trait for all data types that flow between workflow steps.
|
/// Marker trait for all data types that flow between workflow steps.
|
||||||
/// Anything that is serializable and deserializable qualifies.
|
/// Anything that is serializable and deserializable qualifies.
|
||||||
@@ -13,12 +15,19 @@ impl<T> WorkflowData for T where T: Serialize + DeserializeOwned + Send + Sync +
|
|||||||
|
|
||||||
/// Context for steps that need to interact with the workflow host.
|
/// Context for steps that need to interact with the workflow host.
|
||||||
/// Implemented by WorkflowHost to allow steps like SubWorkflow to start child workflows.
|
/// Implemented by WorkflowHost to allow steps like SubWorkflow to start child workflows.
|
||||||
|
///
|
||||||
|
/// The `parent_root_workflow_id` argument carries the UUID of the top-level
|
||||||
|
/// ancestor workflow so backends (notably Kubernetes) can place every
|
||||||
|
/// descendant of a given root run in the same isolation domain — namespace,
|
||||||
|
/// shared volume, RBAC — so sub-workflows can share state like a cloned
|
||||||
|
/// repo checkout. Pass `None` when starting a brand-new root workflow.
|
||||||
pub trait HostContext: Send + Sync {
|
pub trait HostContext: Send + Sync {
|
||||||
fn start_workflow(
|
fn start_workflow(
|
||||||
&self,
|
&self,
|
||||||
definition_id: &str,
|
definition_id: &str,
|
||||||
version: u32,
|
version: u32,
|
||||||
data: serde_json::Value,
|
data: serde_json::Value,
|
||||||
|
parent_root_workflow_id: Option<String>,
|
||||||
) -> std::pin::Pin<Box<dyn std::future::Future<Output = crate::Result<String>> + Send + '_>>;
|
) -> std::pin::Pin<Box<dyn std::future::Future<Output = crate::Result<String>> + Send + '_>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,6 +43,12 @@ pub struct StepExecutionContext<'a> {
|
|||||||
pub step: &'a WorkflowStep,
|
pub step: &'a WorkflowStep,
|
||||||
/// The running workflow instance.
|
/// The running workflow instance.
|
||||||
pub workflow: &'a WorkflowInstance,
|
pub workflow: &'a WorkflowInstance,
|
||||||
|
/// The compiled workflow definition the instance was created from.
|
||||||
|
/// `None` on code paths that don't have it available (some test fixtures);
|
||||||
|
/// production execution always populates this so executor-specific
|
||||||
|
/// features (e.g. Kubernetes shared volumes) can inspect the
|
||||||
|
/// definition-level configuration.
|
||||||
|
pub definition: Option<&'a WorkflowDefinition>,
|
||||||
/// Cancellation token.
|
/// Cancellation token.
|
||||||
pub cancellation_token: tokio_util::sync::CancellationToken,
|
pub cancellation_token: tokio_util::sync::CancellationToken,
|
||||||
/// Host context for starting child workflows. None if not available.
|
/// Host context for starting child workflows. None if not available.
|
||||||
@@ -51,6 +66,7 @@ impl<'a> std::fmt::Debug for StepExecutionContext<'a> {
|
|||||||
.field("persistence_data", &self.persistence_data)
|
.field("persistence_data", &self.persistence_data)
|
||||||
.field("step", &self.step)
|
.field("step", &self.step)
|
||||||
.field("workflow", &self.workflow)
|
.field("workflow", &self.workflow)
|
||||||
|
.field("definition", &self.definition.is_some())
|
||||||
.field("host_context", &self.host_context.is_some())
|
.field("host_context", &self.host_context.is_some())
|
||||||
.field("log_sink", &self.log_sink.is_some())
|
.field("log_sink", &self.log_sink.is_some())
|
||||||
.finish()
|
.finish()
|
||||||
|
|||||||
@@ -189,6 +189,7 @@ mod tests {
|
|||||||
let instance = WorkflowInstance {
|
let instance = WorkflowInstance {
|
||||||
id: "wf-1".into(),
|
id: "wf-1".into(),
|
||||||
name: "test-def-1".into(),
|
name: "test-def-1".into(),
|
||||||
|
root_workflow_id: None,
|
||||||
workflow_definition_id: "test-def".into(),
|
workflow_definition_id: "test-def".into(),
|
||||||
version: 1,
|
version: 1,
|
||||||
description: None,
|
description: None,
|
||||||
@@ -212,6 +213,7 @@ mod tests {
|
|||||||
step.step_config = Some(serde_json::json!({"key": "val"}));
|
step.step_config = Some(serde_json::json!({"key": "val"}));
|
||||||
|
|
||||||
let ctx = StepExecutionContext {
|
let ctx = StepExecutionContext {
|
||||||
|
definition: None,
|
||||||
item: None,
|
item: None,
|
||||||
execution_pointer: &pointer,
|
execution_pointer: &pointer,
|
||||||
persistence_data: None,
|
persistence_data: None,
|
||||||
@@ -236,6 +238,7 @@ mod tests {
|
|||||||
let item = serde_json::json!({"id": 42});
|
let item = serde_json::json!({"id": 42});
|
||||||
|
|
||||||
let ctx = StepExecutionContext {
|
let ctx = StepExecutionContext {
|
||||||
|
definition: None,
|
||||||
item: Some(&item),
|
item: Some(&item),
|
||||||
execution_pointer: &pointer,
|
execution_pointer: &pointer,
|
||||||
persistence_data: Some(&serde_json::json!({"saved": true})),
|
persistence_data: Some(&serde_json::json!({"saved": true})),
|
||||||
@@ -360,6 +363,7 @@ mod tests {
|
|||||||
|
|
||||||
let (instance, step, pointer) = make_test_context();
|
let (instance, step, pointer) = make_test_context();
|
||||||
let ctx = StepExecutionContext {
|
let ctx = StepExecutionContext {
|
||||||
|
definition: None,
|
||||||
item: None,
|
item: None,
|
||||||
execution_pointer: &pointer,
|
execution_pointer: &pointer,
|
||||||
persistence_data: None,
|
persistence_data: None,
|
||||||
@@ -397,6 +401,7 @@ mod tests {
|
|||||||
|
|
||||||
let (instance, step, pointer) = make_test_context();
|
let (instance, step, pointer) = make_test_context();
|
||||||
let ctx = StepExecutionContext {
|
let ctx = StepExecutionContext {
|
||||||
|
definition: None,
|
||||||
item: None,
|
item: None,
|
||||||
execution_pointer: &pointer,
|
execution_pointer: &pointer,
|
||||||
persistence_data: None,
|
persistence_data: None,
|
||||||
@@ -428,6 +433,7 @@ mod tests {
|
|||||||
|
|
||||||
let (instance, step, pointer) = make_test_context();
|
let (instance, step, pointer) = make_test_context();
|
||||||
let ctx = StepExecutionContext {
|
let ctx = StepExecutionContext {
|
||||||
|
definition: None,
|
||||||
item: None,
|
item: None,
|
||||||
execution_pointer: &pointer,
|
execution_pointer: &pointer,
|
||||||
persistence_data: None,
|
persistence_data: None,
|
||||||
|
|||||||
@@ -47,6 +47,13 @@ pub fn compile(spec: &WorkflowSpec) -> Result<CompiledWorkflow, YamlWorkflowErro
|
|||||||
let mut definition = WorkflowDefinition::new(&spec.id, spec.version);
|
let mut definition = WorkflowDefinition::new(&spec.id, spec.version);
|
||||||
definition.name = spec.name.clone();
|
definition.name = spec.name.clone();
|
||||||
definition.description = spec.description.clone();
|
definition.description = spec.description.clone();
|
||||||
|
definition.shared_volume =
|
||||||
|
spec.shared_volume
|
||||||
|
.as_ref()
|
||||||
|
.map(|v| wfe_core::models::SharedVolume {
|
||||||
|
mount_path: v.mount_path.clone(),
|
||||||
|
size: v.size.clone(),
|
||||||
|
});
|
||||||
|
|
||||||
if let Some(ref eb) = spec.error_behavior {
|
if let Some(ref eb) = spec.error_behavior {
|
||||||
definition.default_error_behavior = map_error_behavior(eb)?;
|
definition.default_error_behavior = map_error_behavior(eb)?;
|
||||||
@@ -883,6 +890,7 @@ fn build_kubernetes_config(
|
|||||||
image,
|
image,
|
||||||
command: config.command.clone(),
|
command: config.command.clone(),
|
||||||
run: config.run.clone(),
|
run: config.run.clone(),
|
||||||
|
shell: config.shell.clone(),
|
||||||
env: config.env.clone(),
|
env: config.env.clone(),
|
||||||
working_dir: config.working_dir.clone(),
|
working_dir: config.working_dir.clone(),
|
||||||
memory: config.memory.clone(),
|
memory: config.memory.clone(),
|
||||||
|
|||||||
@@ -108,12 +108,37 @@ pub struct WorkflowSpec {
|
|||||||
/// Infrastructure services required by this workflow (databases, caches, etc.).
|
/// Infrastructure services required by this workflow (databases, caches, etc.).
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub services: HashMap<String, YamlService>,
|
pub services: HashMap<String, YamlService>,
|
||||||
|
/// Optional persistent volume shared across every step in this workflow
|
||||||
|
/// run, including sub-workflows. Declared once on the top-level
|
||||||
|
/// orchestrator (e.g. `ci`); ignored on non-root workflows. The Kubernetes
|
||||||
|
/// executor provisions a single PVC per top-level run and mounts it on
|
||||||
|
/// every step container at `mount_path` so steps like `git clone` in one
|
||||||
|
/// sub-workflow are visible to `cargo fmt --check` in another.
|
||||||
|
#[serde(default)]
|
||||||
|
pub shared_volume: Option<YamlSharedVolume>,
|
||||||
/// Allow unknown top-level keys (e.g. `_templates`) for YAML anchors.
|
/// Allow unknown top-level keys (e.g. `_templates`) for YAML anchors.
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
#[schemars(skip)]
|
#[schemars(skip)]
|
||||||
pub _extra: HashMap<String, serde_yaml::Value>,
|
pub _extra: HashMap<String, serde_yaml::Value>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Shared volume declaration, YAML form.
|
||||||
|
#[derive(Debug, Deserialize, Serialize, JsonSchema)]
|
||||||
|
pub struct YamlSharedVolume {
|
||||||
|
/// Absolute path to mount the volume at inside every step container.
|
||||||
|
/// Defaults to `/workspace` when unset.
|
||||||
|
#[serde(default = "default_shared_volume_mount")]
|
||||||
|
pub mount_path: String,
|
||||||
|
/// Optional size (e.g. `"20Gi"`). When unset the backend falls back
|
||||||
|
/// to its configured default.
|
||||||
|
#[serde(default)]
|
||||||
|
pub size: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn default_shared_volume_mount() -> String {
|
||||||
|
"/workspace".to_string()
|
||||||
|
}
|
||||||
|
|
||||||
/// A service definition in YAML format.
|
/// A service definition in YAML format.
|
||||||
#[derive(Debug, Deserialize, Serialize, JsonSchema)]
|
#[derive(Debug, Deserialize, Serialize, JsonSchema)]
|
||||||
pub struct YamlService {
|
pub struct YamlService {
|
||||||
|
|||||||
@@ -1092,6 +1092,7 @@ workflows:
|
|||||||
_def: &str,
|
_def: &str,
|
||||||
_ver: u32,
|
_ver: u32,
|
||||||
_data: serde_json::Value,
|
_data: serde_json::Value,
|
||||||
|
_parent_root_workflow_id: Option<String>,
|
||||||
) -> Pin<Box<dyn Future<Output = wfe_core::Result<String>> + Send + '_>> {
|
) -> Pin<Box<dyn Future<Output = wfe_core::Result<String>> + Send + '_>> {
|
||||||
*self.called.lock().unwrap() = true;
|
*self.called.lock().unwrap() = true;
|
||||||
Box::pin(async { Ok("child-instance-id".to_string()) })
|
Box::pin(async { Ok("child-instance-id".to_string()) })
|
||||||
@@ -1105,6 +1106,7 @@ workflows:
|
|||||||
let wf_step = WfStep::new(0, &factory_key);
|
let wf_step = WfStep::new(0, &factory_key);
|
||||||
let workflow = WorkflowInstance::new("parent", 1, serde_json::json!({}));
|
let workflow = WorkflowInstance::new("parent", 1, serde_json::json!({}));
|
||||||
let ctx = StepExecutionContext {
|
let ctx = StepExecutionContext {
|
||||||
|
definition: None,
|
||||||
item: None,
|
item: None,
|
||||||
execution_pointer: &pointer,
|
execution_pointer: &pointer,
|
||||||
persistence_data: None,
|
persistence_data: None,
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ fn make_context<'a>(
|
|||||||
pointer: &'a ExecutionPointer,
|
pointer: &'a ExecutionPointer,
|
||||||
) -> StepExecutionContext<'a> {
|
) -> StepExecutionContext<'a> {
|
||||||
StepExecutionContext {
|
StepExecutionContext {
|
||||||
|
definition: None,
|
||||||
item: None,
|
item: None,
|
||||||
execution_pointer: pointer,
|
execution_pointer: pointer,
|
||||||
persistence_data: None,
|
persistence_data: None,
|
||||||
|
|||||||
Reference in New Issue
Block a user