Rename attach source around existing clusters

This commit is contained in:
andrussal 2026-03-08 14:05:28 +01:00
parent e04832f62c
commit 4d8349679e
11 changed files with 60 additions and 50 deletions

View File

@ -4,7 +4,7 @@ use thiserror::Error;
use tracing::{debug, info};
use super::{
Application, AttachSource, DeploymentPolicy, DynError, ExternalNodeSource,
Application, DeploymentPolicy, DynError, ExistingCluster, ExternalNodeSource,
HttpReadinessRequirement, NodeControlCapability, ObservabilityCapability, ScenarioSources,
builder_ops::CoreBuilderAccess,
expectation::Expectation,
@ -119,7 +119,7 @@ impl<E: Application, Caps> Scenario<E, Caps> {
}
#[must_use]
pub fn existing_cluster(&self) -> Option<&AttachSource> {
pub fn existing_cluster(&self) -> Option<&ExistingCluster> {
self.sources.existing_cluster()
}
@ -130,7 +130,7 @@ impl<E: Application, Caps> Scenario<E, Caps> {
#[must_use]
#[doc(hidden)]
pub fn attached_source(&self) -> Option<&AttachSource> {
pub fn attached_source(&self) -> Option<&ExistingCluster> {
self.existing_cluster()
}
@ -255,13 +255,13 @@ macro_rules! impl_common_builder_methods {
}
#[must_use]
pub fn with_existing_cluster(self, cluster: AttachSource) -> Self {
pub fn with_existing_cluster(self, cluster: ExistingCluster) -> Self {
self.map_core_builder(|builder| builder.with_existing_cluster(cluster))
}
#[must_use]
#[doc(hidden)]
pub fn with_attach_source(self, attach: AttachSource) -> Self {
pub fn with_attach_source(self, attach: ExistingCluster) -> Self {
self.with_existing_cluster(attach)
}
@ -574,14 +574,14 @@ impl<E: Application, Caps> Builder<E, Caps> {
}
#[must_use]
pub fn with_existing_cluster(mut self, cluster: AttachSource) -> Self {
pub fn with_existing_cluster(mut self, cluster: ExistingCluster) -> Self {
self.sources = self.sources.with_attach(cluster);
self
}
#[must_use]
#[doc(hidden)]
pub fn with_attach_source(self, attach: AttachSource) -> Self {
pub fn with_attach_source(self, attach: ExistingCluster) -> Self {
self.with_existing_cluster(attach)
}

View File

@ -51,7 +51,9 @@ pub use runtime::{
wait_for_http_ports_with_host_and_requirement, wait_for_http_ports_with_requirement,
wait_http_readiness, wait_until_stable,
};
pub use sources::{AttachSource, ExternalNodeSource, ScenarioSources};
#[doc(hidden)]
pub use sources::AttachSource;
pub use sources::{ExistingCluster, ExternalNodeSource, ScenarioSources};
pub use workload::Workload;
pub use crate::env::Application;

View File

@ -1,4 +1,4 @@
use crate::scenario::{AttachSource, ExternalNodeSource, ScenarioSources};
use crate::scenario::{ExistingCluster, ExternalNodeSource, ScenarioSources};
/// Explicit descriptor for managed node sourcing.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
@ -19,7 +19,7 @@ pub(crate) enum SourceOrchestrationMode {
external: Vec<ExternalNodeSource>,
},
Attached {
attach: AttachSource,
attach: ExistingCluster,
external: Vec<ExternalNodeSource>,
},
ExternalOnly {
@ -69,11 +69,12 @@ impl SourceOrchestrationPlan {
#[cfg(test)]
mod tests {
use super::{SourceOrchestrationMode, SourceOrchestrationPlan};
use crate::scenario::{AttachSource, ScenarioSources};
use crate::scenario::{ExistingCluster, ScenarioSources};
#[test]
fn attached_sources_are_planned() {
let sources = ScenarioSources::attached(AttachSource::compose(vec!["node-0".to_string()]));
let sources =
ScenarioSources::attached(ExistingCluster::compose(vec!["node-0".to_string()]));
let plan = SourceOrchestrationPlan::try_from_sources(&sources)
.expect("attached sources should build a source orchestration plan");

View File

@ -1,6 +1,6 @@
use async_trait::async_trait;
use crate::scenario::{Application, AttachSource, DynError};
use crate::scenario::{Application, DynError, ExistingCluster};
/// Attached node discovered from an existing external cluster source.
#[derive(Clone, Debug)]
@ -15,7 +15,7 @@ pub struct AttachedNode<E: Application> {
#[derive(Debug, thiserror::Error)]
pub enum AttachProviderError {
#[error("attach source is not supported by this provider: {attach_source:?}")]
UnsupportedSource { attach_source: AttachSource },
UnsupportedSource { attach_source: ExistingCluster },
#[error("attach discovery failed: {source}")]
Discovery {
#[source]
@ -32,7 +32,7 @@ pub trait AttachProvider<E: Application>: Send + Sync {
/// Discovers node clients for the requested attach source.
async fn discover(
&self,
source: &AttachSource,
source: &ExistingCluster,
) -> Result<Vec<AttachedNode<E>>, AttachProviderError>;
}
@ -44,7 +44,7 @@ pub struct NoopAttachProvider;
impl<E: Application> AttachProvider<E> for NoopAttachProvider {
async fn discover(
&self,
source: &AttachSource,
source: &ExistingCluster,
) -> Result<Vec<AttachedNode<E>>, AttachProviderError> {
Err(AttachProviderError::UnsupportedSource {
attach_source: source.clone(),

View File

@ -1,3 +1,5 @@
mod model;
pub use model::{AttachSource, ExternalNodeSource, ScenarioSources};
#[doc(hidden)]
pub use model::AttachSource;
pub use model::{ExistingCluster, ExternalNodeSource, ScenarioSources};

View File

@ -1,6 +1,6 @@
/// Typed attach source for existing clusters.
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum AttachSource {
pub enum ExistingCluster {
K8s {
namespace: Option<String>,
label_selector: String,
@ -11,7 +11,7 @@ pub enum AttachSource {
},
}
impl AttachSource {
impl ExistingCluster {
#[must_use]
pub fn k8s(label_selector: String) -> Self {
Self::K8s {
@ -77,6 +77,9 @@ impl AttachSource {
}
}
#[doc(hidden)]
pub type AttachSource = ExistingCluster;
/// Static external node endpoint that should be included in the runtime
/// inventory.
#[derive(Clone, Debug, Eq, PartialEq)]
@ -110,7 +113,7 @@ pub enum ScenarioSources {
external: Vec<ExternalNodeSource>,
},
Attached {
attach: AttachSource,
attach: ExistingCluster,
external: Vec<ExternalNodeSource>,
},
ExternalOnly {
@ -135,7 +138,7 @@ impl ScenarioSources {
}
#[must_use]
pub fn attached(attach: AttachSource) -> Self {
pub fn attached(attach: ExistingCluster) -> Self {
Self::Attached {
attach,
external: Vec::new(),
@ -159,7 +162,7 @@ impl ScenarioSources {
}
#[must_use]
pub fn with_attach(self, attach: AttachSource) -> Self {
pub fn with_attach(self, attach: ExistingCluster) -> Self {
let external = self.external_nodes().to_vec();
Self::Attached { attach, external }

View File

@ -2,8 +2,8 @@ use std::marker::PhantomData;
use async_trait::async_trait;
use testing_framework_core::scenario::{
AttachProvider, AttachProviderError, AttachSource, AttachedNode, ClusterWaitHandle, DynError,
ExternalNodeSource, HttpReadinessRequirement, wait_http_readiness,
AttachProvider, AttachProviderError, AttachedNode, ClusterWaitHandle, DynError,
ExistingCluster, ExternalNodeSource, HttpReadinessRequirement, wait_http_readiness,
};
use url::Url;
@ -22,7 +22,7 @@ pub(super) struct ComposeAttachProvider<E: ComposeDeployEnv> {
pub(super) struct ComposeAttachedClusterWait<E: ComposeDeployEnv> {
host: String,
source: AttachSource,
source: ExistingCluster,
_env: PhantomData<E>,
}
@ -42,7 +42,7 @@ impl<E: ComposeDeployEnv> ComposeAttachProvider<E> {
}
impl<E: ComposeDeployEnv> ComposeAttachedClusterWait<E> {
pub(super) fn new(host: String, source: AttachSource) -> Self {
pub(super) fn new(host: String, source: ExistingCluster) -> Self {
Self {
host,
source,
@ -60,7 +60,7 @@ struct ComposeAttachRequest<'a> {
impl<E: ComposeDeployEnv> AttachProvider<E> for ComposeAttachProvider<E> {
async fn discover(
&self,
source: &AttachSource,
source: &ExistingCluster,
) -> Result<Vec<AttachedNode<E>>, AttachProviderError> {
let request = compose_attach_request(source)?;
let services = resolve_services(request.project, request.services)
@ -85,7 +85,7 @@ fn to_discovery_error(source: DynError) -> AttachProviderError {
}
fn compose_attach_request(
source: &AttachSource,
source: &ExistingCluster,
) -> Result<ComposeAttachRequest<'_>, AttachProviderError> {
let services =
source
@ -173,7 +173,7 @@ impl<E: ComposeDeployEnv> ClusterWaitHandle<E> for ComposeAttachedClusterWait<E>
}
}
fn compose_wait_request(source: &AttachSource) -> Result<ComposeAttachRequest<'_>, DynError> {
fn compose_wait_request(source: &ExistingCluster) -> Result<ComposeAttachRequest<'_>, DynError> {
let project = source
.compose_project()
.ok_or_else(|| DynError::from("compose cluster wait requires a compose attach source"))?;

View File

@ -9,7 +9,7 @@ use std::marker::PhantomData;
use async_trait::async_trait;
use testing_framework_core::scenario::{
AttachSource, CleanupGuard, Deployer, DynError, FeedHandle, ObservabilityCapabilityProvider,
CleanupGuard, Deployer, DynError, ExistingCluster, FeedHandle, ObservabilityCapabilityProvider,
RequiresNodeControl, Runner, Scenario,
};
@ -45,12 +45,12 @@ impl ComposeDeploymentMetadata {
/// Builds an existing-cluster descriptor for the same compose project
/// using deployer discovery to resolve services.
pub fn existing_cluster(&self) -> Result<AttachSource, DynError> {
pub fn existing_cluster(&self) -> Result<ExistingCluster, DynError> {
let project_name = self
.project_name()
.ok_or(ComposeMetadataError::MissingProjectName)?;
Ok(AttachSource::compose_in_project(
Ok(ExistingCluster::compose_in_project(
Vec::new(),
project_name.to_owned(),
))
@ -60,19 +60,19 @@ impl ComposeDeploymentMetadata {
pub fn existing_cluster_for_services(
&self,
services: Vec<String>,
) -> Result<AttachSource, DynError> {
) -> Result<ExistingCluster, DynError> {
let project_name = self
.project_name()
.ok_or(ComposeMetadataError::MissingProjectName)?;
Ok(AttachSource::compose_in_project(
Ok(ExistingCluster::compose_in_project(
services,
project_name.to_owned(),
))
}
#[doc(hidden)]
pub fn attach_source(&self) -> Result<AttachSource, DynError> {
pub fn attach_source(&self) -> Result<ExistingCluster, DynError> {
self.existing_cluster()
}
@ -80,7 +80,7 @@ impl ComposeDeploymentMetadata {
pub fn attach_source_for_services(
&self,
services: Vec<String>,
) -> Result<AttachSource, DynError> {
) -> Result<ExistingCluster, DynError> {
self.existing_cluster_for_services(services)
}
}

View File

@ -3,8 +3,8 @@ use std::{env, sync::Arc, time::Duration};
use reqwest::Url;
use testing_framework_core::{
scenario::{
ApplicationExternalProvider, AttachSource, CleanupGuard, ClusterWaitHandle,
DeploymentPolicy, FeedHandle, FeedRuntime, HttpReadinessRequirement, Metrics, NodeClients,
ApplicationExternalProvider, CleanupGuard, ClusterWaitHandle, DeploymentPolicy,
ExistingCluster, FeedHandle, FeedRuntime, HttpReadinessRequirement, Metrics, NodeClients,
NodeControlHandle, ObservabilityCapabilityProvider, ObservabilityInputs,
RequiresNodeControl, RunContext, Runner, Scenario, SourceOrchestrationPlan,
SourceProviders, StaticManagedProvider, build_source_orchestration_plan,
@ -315,7 +315,7 @@ impl<E: ComposeDeployEnv> DeploymentOrchestrator<E> {
fn managed_cluster_wait(&self, project_name: String) -> Arc<dyn ClusterWaitHandle<E>> {
Arc::new(ComposeAttachedClusterWait::<E>::new(
compose_runner_host(),
AttachSource::compose_in_project(Vec::new(), project_name),
ExistingCluster::compose_in_project(Vec::new(), project_name),
))
}

View File

@ -7,8 +7,8 @@ use kube::{
api::{ListParams, ObjectList},
};
use testing_framework_core::scenario::{
AttachProvider, AttachProviderError, AttachSource, AttachedNode, ClusterWaitHandle, DynError,
ExternalNodeSource, HttpReadinessRequirement, wait_http_readiness,
AttachProvider, AttachProviderError, AttachedNode, ClusterWaitHandle, DynError,
ExistingCluster, ExternalNodeSource, HttpReadinessRequirement, wait_http_readiness,
};
use url::Url;
@ -37,7 +37,7 @@ pub(super) struct K8sAttachProvider<E: K8sDeployEnv> {
pub(super) struct K8sAttachedClusterWait<E: K8sDeployEnv> {
client: Client,
source: AttachSource,
source: ExistingCluster,
_env: PhantomData<E>,
}
@ -56,7 +56,7 @@ impl<E: K8sDeployEnv> K8sAttachProvider<E> {
}
impl<E: K8sDeployEnv> K8sAttachedClusterWait<E> {
pub(super) fn new(client: Client, source: AttachSource) -> Self {
pub(super) fn new(client: Client, source: ExistingCluster) -> Self {
Self {
client,
source,
@ -69,7 +69,7 @@ impl<E: K8sDeployEnv> K8sAttachedClusterWait<E> {
impl<E: K8sDeployEnv> AttachProvider<E> for K8sAttachProvider<E> {
async fn discover(
&self,
source: &AttachSource,
source: &ExistingCluster,
) -> Result<Vec<AttachedNode<E>>, AttachProviderError> {
let request = k8s_attach_request(source)?;
let services = discover_services(&self.client, request.namespace, request.label_selector)
@ -90,7 +90,9 @@ fn to_discovery_error(source: DynError) -> AttachProviderError {
AttachProviderError::Discovery { source }
}
fn k8s_attach_request(source: &AttachSource) -> Result<K8sAttachRequest<'_>, AttachProviderError> {
fn k8s_attach_request(
source: &ExistingCluster,
) -> Result<K8sAttachRequest<'_>, AttachProviderError> {
let Some(label_selector) = source.k8s_label_selector() else {
return Err(AttachProviderError::UnsupportedSource {
attach_source: source.clone(),
@ -242,7 +244,7 @@ impl<E: K8sDeployEnv> ClusterWaitHandle<E> for K8sAttachedClusterWait<E> {
}
}
fn k8s_wait_request(source: &AttachSource) -> Result<K8sAttachRequest<'_>, DynError> {
fn k8s_wait_request(source: &ExistingCluster) -> Result<K8sAttachRequest<'_>, DynError> {
let label_selector = source
.k8s_label_selector()
.ok_or_else(|| DynError::from("k8s cluster wait requires a k8s attach source"))?;

View File

@ -2,7 +2,7 @@ mod attach_provider;
mod orchestrator;
pub use orchestrator::{K8sDeployer, K8sRunnerError};
use testing_framework_core::scenario::{AttachSource, DynError};
use testing_framework_core::scenario::{DynError, ExistingCluster};
/// Kubernetes deployment metadata returned by k8s-specific deployment APIs.
#[derive(Clone, Debug, Eq, PartialEq)]
@ -35,20 +35,20 @@ impl K8sDeploymentMetadata {
}
/// Builds an existing-cluster descriptor for the same k8s deployment scope.
pub fn existing_cluster(&self) -> Result<AttachSource, DynError> {
pub fn existing_cluster(&self) -> Result<ExistingCluster, DynError> {
let namespace = self.namespace().ok_or(K8sMetadataError::MissingNamespace)?;
let label_selector = self
.label_selector()
.ok_or(K8sMetadataError::MissingLabelSelector)?;
Ok(AttachSource::k8s_in_namespace(
Ok(ExistingCluster::k8s_in_namespace(
label_selector.to_owned(),
namespace.to_owned(),
))
}
#[doc(hidden)]
pub fn attach_source(&self) -> Result<AttachSource, DynError> {
pub fn attach_source(&self) -> Result<ExistingCluster, DynError> {
self.existing_cluster()
}
}