greentic_deployer/environment/reads.rs
1//! Read-only environment views shared by the local and remote stores.
2//!
3//! The `op` read verbs (`env list`/`show`, the `*-list` verbs, `traffic
4//! show`, `messaging endpoint show`) all project from a single loaded
5//! [`Environment`] — plus, for `env show`, the runtime sidecar.
6//! [`EnvironmentReads`] is the minimal read surface that BOTH
7//! [`LocalFsStore`](super::LocalFsStore) (filesystem) and
8//! [`HttpEnvironmentStore`](super::HttpEnvironmentStore) (the A8 `GET`
9//! endpoints) implement, so a single verb function serves both backends —
10//! the local CLI passes the FS store, the `--store-url` dispatch passes the
11//! HTTP store, and neither projection is duplicated.
12//!
13//! The methods carry distinct names (`load_env`, not `load`) on purpose:
14//! `LocalFsStore` implements both this trait and
15//! [`EnvironmentStore`](super::EnvironmentStore), and reusing `load`/`list`/
16//! `exists` here would make those calls ambiguous on a concrete
17//! `LocalFsStore`.
18//!
19//! Trust-root reads are deliberately NOT on this trait: they come from a
20//! separate document (its own error type) and a separate `GET .../trust-root`
21//! endpoint, so they are wired through an inherent
22//! [`HttpEnvironmentStore::load_trust_root_keys`] method instead.
23
24use greentic_deploy_spec::{EnvId, Environment, EnvironmentRuntime};
25
26use super::store::{EnvironmentStore, LocalFsStore, StoreError};
27
28/// The read surface the `op` read verbs need, implemented by both the
29/// filesystem and HTTP backends.
30pub trait EnvironmentReads: Send + Sync {
31 /// All environment ids known to the store, sorted.
32 fn list_env_ids(&self) -> Result<Vec<EnvId>, StoreError>;
33 /// Whether `env_id` exists.
34 fn env_exists(&self, env_id: &EnvId) -> Result<bool, StoreError>;
35 /// Load the environment document.
36 fn load_env(&self, env_id: &EnvId) -> Result<Environment, StoreError>;
37 /// Load the runtime host-config sidecar, or `None` when none has been
38 /// written. Both backends read it (the HTTP store via `GET
39 /// /environments/{env_id}/runtime`), so `None` means genuinely absent.
40 fn read_runtime(&self, env_id: &EnvId) -> Result<Option<EnvironmentRuntime>, StoreError>;
41}
42
43impl EnvironmentReads for LocalFsStore {
44 fn list_env_ids(&self) -> Result<Vec<EnvId>, StoreError> {
45 EnvironmentStore::list(self)
46 }
47
48 fn env_exists(&self, env_id: &EnvId) -> Result<bool, StoreError> {
49 EnvironmentStore::exists(self, env_id)
50 }
51
52 fn load_env(&self, env_id: &EnvId) -> Result<Environment, StoreError> {
53 EnvironmentStore::load(self, env_id)
54 }
55
56 fn read_runtime(&self, env_id: &EnvId) -> Result<Option<EnvironmentRuntime>, StoreError> {
57 EnvironmentStore::load_runtime(self, env_id)
58 }
59}