orchestrator_config/config/
mod.rs1mod agent;
4mod defaults;
5mod dynamic_items;
6mod env_store;
7mod execution;
8mod execution_profile;
9mod invariant;
10mod item_isolation;
11mod item_select;
12mod observability;
13mod pipeline;
14mod prehook;
15mod runner;
16mod safety;
17mod spawn;
18mod step;
19mod step_conventions;
20mod step_template;
21mod store_backend_provider;
22mod store_io;
23mod trigger;
24mod workflow;
25mod workflow_store;
26
27pub use agent::*;
28pub use defaults::*;
29pub use dynamic_items::*;
30pub use env_store::*;
31pub use execution::*;
32pub use execution_profile::*;
33pub use invariant::*;
34pub use item_isolation::*;
35pub use item_select::*;
36pub use observability::*;
37pub use pipeline::*;
38pub use prehook::*;
39pub use runner::*;
40pub use safety::*;
41pub use spawn::*;
42pub use step::*;
43pub use step_conventions::*;
44pub use step_template::*;
45pub use store_backend_provider::*;
46pub use store_io::*;
47pub use trigger::*;
48pub use workflow::*;
49pub use workflow_store::*;
50
51use crate::crd_types::{CustomResource, CustomResourceDefinition};
52use crate::resource_store::ResourceStore;
53use serde::{Deserialize, Serialize};
54use std::collections::HashMap;
55
56pub const DEFAULT_PROJECT_ID: &str = "default";
58
59#[derive(Debug, Clone, Default, Serialize, Deserialize)]
61pub struct OrchestratorConfig {
62 #[serde(default)]
64 pub projects: HashMap<String, ProjectConfig>,
65 #[serde(default)]
67 pub custom_resource_definitions: HashMap<String, CustomResourceDefinition>,
68 #[serde(default)]
70 pub custom_resources: HashMap<String, CustomResource>,
71 #[serde(default)]
73 pub resource_store: ResourceStore,
74}
75
76impl OrchestratorConfig {
77 pub fn effective_project_id<'a>(&'a self, project_id: Option<&'a str>) -> &'a str {
79 project_id
80 .filter(|value| !value.trim().is_empty())
81 .unwrap_or(DEFAULT_PROJECT_ID)
82 }
83
84 pub fn project(&self, project_id: Option<&str>) -> Option<&ProjectConfig> {
86 self.projects.get(self.effective_project_id(project_id))
87 }
88
89 pub fn project_mut(&mut self, project_id: Option<&str>) -> Option<&mut ProjectConfig> {
91 let project_id = self.effective_project_id(project_id).to_string();
92 self.projects.get_mut(&project_id)
93 }
94
95 pub fn default_project(&self) -> Option<&ProjectConfig> {
97 self.project(Some(DEFAULT_PROJECT_ID))
98 }
99
100 pub fn ensure_project(&mut self, project_id: Option<&str>) -> &mut ProjectConfig {
102 let project_id = self.effective_project_id(project_id).to_string();
103 self.projects.entry(project_id).or_default()
104 }
105}
106
107#[derive(Debug, Clone, Serialize, Deserialize, Default)]
109pub struct ResourceMetadataStore {
110 #[serde(default)]
112 pub workspaces: HashMap<String, ResourceStoredMetadata>,
113 #[serde(default)]
115 pub agents: HashMap<String, ResourceStoredMetadata>,
116 #[serde(default)]
118 pub workflows: HashMap<String, ResourceStoredMetadata>,
119}
120
121#[derive(Debug, Clone, Serialize, Deserialize, Default)]
123pub struct ResourceStoredMetadata {
124 #[serde(default, skip_serializing_if = "Option::is_none")]
126 pub labels: Option<HashMap<String, String>>,
127 #[serde(default, skip_serializing_if = "Option::is_none")]
129 pub annotations: Option<HashMap<String, String>>,
130}
131
132#[cfg(test)]
133mod tests {
134 use super::*;
135
136 #[test]
137 fn test_orchestrator_config_default() {
138 let cfg = OrchestratorConfig::default();
139 assert!(cfg.projects.is_empty());
140 }
141
142 #[test]
143 fn test_orchestrator_config_serde_round_trip() {
144 let cfg = OrchestratorConfig::default();
145 let json = serde_json::to_string(&cfg).expect("config should serialize");
146 let cfg2: OrchestratorConfig =
147 serde_json::from_str(&json).expect("config should deserialize");
148 assert_eq!(cfg2.projects.len(), cfg.projects.len());
149 assert!(cfg2.projects.is_empty());
150 }
151
152 #[test]
153 fn test_default_project() {
154 assert_eq!(DEFAULT_PROJECT_ID, "default");
155 }
156}