Skip to main content

greentic_setup/platform_setup/
persistence.rs

1//! Artifact persistence for static routes policy.
2
3use std::path::{Path, PathBuf};
4
5use anyhow::{Context, Result};
6use serde::Deserialize;
7
8use crate::platform_setup::types::StaticRoutesPolicy;
9
10/// Get the path to the static routes artifact file.
11pub fn static_routes_artifact_path(bundle_root: &Path) -> PathBuf {
12    bundle_root
13        .join("state")
14        .join("config")
15        .join("platform")
16        .join("static-routes.json")
17}
18
19/// Load static routes policy from the bundle artifact file.
20pub fn load_static_routes_artifact(bundle_root: &Path) -> Result<Option<StaticRoutesPolicy>> {
21    let path = static_routes_artifact_path(bundle_root);
22    if !path.exists() {
23        return Ok(None);
24    }
25    let raw = std::fs::read_to_string(&path)
26        .with_context(|| format!("failed to read {}", path.display()))?;
27    let policy = serde_json::from_str(&raw)
28        .or_else(|_| serde_yaml_bw::from_str(&raw))
29        .with_context(|| format!("failed to parse {}", path.display()))?;
30    Ok(Some(policy))
31}
32
33#[derive(Debug, Deserialize)]
34struct RuntimeEndpoints {
35    #[allow(dead_code)]
36    tenant: Option<String>,
37    #[allow(dead_code)]
38    team: Option<String>,
39    public_base_url: Option<String>,
40}
41
42/// Load public base URL from runtime endpoints file.
43pub fn load_runtime_public_base_url(
44    bundle_root: &Path,
45    tenant: &str,
46    team: Option<&str>,
47) -> Result<Option<String>> {
48    let team = team.unwrap_or("default");
49    let path = bundle_root
50        .join("state")
51        .join("runtime")
52        .join(format!("{tenant}.{team}"))
53        .join("endpoints.json");
54    if !path.exists() {
55        return Ok(None);
56    }
57    let raw = std::fs::read_to_string(&path)
58        .with_context(|| format!("failed to read {}", path.display()))?;
59    let endpoints: RuntimeEndpoints = serde_json::from_str(&raw)
60        .with_context(|| format!("failed to parse {}", path.display()))?;
61    Ok(endpoints
62        .public_base_url
63        .as_deref()
64        .map(str::trim)
65        .filter(|value| !value.is_empty())
66        .map(ToString::to_string))
67}
68
69/// Load effective static routes defaults, merging artifact and runtime data.
70pub fn load_effective_static_routes_defaults(
71    bundle_root: &Path,
72    tenant: &str,
73    team: Option<&str>,
74) -> Result<Option<StaticRoutesPolicy>> {
75    let mut policy = load_static_routes_artifact(bundle_root)?.unwrap_or_default();
76    if policy.public_base_url.is_none()
77        && let Some(runtime_url) = load_runtime_public_base_url(bundle_root, tenant, team)?
78    {
79        policy.public_base_url = Some(runtime_url);
80    }
81    if policy == StaticRoutesPolicy::disabled() {
82        return Ok(None);
83    }
84    Ok(Some(policy))
85}
86
87/// Persist static routes policy to the bundle artifact file.
88pub fn persist_static_routes_artifact(
89    bundle_root: &Path,
90    policy: &StaticRoutesPolicy,
91) -> Result<PathBuf> {
92    let path = static_routes_artifact_path(bundle_root);
93    if let Some(parent) = path.parent() {
94        std::fs::create_dir_all(parent)?;
95    }
96    let payload = serde_json::to_string_pretty(policy).context("serialize static routes policy")?;
97    std::fs::write(&path, payload)
98        .with_context(|| format!("failed to write {}", path.display()))?;
99    Ok(path)
100}