Skip to main content

spin_factor_variables/
host.rs

1use spin_factors::anyhow;
2use spin_telemetry::traces::{self, Blame};
3use spin_world::{v1, v2::variables, wasi::config as wasi_config};
4use tracing::instrument;
5
6use crate::InstanceState;
7
8impl variables::Host for InstanceState {
9    #[instrument(name = "spin_variables.get", skip(self), fields(otel.kind = "client"))]
10    async fn get(&mut self, key: String) -> Result<String, variables::Error> {
11        self.otel.reparent_tracing_span();
12        let key = spin_expressions::Key::new(&key).map_err(expressions_to_variables_err)?;
13        self.expression_resolver
14            .resolve(&self.component_id, key)
15            .await
16            .map_err(expressions_to_variables_err)
17    }
18
19    fn convert_error(&mut self, error: variables::Error) -> anyhow::Result<variables::Error> {
20        Ok(error)
21    }
22}
23
24impl v1::config::Host for InstanceState {
25    #[instrument(name = "spin_config.get", skip(self), fields(otel.kind = "client"))]
26    async fn get_config(&mut self, key: String) -> Result<String, v1::config::Error> {
27        <Self as variables::Host>::get(self, key)
28            .await
29            .map_err(|err| match err {
30                variables::Error::InvalidName(msg) => v1::config::Error::InvalidKey(msg),
31                variables::Error::Undefined(msg) => v1::config::Error::Provider(msg),
32                other => v1::config::Error::Other(format!("{other}")),
33            })
34    }
35
36    fn convert_error(&mut self, err: v1::config::Error) -> anyhow::Result<v1::config::Error> {
37        Ok(err)
38    }
39}
40
41impl wasi_config::store::Host for InstanceState {
42    #[instrument(name = "wasi_config.get", skip(self), fields(otel.kind = "client"))]
43    async fn get(&mut self, key: String) -> Result<Option<String>, wasi_config::store::Error> {
44        match <Self as variables::Host>::get(self, key).await {
45            Ok(value) => Ok(Some(value)),
46            Err(variables::Error::Undefined(_)) => Ok(None),
47            Err(variables::Error::InvalidName(_)) => Ok(None), // this is the guidance from https://github.com/WebAssembly/wasi-runtime-config/pull/19)
48            Err(variables::Error::Provider(msg)) => Err(wasi_config::store::Error::Upstream(msg)),
49            Err(variables::Error::Other(msg)) => Err(wasi_config::store::Error::Io(msg)),
50        }
51    }
52
53    #[instrument(name = "wasi_config.get_all", skip(self), fields(otel.kind = "client"))]
54    async fn get_all(&mut self) -> Result<Vec<(String, String)>, wasi_config::store::Error> {
55        let all = self
56            .expression_resolver
57            .resolve_all(&self.component_id)
58            .await;
59        all.map_err(|e| {
60            match expressions_to_variables_err(e) {
61                variables::Error::Undefined(msg) => wasi_config::store::Error::Io(msg), // this shouldn't happen but just in case
62                variables::Error::InvalidName(msg) => wasi_config::store::Error::Io(msg), // this shouldn't happen but just in case
63                variables::Error::Provider(msg) => wasi_config::store::Error::Upstream(msg),
64                variables::Error::Other(msg) => wasi_config::store::Error::Io(msg),
65            }
66        })
67    }
68
69    fn convert_error(
70        &mut self,
71        err: wasi_config::store::Error,
72    ) -> anyhow::Result<wasi_config::store::Error> {
73        Ok(err)
74    }
75}
76
77/// Convert a `spin_expressions::Error` to a `variables::Error`, setting the current span's status and fault attribute.
78fn expressions_to_variables_err(err: spin_expressions::Error) -> variables::Error {
79    use spin_expressions::Error;
80    let blame = match err {
81        Error::InvalidName(_) | Error::InvalidTemplate(_) | Error::Undefined(_) => Blame::Guest,
82        Error::Provider(_) => Blame::Host,
83    };
84    traces::mark_as_error(&err, Some(blame));
85    match err {
86        Error::InvalidName(msg) => variables::Error::InvalidName(msg),
87        Error::Undefined(msg) => variables::Error::Undefined(msg),
88        Error::InvalidTemplate(_) => variables::Error::Other(format!("{err}")),
89        Error::Provider(err) => variables::Error::Provider(err.to_string()),
90    }
91}