greentic_bundle/setup/
mod.rs1pub mod backend;
2pub mod legacy_formspec;
3pub mod persist;
4pub mod qa_bridge;
5
6use std::collections::BTreeMap;
7
8use anyhow::Result;
9use greentic_deploy_spec::SecretRef;
10use serde::{Deserialize, Serialize};
11use serde_json::Value;
12
13pub const SETUP_STATE_DIR: &str = "state/setup";
14pub const SETUP_STATE_SCHEMA_VERSION: u32 = 3;
25
26#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
27pub struct FormSpec {
28 pub id: String,
29 pub title: String,
30 pub version: String,
31 #[serde(skip_serializing_if = "Option::is_none")]
32 pub description: Option<String>,
33 pub questions: Vec<QuestionSpec>,
34}
35
36#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
37pub struct QuestionSpec {
38 pub id: String,
39 pub kind: QuestionKind,
40 pub title: String,
41 #[serde(skip_serializing_if = "Option::is_none")]
42 pub description: Option<String>,
43 pub required: bool,
44 #[serde(default, skip_serializing_if = "Vec::is_empty")]
45 pub choices: Vec<String>,
46 #[serde(skip_serializing_if = "Option::is_none")]
47 pub default_value: Option<Value>,
48 pub secret: bool,
49}
50
51#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
52#[serde(rename_all = "snake_case")]
53pub enum QuestionKind {
54 String,
55 Number,
56 Boolean,
57 Enum,
58}
59
60#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
61#[serde(tag = "type", rename_all = "snake_case")]
62pub enum SetupSpecInput {
63 Legacy {
64 spec: Value,
65 },
66 ProviderQa {
67 qa_output: Value,
68 #[serde(default)]
69 i18n: BTreeMap<String, String>,
70 },
71}
72
73#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
74pub struct PersistedSetupState {
75 pub schema_version: u32,
76 pub env_id: String,
84 pub provider_id: String,
85 pub source_kind: String,
86 pub form: FormSpec,
87 pub normalized_answers: BTreeMap<String, Value>,
88 pub non_secret_config: BTreeMap<String, Value>,
89 pub secret_refs: BTreeMap<String, SecretRef>,
98}
99
100pub fn form_spec_from_input(
101 input: &SetupSpecInput,
102 provider_id: &str,
103) -> Result<(String, FormSpec)> {
104 match input {
105 SetupSpecInput::Legacy { spec } => {
106 let parsed = match spec {
107 Value::String(raw) => legacy_formspec::parse_setup_spec_str(raw)?,
108 value => legacy_formspec::parse_setup_spec_value(value.clone())?,
109 };
110 Ok((
111 "legacy".to_string(),
112 legacy_formspec::setup_spec_to_form_spec(&parsed, provider_id),
113 ))
114 }
115 SetupSpecInput::ProviderQa { qa_output, i18n } => Ok((
116 "provider_qa".to_string(),
117 qa_bridge::provider_qa_to_form_spec(qa_output, i18n, provider_id),
118 )),
119 }
120}