Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add basic one-shot tera support, to enable use of environmental varia… #296

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Status: Available for use
## [Unreleased]

### Breaking Changes
- Interpret floki.yaml as a template using tera. Among other function, this allows use of environmental variables in floki config.

### Added

Expand Down
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ shlex = "1.1"
sha2 = "0.10.7"
anyhow = "1.0.71"
thiserror = "1.0.40"
tera = "1"

[dev-dependencies]
tempfile = "3.6.0"
9 changes: 9 additions & 0 deletions docs/content/intro/feature-overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -222,3 +222,12 @@ Note that use of `docker_switches` may reduce the reproducibility and shareabili

Nonetheless, it is useful to be able to add arbitrary switches in a pinch, just to be able to get something working.
If there are things you can add with `docker_switches` which are reproducible and shareable, please raise a feature request, or go ahead and implement it yourself!

# Templating

`floki` supports templating using the [Tera engine](https://tera.netlify.app/). Currently this is executed as a one-shot rendering of your `floki.yaml`. Example uses include referencing environmental variables in the `floki` config, e.g. to mount a subdirectory of the user's home directory:
```yaml
docker_switches:
- -v {{ get_env(name='HOME') }}/.vim:/home/build/.vim
```
Note that extensive use may reduce the reproducibility and shareability of your `floki.yaml`
51 changes: 45 additions & 6 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ use crate::errors;
use crate::image;
use anyhow::Error;
use serde::{Deserialize, Serialize};
use tera::{Context, Tera};

use std::collections::BTreeMap;
use std::fs::File;
use std::fs::read_to_string;
use std::path;

#[derive(Debug, PartialEq, Serialize, Deserialize)]
Expand Down Expand Up @@ -98,14 +99,28 @@ pub(crate) struct FlokiConfig {

impl FlokiConfig {
pub fn from_file(file: &path::Path) -> Result<FlokiConfig, Error> {
debug!("Reading configuration file: {:?}", file);
debug!("Reading configuration file: {}", file.display());

let f = File::open(file).map_err(|e| errors::FlokiError::ProblemOpeningConfigYaml {
name: file.display().to_string(),
error: e,
let contents =
read_to_string(file).map_err(|e| errors::FlokiError::ProblemReadingConfigFile {
name: file.display().to_string(),
error: e,
})?;

let contents = Tera::one_off(&contents, &Context::new(), false).map_err(|e| {
errors::FlokiError::ProblemRenderingConfig {
name: file.display().to_string(),
error: e,
}
})?;

let mut config: FlokiConfig = serde_yaml::from_reader(f).map_err(|e| {
debug!(
"Rendered '{}' into text configuration:\n{}",
file.display(),
contents
);

let mut config: FlokiConfig = serde_yaml::from_str(&contents).map_err(|e| {
errors::FlokiError::ProblemParsingConfigYaml {
name: file.display().to_string(),
error: e,
Expand Down Expand Up @@ -160,6 +175,30 @@ fn default_entrypoint() -> Entrypoint {
#[cfg(test)]
mod test {
use super::*;
use image::Image;

#[derive(Debug, PartialEq, Serialize, Deserialize)]
struct TestImageConfig {
image: Image,
}

#[test]
fn test_user_env_config() {
std::env::set_var("image", "a_local_user_variable");

let expected = TestImageConfig {
image: Image::Name("prefix_a_local_user_variable:1.1".into()),
};

let content = Tera::one_off(
"image: \"prefix_{{ get_env(name='image') }}:1.1\"",
&Context::new(),
false,
)
.unwrap();
let actual: TestImageConfig = serde_yaml::from_str(&content).unwrap();
assert!(actual == expected);
}

#[derive(Debug, PartialEq, Serialize, Deserialize)]
struct TestShellConfig {
Expand Down
9 changes: 7 additions & 2 deletions src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,13 @@ pub enum FlokiError {
#[error("Could not normalize the file path '{name}': {error:?}")]
ProblemNormalizingFilePath { name: String, error: io::Error },

#[error("There was a problem opening the configuration file '{name}': {error:?}")]
ProblemOpeningConfigYaml { name: String, error: io::Error },
#[error("There was a problem reading the configuration file '{name}': {error:?}")]
ProblemReadingConfigFile { name: String, error: io::Error },

#[error(
"There was a problem rendering configuration from the template file '{name}': {error:?}"
)]
ProblemRenderingConfig { name: String, error: tera::Error },

#[error("There was a problem parsing the configuration file '{name}': {error:?}")]
ProblemParsingConfigYaml {
Expand Down
Loading