feat: add workspace runtime registry source boundary
This commit is contained in:
parent
40d4138068
commit
f6fd7b6323
|
|
@ -44,6 +44,69 @@ pub enum DiagnosticSeverity {
|
||||||
Error,
|
Error,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
|
pub enum RuntimeSourceKind {
|
||||||
|
/// Compatibility projection over the existing local Pod metadata store.
|
||||||
|
LocalCompatibility,
|
||||||
|
/// Reserved boundary for the future in-process worker-runtime Runtime adapter.
|
||||||
|
EmbeddedWorkerRuntime,
|
||||||
|
/// Reserved boundary for a future remote Workspace Runtime adapter.
|
||||||
|
RemoteHttp,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
|
pub enum RuntimeSourceStatus {
|
||||||
|
Active,
|
||||||
|
Reserved,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
|
pub enum RuntimeIdentityAuthority {
|
||||||
|
/// Public Runtime/Host/Worker ids are registry projections, never raw
|
||||||
|
/// compatibility-store names, socket addresses, session ids, or paths.
|
||||||
|
RuntimeRegistryProjection,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||||
|
pub struct RuntimeSourceSummary {
|
||||||
|
pub kind: RuntimeSourceKind,
|
||||||
|
pub status: RuntimeSourceStatus,
|
||||||
|
pub identity_authority: RuntimeIdentityAuthority,
|
||||||
|
pub note: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RuntimeSourceSummary {
|
||||||
|
pub fn local_compatibility() -> Self {
|
||||||
|
Self {
|
||||||
|
kind: RuntimeSourceKind::LocalCompatibility,
|
||||||
|
status: RuntimeSourceStatus::Active,
|
||||||
|
identity_authority: RuntimeIdentityAuthority::RuntimeRegistryProjection,
|
||||||
|
note: "read-only compatibility projection over local Worker metadata; no socket, session, or path authority is exposed".to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn embedded_worker_runtime_reserved() -> Self {
|
||||||
|
Self {
|
||||||
|
kind: RuntimeSourceKind::EmbeddedWorkerRuntime,
|
||||||
|
status: RuntimeSourceStatus::Reserved,
|
||||||
|
identity_authority: RuntimeIdentityAuthority::RuntimeRegistryProjection,
|
||||||
|
note: "reserved boundary for a future embedded worker-runtime adapter; not connected in this registry foundation".to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remote_http_reserved() -> Self {
|
||||||
|
Self {
|
||||||
|
kind: RuntimeSourceKind::RemoteHttp,
|
||||||
|
status: RuntimeSourceStatus::Reserved,
|
||||||
|
identity_authority: RuntimeIdentityAuthority::RuntimeRegistryProjection,
|
||||||
|
note: "reserved boundary for a future remote Runtime adapter; no HTTP client or REST server is implemented here".to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||||
pub struct RuntimeCapabilitySummary {
|
pub struct RuntimeCapabilitySummary {
|
||||||
pub can_list_hosts: bool,
|
pub can_list_hosts: bool,
|
||||||
|
|
@ -74,6 +137,7 @@ pub struct RuntimeSummary {
|
||||||
pub label: String,
|
pub label: String,
|
||||||
pub kind: String,
|
pub kind: String,
|
||||||
pub status: String,
|
pub status: String,
|
||||||
|
pub source: RuntimeSourceSummary,
|
||||||
pub host_ids: Vec<String>,
|
pub host_ids: Vec<String>,
|
||||||
pub capabilities: RuntimeCapabilitySummary,
|
pub capabilities: RuntimeCapabilitySummary,
|
||||||
pub diagnostics: Vec<RuntimeDiagnostic>,
|
pub diagnostics: Vec<RuntimeDiagnostic>,
|
||||||
|
|
@ -317,11 +381,11 @@ pub trait WorkspaceWorkerRuntime: Send + Sync {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct WorkerRuntimeRegistry {
|
pub struct RuntimeRegistry {
|
||||||
runtimes: Vec<Arc<dyn WorkspaceWorkerRuntime>>,
|
runtimes: Vec<Arc<dyn WorkspaceWorkerRuntime>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WorkerRuntimeRegistry {
|
impl RuntimeRegistry {
|
||||||
pub fn new(runtimes: Vec<Arc<dyn WorkspaceWorkerRuntime>>) -> Self {
|
pub fn new(runtimes: Vec<Arc<dyn WorkspaceWorkerRuntime>>) -> Self {
|
||||||
Self { runtimes }
|
Self { runtimes }
|
||||||
}
|
}
|
||||||
|
|
@ -582,6 +646,7 @@ impl WorkspaceWorkerRuntime for LocalWorkerRuntime {
|
||||||
label: "Local Worker runtime".to_string(),
|
label: "Local Worker runtime".to_string(),
|
||||||
kind: "local_pod".to_string(),
|
kind: "local_pod".to_string(),
|
||||||
status: "available".to_string(),
|
status: "available".to_string(),
|
||||||
|
source: RuntimeSourceSummary::local_compatibility(),
|
||||||
host_ids: host_list
|
host_ids: host_list
|
||||||
.items
|
.items
|
||||||
.iter()
|
.iter()
|
||||||
|
|
@ -1011,7 +1076,7 @@ mod tests {
|
||||||
fn registry_lists_runtimes_hosts_and_workers() {
|
fn registry_lists_runtimes_hosts_and_workers() {
|
||||||
let temp = TempDir::new().unwrap();
|
let temp = TempDir::new().unwrap();
|
||||||
write_metadata(temp.path(), "coder", &metadata(Some("/workspace/project")));
|
write_metadata(temp.path(), "coder", &metadata(Some("/workspace/project")));
|
||||||
let registry = WorkerRuntimeRegistry::for_local_pods(LocalWorkerRuntime::new(
|
let registry = RuntimeRegistry::for_local_pods(LocalWorkerRuntime::new(
|
||||||
"local:test",
|
"local:test",
|
||||||
"/workspace/project",
|
"/workspace/project",
|
||||||
Some(temp.path().to_path_buf()),
|
Some(temp.path().to_path_buf()),
|
||||||
|
|
@ -1019,6 +1084,14 @@ mod tests {
|
||||||
|
|
||||||
let runtimes = registry.list_runtimes(10);
|
let runtimes = registry.list_runtimes(10);
|
||||||
assert_eq!(runtimes.items[0].runtime_id, LOCAL_RUNTIME_ID);
|
assert_eq!(runtimes.items[0].runtime_id, LOCAL_RUNTIME_ID);
|
||||||
|
assert_eq!(
|
||||||
|
runtimes.items[0].source.kind,
|
||||||
|
RuntimeSourceKind::LocalCompatibility
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
runtimes.items[0].source.identity_authority,
|
||||||
|
RuntimeIdentityAuthority::RuntimeRegistryProjection
|
||||||
|
);
|
||||||
assert_eq!(runtimes.items[0].host_ids, vec![host_id()]);
|
assert_eq!(runtimes.items[0].host_ids, vec![host_id()]);
|
||||||
|
|
||||||
let hosts = registry.list_hosts(10);
|
let hosts = registry.list_hosts(10);
|
||||||
|
|
@ -1043,7 +1116,7 @@ mod tests {
|
||||||
fn registry_resolves_backend_validated_host_ids() {
|
fn registry_resolves_backend_validated_host_ids() {
|
||||||
let temp = TempDir::new().unwrap();
|
let temp = TempDir::new().unwrap();
|
||||||
write_metadata(temp.path(), "coder", &metadata(Some("/workspace/project")));
|
write_metadata(temp.path(), "coder", &metadata(Some("/workspace/project")));
|
||||||
let registry = WorkerRuntimeRegistry::for_local_pods(LocalWorkerRuntime::new(
|
let registry = RuntimeRegistry::for_local_pods(LocalWorkerRuntime::new(
|
||||||
"local:test",
|
"local:test",
|
||||||
"/workspace/project",
|
"/workspace/project",
|
||||||
Some(temp.path().to_path_buf()),
|
Some(temp.path().to_path_buf()),
|
||||||
|
|
@ -1133,7 +1206,7 @@ mod tests {
|
||||||
"/workspace/project",
|
"/workspace/project",
|
||||||
Some(temp.path().to_path_buf()),
|
Some(temp.path().to_path_buf()),
|
||||||
);
|
);
|
||||||
let registry = WorkerRuntimeRegistry::for_local_pods(bridge.clone());
|
let registry = RuntimeRegistry::for_local_pods(bridge.clone());
|
||||||
|
|
||||||
let listed = registry.list_workers(100);
|
let listed = registry.list_workers(100);
|
||||||
assert_eq!(listed.items.len(), worker_names.len());
|
assert_eq!(listed.items.len(), worker_names.len());
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,8 @@ use serde::{Deserialize, Serialize};
|
||||||
use tokio::net::TcpListener;
|
use tokio::net::TcpListener;
|
||||||
|
|
||||||
use crate::hosts::{
|
use crate::hosts::{
|
||||||
DiagnosticSeverity, HostSummary, LocalWorkerRuntime, RuntimeDiagnostic, RuntimeSummary,
|
DiagnosticSeverity, HostSummary, LocalWorkerRuntime, RuntimeDiagnostic, RuntimeRegistry,
|
||||||
WorkerRuntimeRegistry, WorkerSummary,
|
RuntimeSummary, WorkerSummary,
|
||||||
};
|
};
|
||||||
use crate::identity::WorkspaceIdentity;
|
use crate::identity::WorkspaceIdentity;
|
||||||
use crate::records::{
|
use crate::records::{
|
||||||
|
|
@ -64,7 +64,7 @@ pub struct WorkspaceApi {
|
||||||
config: ServerConfig,
|
config: ServerConfig,
|
||||||
store: Arc<dyn ControlPlaneStore>,
|
store: Arc<dyn ControlPlaneStore>,
|
||||||
records: LocalProjectRecordReader,
|
records: LocalProjectRecordReader,
|
||||||
runtime: Arc<WorkerRuntimeRegistry>,
|
runtime: Arc<RuntimeRegistry>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WorkspaceApi {
|
impl WorkspaceApi {
|
||||||
|
|
@ -78,13 +78,11 @@ impl WorkspaceApi {
|
||||||
updated_at: config.workspace_created_at.clone(),
|
updated_at: config.workspace_created_at.clone(),
|
||||||
})
|
})
|
||||||
.await?;
|
.await?;
|
||||||
let runtime = Arc::new(WorkerRuntimeRegistry::for_local_pods(
|
let runtime = Arc::new(RuntimeRegistry::for_local_pods(LocalWorkerRuntime::new(
|
||||||
LocalWorkerRuntime::new(
|
config.workspace_id.clone(),
|
||||||
config.workspace_id.clone(),
|
config.workspace_root.clone(),
|
||||||
config.workspace_root.clone(),
|
config.local_runtime_data_dir.clone(),
|
||||||
config.local_runtime_data_dir.clone(),
|
)));
|
||||||
),
|
|
||||||
));
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
records: LocalProjectRecordReader::new(config.workspace_root.clone()),
|
records: LocalProjectRecordReader::new(config.workspace_root.clone()),
|
||||||
config,
|
config,
|
||||||
|
|
@ -746,6 +744,15 @@ mod tests {
|
||||||
let runtimes = get_json(app.clone(), "/api/runtimes").await;
|
let runtimes = get_json(app.clone(), "/api/runtimes").await;
|
||||||
assert_eq!(runtimes["source"], "worker_runtime_registry");
|
assert_eq!(runtimes["source"], "worker_runtime_registry");
|
||||||
assert_eq!(runtimes["items"][0]["runtime_id"], "local-worker-runtime");
|
assert_eq!(runtimes["items"][0]["runtime_id"], "local-worker-runtime");
|
||||||
|
assert_eq!(
|
||||||
|
runtimes["items"][0]["source"]["kind"],
|
||||||
|
"local_compatibility"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
runtimes["items"][0]["source"]["identity_authority"],
|
||||||
|
"runtime_registry_projection"
|
||||||
|
);
|
||||||
|
assert!(!runtimes.to_string().contains("/workspace/demo"));
|
||||||
assert_eq!(runtimes["items"][0]["host_ids"][0], host_id);
|
assert_eq!(runtimes["items"][0]["host_ids"][0], host_id);
|
||||||
|
|
||||||
let workers = get_json(app.clone(), "/api/workers").await;
|
let workers = get_json(app.clone(), "/api/workers").await;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user