spin_variables/
lib.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
//! The runtime configuration for the variables factor used in the Spin CLI.

mod azure_key_vault;
mod env;
mod statik;
mod vault;

pub use azure_key_vault::*;
pub use env::*;
pub use statik::*;
pub use vault::*;

use serde::Deserialize;
use spin_expressions::Provider;
use spin_factors::{anyhow, runtime_config::toml::GetTomlValue};

use spin_factor_variables::runtime_config::RuntimeConfig;

/// Resolves a runtime configuration for the variables factor from a TOML table.
pub fn runtime_config_from_toml(table: &impl GetTomlValue) -> anyhow::Result<RuntimeConfig> {
    // Always include the environment variable provider.
    let var_provider = vec![Box::<EnvVariablesProvider>::default() as _];
    let value = table
        .get("variables_provider")
        .or_else(|| table.get("config_provider"));
    let Some(array) = value else {
        return Ok(RuntimeConfig {
            providers: var_provider,
        });
    };

    let provider_configs: Vec<VariableProviderConfiguration> = array.clone().try_into()?;
    let mut providers = provider_configs
        .into_iter()
        .map(VariableProviderConfiguration::into_provider)
        .collect::<anyhow::Result<Vec<_>>>()?;
    providers.extend(var_provider);
    Ok(RuntimeConfig { providers })
}

/// A runtime configuration used in the Spin CLI for one type of variable provider.
#[derive(Debug, Deserialize)]
#[serde(rename_all = "snake_case", tag = "type")]
pub enum VariableProviderConfiguration {
    /// A provider that uses Azure Key Vault.
    AzureKeyVault(AzureKeyVaultVariablesConfig),
    /// A static provider of variables.
    Static(StaticVariablesProvider),
    /// A provider that uses HashiCorp Vault.
    Vault(VaultVariablesProvider),
    /// An environment variable provider.
    Env(EnvVariablesConfig),
}

impl VariableProviderConfiguration {
    /// Returns the provider for the configuration.
    pub fn into_provider(self) -> anyhow::Result<Box<dyn Provider>> {
        let provider: Box<dyn Provider> = match self {
            VariableProviderConfiguration::Static(provider) => Box::new(provider),
            VariableProviderConfiguration::Env(config) => Box::new(env::EnvVariablesProvider::new(
                config.prefix,
                |s| std::env::var(s),
                config.dotenv_path,
            )),
            VariableProviderConfiguration::Vault(provider) => Box::new(provider),
            VariableProviderConfiguration::AzureKeyVault(config) => Box::new(
                AzureKeyVaultProvider::create(config.vault_url.clone(), config.try_into()?)?,
            ),
        };
        Ok(provider)
    }
}