From f7d90cc7ca8a88d1f6be2b7ed523f2586ea3ba55 Mon Sep 17 00:00:00 2001 From: qubitrenagade Date: Sat, 2 Feb 2019 18:25:30 -0700 Subject: [PATCH 01/39] Attempt to render config file from handlebars... Signed-off-by: qubitrenagade --- components/hab/src/cli.rs | 8 ++ components/hab/src/command/plan/mod.rs | 1 + components/hab/src/command/plan/render.rs | 99 +++++++++++++++++++++++ components/hab/src/lib.rs | 3 + components/hab/src/main.rs | 31 +++++++ support/linux/install_dev_9_linux.sh | 4 +- 6 files changed, 144 insertions(+), 2 deletions(-) create mode 100644 components/hab/src/command/plan/render.rs diff --git a/components/hab/src/cli.rs b/components/hab/src/cli.rs index 73e13e556f..b344522eab 100644 --- a/components/hab/src/cli.rs +++ b/components/hab/src/cli.rs @@ -580,6 +580,14 @@ pub fn get() -> App<'static, 'static> { (@arg SCAFFOLDING: --scaffolding -s +takes_value "Specify explicit Scaffolding for your app (ex: node, ruby)") ) + (@subcommand render => + (about: "Renders plan config files") + (aliases: &["r", "re", "ren", "rend", "rende"]) + (@arg TEMPLATE_PATH: +required +takes_value "Path to config to render") + (@arg DEFAULT_TOML: -d --("default-toml") +takes_value"Path to default.toml, defaults to ./default.toml") + (@arg MOCK_DATA: -m --("mock-data") +takes_value "Path to json file with mock data for template, defaults to none") + (@arg RENDER_DIR: -r --("render-dir") +takes_value"Path to render templates to, defaults to ./results/") + ) ) (@subcommand ring => (about: "Commands relating to Habitat rings") diff --git a/components/hab/src/command/plan/mod.rs b/components/hab/src/command/plan/mod.rs index 66d2764efe..4aad7f1dfc 100644 --- a/components/hab/src/command/plan/mod.rs +++ b/components/hab/src/command/plan/mod.rs @@ -13,3 +13,4 @@ // limitations under the License. pub mod init; +pub mod render; diff --git a/components/hab/src/command/plan/render.rs b/components/hab/src/command/plan/render.rs new file mode 100644 index 0000000000..b2284c5f67 --- /dev/null +++ b/components/hab/src/command/plan/render.rs @@ -0,0 +1,99 @@ +// Copyright (c) 2016 Chef Software Inc. and/or applicable contributors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use std::collections::HashMap; +// use std::env; +use std::fs::create_dir_all; +use std::fs::{File, read_to_string}; +use std::io::{BufRead, BufReader, Write}; +use std::path::Path; + +use serde::Serialize; +use serde_json::{self, Value as Json}; + +use handlebars::Handlebars; + +use crate::common::templating::*; +use crate::common::ui::{Status, UIWriter, UI}; +use crate::error::Result; + +pub fn start( + ui: &mut UI, + template_path: String, + default_toml_path: String, + mock_data_path: Option, + render_dir: String, +) -> Result<()> { + // create necessary vars + let handlebars = Handlebars::new(); + // let mut data = HashMap::new(); + + // let mut new_data = convert_to_json(&data); + // Strip the file name out of our passed template + let file_name = match Path::new(&template_path).file_name() { + Some(name) => name.to_str().clone().unwrap(), + None => panic!(format!("Something went wrong getting filename of {}", &template_path)), + }; + + ui.begin(format!("Rendering: {} into: {}/ as: {}", template_path, render_dir, file_name))?; + ui.br()?; + + // Build out the variables passed. + // data.insert("pkg_name".to_string(), "test".to_string()); + + // read our template from file + let template = read_to_string(&template_path) + .expect(&format!("something went wrong reading: {}", template_path)); + + let mock_data = match mock_data_path { + Some(path) => read_to_string(path.to_string()) + .expect(&format!("Something went wrong reading: {}", path.to_string())), + None => "{}".to_string(), + }; + + + let json: Json = serde_json::from_str(&mock_data).unwrap(); + // println!("mock_data: {}", json); + // println!("{}", template); + //let content = render(template, json)?; + + let mut renderer = TemplateRenderer::new(); + renderer + .register_template_string("testing", &template) + .expect("Could not register template content"); + renderer + .render("testing", &mock_data) + .expect("Could not render template"); + + + // We want to render the configured variables. + // let rendered_template = handlebars.template_render(&template, &json)?; + + // println!("#################\nRendered template:\n{}\n#############", rendered_template); + // println!("######\nRendered template:\n{}\n#######", renderer); + create_with_template(ui, &format!("{}/{}", render_dir, file_name), &renderer.to_string())?; + Ok(()) +} + +fn create_with_template(ui: &mut UI, location: &str, template: &str) -> Result<()> { + let path = Path::new(&location); + ui.status(Status::Creating, format!("file: {}", location))?; + // If the directory doesn't exist we need to make it. + if let Some(directory) = path.parent() { + create_dir_all(directory)?; + } + // Create and then render the template with Handlebars + File::create(path).and_then(|mut file| file.write(template.as_bytes()))?; + Ok(()) +} diff --git a/components/hab/src/lib.rs b/components/hab/src/lib.rs index ed75b517e4..e570d94916 100644 --- a/components/hab/src/lib.rs +++ b/components/hab/src/lib.rs @@ -36,6 +36,9 @@ extern crate log; #[macro_use] extern crate serde_derive; +#[macro_use] +extern crate serde_json; + #[cfg(windows)] extern crate widestring; #[cfg(windows)] diff --git a/components/hab/src/main.rs b/components/hab/src/main.rs index 2b6c6065b3..74c6c4ff45 100644 --- a/components/hab/src/main.rs +++ b/components/hab/src/main.rs @@ -280,6 +280,7 @@ fn start(ui: &mut UI) -> Result<()> { ("plan", Some(matches)) => { match matches.subcommand() { ("init", Some(m)) => sub_plan_init(ui, m)?, + ("render", Some(m)) => sub_plan_render(ui, m)?, _ => unreachable!(), } } @@ -702,6 +703,36 @@ fn sub_plan_init(ui: &mut UI, m: &ArgMatches<'_>) -> Result<()> { name) } +fn sub_plan_render(ui: &mut UI, m: &ArgMatches<'_>) -> Result<()> { + let template_path = match m.value_of("TEMPLATE_PATH") { + Some(o) => o.to_string(), + None => return Err(Error::CryptoCLI("No config to render specified".to_string())), + }; + + let default_toml_path = match m.value_of("DEFAULT_TOML") { + Some(o) => o.to_string(), + None => "./default.toml".to_string(), + }; + + let mock_data_path = match m.value_of("MOCK_DATA") { + Some(o) => Some(o.to_string()), + None => None + }; + + let render_dir = match m.value_of("RENDER_DIR") { + Some(name) => name.to_string(), + None => "result".into(), + }; + + command::plan::render::start( + ui, + template_path, + default_toml_path, + mock_data_path, + render_dir, + ) +} + fn sub_pkg_install(ui: &mut UI, m: &ArgMatches<'_>) -> Result<()> { let url = bldr_url_from_matches(&m)?; let channel = channel_from_matches_or_default(m); diff --git a/support/linux/install_dev_9_linux.sh b/support/linux/install_dev_9_linux.sh index 6ecd3156c5..01a98b28a6 100755 --- a/support/linux/install_dev_9_linux.sh +++ b/support/linux/install_dev_9_linux.sh @@ -43,6 +43,6 @@ else sudo -E addgroup --system hab || true fi -sudo sh /tmp/install.sh +sudo bash /tmp/install.sh sudo hab install core/busybox-static core/hab-studio -sudo rm -rf /tmp/install.sh +sudo rm -f /tmp/install.sh From a8dee0672f8bb9ea01b83d58ddede2d1013fac23 Mon Sep 17 00:00:00 2001 From: qubitrenagade Date: Sat, 2 Feb 2019 18:56:53 -0700 Subject: [PATCH 02/39] should be rendering json? Signed-off-by: qubitrenagade --- components/hab/src/command/plan/render.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/hab/src/command/plan/render.rs b/components/hab/src/command/plan/render.rs index b2284c5f67..035fa8ab6b 100644 --- a/components/hab/src/command/plan/render.rs +++ b/components/hab/src/command/plan/render.rs @@ -73,7 +73,7 @@ pub fn start( .register_template_string("testing", &template) .expect("Could not register template content"); renderer - .render("testing", &mock_data) + .render("testing", &json) .expect("Could not render template"); From bbbd752020cf6ff0e8f7ecf8a90a2da97dd8afba Mon Sep 17 00:00:00 2001 From: qubitrenagade Date: Sat, 2 Feb 2019 19:59:33 -0700 Subject: [PATCH 03/39] Add --print method to print config to STDOUT Signed-off-by: qubitrenagade --- components/hab/src/cli.rs | 1 + components/hab/src/command/plan/render.rs | 56 ++++++++++------------- components/hab/src/lib.rs | 1 - components/hab/src/main.rs | 3 ++ 4 files changed, 28 insertions(+), 33 deletions(-) diff --git a/components/hab/src/cli.rs b/components/hab/src/cli.rs index b344522eab..ad3cd0a882 100644 --- a/components/hab/src/cli.rs +++ b/components/hab/src/cli.rs @@ -586,6 +586,7 @@ pub fn get() -> App<'static, 'static> { (@arg TEMPLATE_PATH: +required +takes_value "Path to config to render") (@arg DEFAULT_TOML: -d --("default-toml") +takes_value"Path to default.toml, defaults to ./default.toml") (@arg MOCK_DATA: -m --("mock-data") +takes_value "Path to json file with mock data for template, defaults to none") + (@arg PRINT: -p --("print") "Prints config to STDOUT") (@arg RENDER_DIR: -r --("render-dir") +takes_value"Path to render templates to, defaults to ./results/") ) ) diff --git a/components/hab/src/command/plan/render.rs b/components/hab/src/command/plan/render.rs index 035fa8ab6b..94a01ccea2 100644 --- a/components/hab/src/command/plan/render.rs +++ b/components/hab/src/command/plan/render.rs @@ -12,34 +12,29 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::collections::HashMap; -// use std::env; use std::fs::create_dir_all; use std::fs::{File, read_to_string}; -use std::io::{BufRead, BufReader, Write}; +use std::io::{Write}; use std::path::Path; - -use serde::Serialize; use serde_json::{self, Value as Json}; -use handlebars::Handlebars; - -use crate::common::templating::*; +use crate::common::templating::TemplateRenderer; use crate::common::ui::{Status, UIWriter, UI}; use crate::error::Result; +// TODO: +// * Need to figure out how to merge TOML and JSON +// * Need to figure out how to load multiple files + + pub fn start( ui: &mut UI, template_path: String, default_toml_path: String, mock_data_path: Option, + print: bool, render_dir: String, ) -> Result<()> { - // create necessary vars - let handlebars = Handlebars::new(); - // let mut data = HashMap::new(); - - // let mut new_data = convert_to_json(&data); // Strip the file name out of our passed template let file_name = match Path::new(&template_path).file_name() { Some(name) => name.to_str().clone().unwrap(), @@ -49,9 +44,6 @@ pub fn start( ui.begin(format!("Rendering: {} into: {}/ as: {}", template_path, render_dir, file_name))?; ui.br()?; - // Build out the variables passed. - // data.insert("pkg_name".to_string(), "test".to_string()); - // read our template from file let template = read_to_string(&template_path) .expect(&format!("something went wrong reading: {}", template_path)); @@ -62,27 +54,27 @@ pub fn start( None => "{}".to_string(), }; - + // convert our mock_data into a string(?) let json: Json = serde_json::from_str(&mock_data).unwrap(); - // println!("mock_data: {}", json); - // println!("{}", template); - //let content = render(template, json)?; + + // create a template renderer let mut renderer = TemplateRenderer::new(); + // register our template renderer - .register_template_string("testing", &template) + .register_template_string(&template_path, &template) .expect("Could not register template content"); - renderer - .render("testing", &json) - .expect("Could not render template"); - - - // We want to render the configured variables. - // let rendered_template = handlebars.template_render(&template, &json)?; + // render our JSON override in our template. + let rendered_template = renderer.render(&template_path, &json).ok().unwrap(); - // println!("#################\nRendered template:\n{}\n#############", rendered_template); - // println!("######\nRendered template:\n{}\n#######", renderer); - create_with_template(ui, &format!("{}/{}", render_dir, file_name), &renderer.to_string())?; + if print { + ui.warn(format!("Rendered template: {}", &template_path))?; + + println!("{}", rendered_template); + } + // Render our template file + create_with_template(ui, &format!("{}/{}", render_dir, file_name), &rendered_template)?; + // not really sure this is correct... Ok(()) } @@ -93,7 +85,7 @@ fn create_with_template(ui: &mut UI, location: &str, template: &str) -> Result<( if let Some(directory) = path.parent() { create_dir_all(directory)?; } - // Create and then render the template with Handlebars + // Write file to disk File::create(path).and_then(|mut file| file.write(template.as_bytes()))?; Ok(()) } diff --git a/components/hab/src/lib.rs b/components/hab/src/lib.rs index e570d94916..d46aa5c57b 100644 --- a/components/hab/src/lib.rs +++ b/components/hab/src/lib.rs @@ -36,7 +36,6 @@ extern crate log; #[macro_use] extern crate serde_derive; -#[macro_use] extern crate serde_json; #[cfg(windows)] diff --git a/components/hab/src/main.rs b/components/hab/src/main.rs index 74c6c4ff45..2c1c6123bb 100644 --- a/components/hab/src/main.rs +++ b/components/hab/src/main.rs @@ -719,6 +719,8 @@ fn sub_plan_render(ui: &mut UI, m: &ArgMatches<'_>) -> Result<()> { None => None }; + let print = m.is_present("PRINT"); + let render_dir = match m.value_of("RENDER_DIR") { Some(name) => name.to_string(), None => "result".into(), @@ -729,6 +731,7 @@ fn sub_plan_render(ui: &mut UI, m: &ArgMatches<'_>) -> Result<()> { template_path, default_toml_path, mock_data_path, + print, render_dir, ) } From 5b6dcadba643f63980a1fe957ed63c5edb020f7e Mon Sep 17 00:00:00 2001 From: qubitrenagade Date: Sat, 2 Feb 2019 23:40:35 -0700 Subject: [PATCH 04/39] Add test files. add --default-toml and --user-toml config logic. --- components/hab/src/cli.rs | 5 +- components/hab/src/command/plan/render.rs | 71 +++++++++++++++++++---- components/hab/src/main.rs | 6 ++ test/fixtures/render/consul_config.json | 21 +++++++ test/fixtures/render/default.toml | 31 ++++++++++ test/fixtures/render/override.json | 22 +++++++ test/fixtures/render/user.toml | 3 + 7 files changed, 146 insertions(+), 13 deletions(-) create mode 100644 test/fixtures/render/consul_config.json create mode 100644 test/fixtures/render/default.toml create mode 100644 test/fixtures/render/override.json create mode 100644 test/fixtures/render/user.toml diff --git a/components/hab/src/cli.rs b/components/hab/src/cli.rs index ad3cd0a882..2a5539c2e8 100644 --- a/components/hab/src/cli.rs +++ b/components/hab/src/cli.rs @@ -584,10 +584,11 @@ pub fn get() -> App<'static, 'static> { (about: "Renders plan config files") (aliases: &["r", "re", "ren", "rend", "rende"]) (@arg TEMPLATE_PATH: +required +takes_value "Path to config to render") - (@arg DEFAULT_TOML: -d --("default-toml") +takes_value"Path to default.toml, defaults to ./default.toml") + (@arg DEFAULT_TOML: -d --("default-toml") +takes_value "Path to default.toml, defaults to ./default.toml") + (@arg USER_TOML: -u --("user-toml") +takes_value "Path to user.toml, defaults to none") (@arg MOCK_DATA: -m --("mock-data") +takes_value "Path to json file with mock data for template, defaults to none") (@arg PRINT: -p --("print") "Prints config to STDOUT") - (@arg RENDER_DIR: -r --("render-dir") +takes_value"Path to render templates to, defaults to ./results/") + (@arg RENDER_DIR: -r --("render-dir") +takes_value "Path to render templates to, defaults to ./results/") ) ) (@subcommand ring => diff --git a/components/hab/src/command/plan/render.rs b/components/hab/src/command/plan/render.rs index 94a01ccea2..23d0e3c92b 100644 --- a/components/hab/src/command/plan/render.rs +++ b/components/hab/src/command/plan/render.rs @@ -17,20 +17,17 @@ use std::fs::{File, read_to_string}; use std::io::{Write}; use std::path::Path; use serde_json::{self, Value as Json}; +use toml::Value; use crate::common::templating::TemplateRenderer; use crate::common::ui::{Status, UIWriter, UI}; use crate::error::Result; -// TODO: -// * Need to figure out how to merge TOML and JSON -// * Need to figure out how to load multiple files - - pub fn start( ui: &mut UI, template_path: String, default_toml_path: String, + user_toml_path: Option, mock_data_path: Option, print: bool, render_dir: String, @@ -48,15 +45,54 @@ pub fn start( let template = read_to_string(&template_path) .expect(&format!("something went wrong reading: {}", template_path)); + // create a "data" json struct + let mut data: Json = serde_json::from_str("{}").unwrap(); + + // import default.toml values, convert to JSON + ui.begin(format!("Importing default.toml: {}", &default_toml_path))?; + let default_toml = read_to_string(&default_toml_path) + .expect(&format!("Something went wrong reading: {}", &default_toml_path)); + let default_toml_value = default_toml.parse::().expect("Error parsing TOML"); + let default_toml_string = serde_json::to_string_pretty(&default_toml_value).expect("Error encoding JSON"); + let default_toml_json: Json = serde_json::from_str(&format!(r#"{{ "cfg": {} }}"#, &default_toml_string)).unwrap(); + + // merge default into data struct + merge(&mut data, default_toml_json); + + // import default.toml values, convert to JSON + // ui.begin(format!("Importing user.toml: {}", &user_toml_path)); + let user_toml = match user_toml_path { + Some(path) => { + ui.begin(format!("Importing user.toml: {}", path.to_string()))?; + read_to_string(path.to_string()) + .expect(&format!("Something went wrong reading: {}", path.to_string())) + }, + None => "".to_string(), + }; + // copy/paste ftw! This could probably stand to be DRY'd up.../there's gotta be an easier way + let user_toml_value = user_toml.parse::().expect("Error parsing TOML"); + let user_toml_string = serde_json::to_string_pretty(&user_toml_value).expect("Error encoding JSON"); + let user_toml_json: Json = serde_json::from_str(&format!(r#"{{ "cfg": {} }}"#, &user_toml_string)).unwrap(); + + // merge default into data struct + merge(&mut data, user_toml_json); + + // read mock data if provided + // ui.begin(format!("Importing override: {}", &mock_data_path)); let mock_data = match mock_data_path { - Some(path) => read_to_string(path.to_string()) - .expect(&format!("Something went wrong reading: {}", path.to_string())), + Some(path) => { + ui.begin(format!("Importing override file: {}", path.to_string()))?; + read_to_string(path.to_string()) + .expect(&format!("Something went wrong reading: {}", path.to_string())) + }, None => "{}".to_string(), }; - // convert our mock_data into a string(?) - let json: Json = serde_json::from_str(&mock_data).unwrap(); + // convert our mock_data into a json::Value + let mock_data_json: Json = serde_json::from_str(&mock_data).unwrap(); + // merge mock data into + merge(&mut data, mock_data_json); // create a template renderer let mut renderer = TemplateRenderer::new(); @@ -65,19 +101,32 @@ pub fn start( .register_template_string(&template_path, &template) .expect("Could not register template content"); // render our JSON override in our template. - let rendered_template = renderer.render(&template_path, &json).ok().unwrap(); + let rendered_template = renderer.render(&template_path, &data).ok().unwrap(); if print { ui.warn(format!("Rendered template: {}", &template_path))?; - println!("{}", rendered_template); } + // Render our template file create_with_template(ui, &format!("{}/{}", render_dir, file_name), &rendered_template)?; + ui.br()?; // not really sure this is correct... Ok(()) } +fn merge(a: &mut Json, b: Json) { + match (a, b) { + (a @ &mut Json::Object(_), Json::Object(b)) => { + let a = a.as_object_mut().unwrap(); + for (k, v) in b { + merge(a.entry(k).or_insert(Json::Null), v); + } + } + (a, b) => *a = b, + } +} + fn create_with_template(ui: &mut UI, location: &str, template: &str) -> Result<()> { let path = Path::new(&location); ui.status(Status::Creating, format!("file: {}", location))?; diff --git a/components/hab/src/main.rs b/components/hab/src/main.rs index 2c1c6123bb..74d55c7951 100644 --- a/components/hab/src/main.rs +++ b/components/hab/src/main.rs @@ -714,6 +714,11 @@ fn sub_plan_render(ui: &mut UI, m: &ArgMatches<'_>) -> Result<()> { None => "./default.toml".to_string(), }; + let user_toml_path = match m.value_of("USER_TOML") { + Some(o) => Some(o.to_string()), + None => None + }; + let mock_data_path = match m.value_of("MOCK_DATA") { Some(o) => Some(o.to_string()), None => None @@ -730,6 +735,7 @@ fn sub_plan_render(ui: &mut UI, m: &ArgMatches<'_>) -> Result<()> { ui, template_path, default_toml_path, + user_toml_path, mock_data_path, print, render_dir, diff --git a/test/fixtures/render/consul_config.json b/test/fixtures/render/consul_config.json new file mode 100644 index 0000000000..fdb1985ead --- /dev/null +++ b/test/fixtures/render/consul_config.json @@ -0,0 +1,21 @@ +{ + "datacenter": "{{cfg.server.datacenter}}", + "data_dir": "{{cfg.server.data-dir}}", + "log_level": "{{cfg.server.loglevel}}", + "bind_addr": "{{sys.ip}}", + "client_addr": "{{sys.ip}}", + "server": {{cfg.server.mode}}, + "retry_join": [ + {{#eachAlive svc.members as |member| ~}} + "{{member.sys.ip}}" {{~#unless @last}},{{/unless}} + {{/eachAlive ~}} + ], + "ports": { + "dns": {{cfg.ports.dns}}, + "http": {{cfg.ports.http}}, + "https": {{cfg.ports.https}}, + "serf_lan": {{cfg.ports.serf_lan}}, + "serf_wan": {{cfg.ports.serf_wan}}, + "server": {{cfg.ports.server}} + } +} diff --git a/test/fixtures/render/default.toml b/test/fixtures/render/default.toml new file mode 100644 index 0000000000..8730e79471 --- /dev/null +++ b/test/fixtures/render/default.toml @@ -0,0 +1,31 @@ +# If you would like the web gui on the agent +website = true + +# The options for consul are available here +# https://www.consul.io/docs/agent/options.html +[bootstrap] +expect = "3" + +[server] +data-dir = "/hab/svc/consul/data/consul" +datacenter = "dc1" +loglevel = "INFO" +# Revert back to the Legacy UI +legacy_ui = false +# switch this to false you want to start in DEVMODE +# https://www.consul.io/docs/guides/bootstrapping.html +mode = true + +[ports] +# The DNS server, -1 to disable +dns = 8600 +# The HTTP API, -1 to disable +http = 8500 +# The HTTPS API, -1 to disable +https = -1 +# The Serf LAN port +serf_lan = 8301 +# The Serf WAN port +serf_wan = 8302 +# Server RPC address +server = 8300 diff --git a/test/fixtures/render/override.json b/test/fixtures/render/override.json new file mode 100644 index 0000000000..b90d20f94d --- /dev/null +++ b/test/fixtures/render/override.json @@ -0,0 +1,22 @@ +{ + "cfg": { + "server": { + "datacenter": "fooo" + }, + "ports": { + "dns": 6666, + "http": 6667, + "https": 6668 + } + }, + "sys": { + "ip": "9.9.9.9" + }, + "svc": { + "members": [ + { "active": true, "sys": { "ip": "1.1.1.1" }}, + { "properties": { "active": true}, "sys": { "ip": "2.2.2.2" }}, + { "sys": { "ip": "3.3.3.3" }} + ] + } +} diff --git a/test/fixtures/render/user.toml b/test/fixtures/render/user.toml new file mode 100644 index 0000000000..a588d1760d --- /dev/null +++ b/test/fixtures/render/user.toml @@ -0,0 +1,3 @@ +[ports] +serf_lan = 8888 +server = 9999 From 746ae98b7f45cbc2d29e1b9c92cb16da8da86b69 Mon Sep 17 00:00:00 2001 From: qubitrenagade Date: Sun, 3 Feb 2019 00:35:44 -0700 Subject: [PATCH 05/39] DRY up toml to json conversion with toml_to_json function Signed-off-by: qubitrenagade --- components/hab/src/command/plan/render.rs | 36 ++++++++++++----------- test/fixtures/render/default.toml | 2 +- test/fixtures/render/override.json | 2 +- test/fixtures/render/user.toml | 3 ++ 4 files changed, 24 insertions(+), 19 deletions(-) diff --git a/components/hab/src/command/plan/render.rs b/components/hab/src/command/plan/render.rs index 23d0e3c92b..d8a1dc318e 100644 --- a/components/hab/src/command/plan/render.rs +++ b/components/hab/src/command/plan/render.rs @@ -52,12 +52,8 @@ pub fn start( ui.begin(format!("Importing default.toml: {}", &default_toml_path))?; let default_toml = read_to_string(&default_toml_path) .expect(&format!("Something went wrong reading: {}", &default_toml_path)); - let default_toml_value = default_toml.parse::().expect("Error parsing TOML"); - let default_toml_string = serde_json::to_string_pretty(&default_toml_value).expect("Error encoding JSON"); - let default_toml_json: Json = serde_json::from_str(&format!(r#"{{ "cfg": {} }}"#, &default_toml_string)).unwrap(); - // merge default into data struct - merge(&mut data, default_toml_json); + merge(&mut data, toml_to_json(&default_toml)); // import default.toml values, convert to JSON // ui.begin(format!("Importing user.toml: {}", &user_toml_path)); @@ -69,13 +65,8 @@ pub fn start( }, None => "".to_string(), }; - // copy/paste ftw! This could probably stand to be DRY'd up.../there's gotta be an easier way - let user_toml_value = user_toml.parse::().expect("Error parsing TOML"); - let user_toml_string = serde_json::to_string_pretty(&user_toml_value).expect("Error encoding JSON"); - let user_toml_json: Json = serde_json::from_str(&format!(r#"{{ "cfg": {} }}"#, &user_toml_string)).unwrap(); - // merge default into data struct - merge(&mut data, user_toml_json); + merge(&mut data, toml_to_json(&user_toml)); // read mock data if provided // ui.begin(format!("Importing override: {}", &mock_data_path)); @@ -87,12 +78,8 @@ pub fn start( }, None => "{}".to_string(), }; - - // convert our mock_data into a json::Value - let mock_data_json: Json = serde_json::from_str(&mock_data).unwrap(); - - // merge mock data into - merge(&mut data, mock_data_json); + // merge mock data into data + merge(&mut data, serde_json::from_str(&mock_data).unwrap()); // create a template renderer let mut renderer = TemplateRenderer::new(); @@ -115,14 +102,29 @@ pub fn start( Ok(()) } +fn toml_to_json(cfg: &str) -> Json { + // parse TOML string to Value + let toml_value = cfg.parse::().expect("Error parsing TOML"); + // convert toml to json string + let toml_string = serde_json::to_string(&toml_value).expect("Error encoding JSON"); + // convert to Json::Value + serde_json::from_str(&format!(r#"{{ "cfg": {} }}"#, &toml_string)).unwrap() +} + +// merge two Json structs fn merge(a: &mut Json, b: Json) { match (a, b) { + // not sure I understand this... (a @ &mut Json::Object(_), Json::Object(b)) => { + // not sure I understand why we unwrap this let a = a.as_object_mut().unwrap(); + // Iterate through key/values in Json object b, + // merge with Json object b for (k, v) in b { merge(a.entry(k).or_insert(Json::Null), v); } } + // or this... (a, b) => *a = b, } } diff --git a/test/fixtures/render/default.toml b/test/fixtures/render/default.toml index 8730e79471..5b1c806317 100644 --- a/test/fixtures/render/default.toml +++ b/test/fixtures/render/default.toml @@ -7,7 +7,7 @@ website = true expect = "3" [server] -data-dir = "/hab/svc/consul/data/consul" +data-dir = "IN_DEFAULT_TOML" datacenter = "dc1" loglevel = "INFO" # Revert back to the Legacy UI diff --git a/test/fixtures/render/override.json b/test/fixtures/render/override.json index b90d20f94d..4d6b9bdcd1 100644 --- a/test/fixtures/render/override.json +++ b/test/fixtures/render/override.json @@ -1,7 +1,7 @@ { "cfg": { "server": { - "datacenter": "fooo" + "datacenter": "IN_OVERRIDE_JSON" }, "ports": { "dns": 6666, diff --git a/test/fixtures/render/user.toml b/test/fixtures/render/user.toml index a588d1760d..24c91d0014 100644 --- a/test/fixtures/render/user.toml +++ b/test/fixtures/render/user.toml @@ -1,3 +1,6 @@ +[server] +loglevel = "IN_USER_TOML" + [ports] serf_lan = 8888 server = 9999 From 3b9afbd3f796f6a65cbaf758fd05dc8531417194 Mon Sep 17 00:00:00 2001 From: qubitrenagade Date: Sun, 3 Feb 2019 00:49:59 -0700 Subject: [PATCH 06/39] moved config and hooks files into respective directories --- .../fixtures/render/{ => config}/consul_config.json | 0 test/fixtures/render/hooks/run | 13 +++++++++++++ 2 files changed, 13 insertions(+) rename test/fixtures/render/{ => config}/consul_config.json (100%) create mode 100644 test/fixtures/render/hooks/run diff --git a/test/fixtures/render/consul_config.json b/test/fixtures/render/config/consul_config.json similarity index 100% rename from test/fixtures/render/consul_config.json rename to test/fixtures/render/config/consul_config.json diff --git a/test/fixtures/render/hooks/run b/test/fixtures/render/hooks/run new file mode 100644 index 0000000000..f880abc2bb --- /dev/null +++ b/test/fixtures/render/hooks/run @@ -0,0 +1,13 @@ +#!/bin/sh + +exec 2>&1 + +SERVERMODE={{cfg.server.mode}} +export CONSUL_UI_LEGACY={{cfg.server.legacy_ui}} + +CONSUL_OPTS="-dev" +if [ "$SERVERMODE" = true ]; then + CONSUL_OPTS="{{~#if cfg.website}} -ui {{~/if}} -server -bootstrap-expect {{cfg.bootstrap.expect}} -config-file={{pkg.svc_config_path}}/basic_config.json" +fi + +exec consul agent ${CONSUL_OPTS} From 312582939639edbf3d8bd31a23f35e421f46abfe Mon Sep 17 00:00:00 2001 From: qubitrenagade Date: Sun, 3 Feb 2019 01:12:27 -0700 Subject: [PATCH 07/39] add commentary. Signed-off-by: qubitrenagade --- components/hab/src/command/plan/render.rs | 13 ++- test/fixtures/render/README.md | 87 +++++++++++++++++++ .../{ => consul}/config/consul_config.json | 0 .../fixtures/render/{ => consul}/default.toml | 0 test/fixtures/render/{ => consul}/hooks/run | 0 .../render/{ => consul}/override.json | 0 test/fixtures/render/{ => consul}/user.toml | 0 7 files changed, 98 insertions(+), 2 deletions(-) create mode 100644 test/fixtures/render/README.md rename test/fixtures/render/{ => consul}/config/consul_config.json (100%) rename test/fixtures/render/{ => consul}/default.toml (100%) rename test/fixtures/render/{ => consul}/hooks/run (100%) rename test/fixtures/render/{ => consul}/override.json (100%) rename test/fixtures/render/{ => consul}/user.toml (100%) diff --git a/components/hab/src/command/plan/render.rs b/components/hab/src/command/plan/render.rs index d8a1dc318e..e8a1f3417e 100644 --- a/components/hab/src/command/plan/render.rs +++ b/components/hab/src/command/plan/render.rs @@ -50,6 +50,8 @@ pub fn start( // import default.toml values, convert to JSON ui.begin(format!("Importing default.toml: {}", &default_toml_path))?; + // we should always have a default.toml, would be nice to "autodiscover" based on package name, + // for now assume we're working in the plan dir if --default-toml not passed let default_toml = read_to_string(&default_toml_path) .expect(&format!("Something went wrong reading: {}", &default_toml_path)); // merge default into data struct @@ -59,6 +61,7 @@ pub fn start( // ui.begin(format!("Importing user.toml: {}", &user_toml_path)); let user_toml = match user_toml_path { Some(path) => { + // print helper message, maybe only print if '--verbose'? how? ui.begin(format!("Importing user.toml: {}", path.to_string()))?; read_to_string(path.to_string()) .expect(&format!("Something went wrong reading: {}", path.to_string())) @@ -69,13 +72,15 @@ pub fn start( merge(&mut data, toml_to_json(&user_toml)); // read mock data if provided - // ui.begin(format!("Importing override: {}", &mock_data_path)); let mock_data = match mock_data_path { Some(path) => { + // print helper message, maybe only print if '--verbose'? how? ui.begin(format!("Importing override file: {}", path.to_string()))?; read_to_string(path.to_string()) .expect(&format!("Something went wrong reading: {}", path.to_string())) }, + // return an empty json block if '--mock-data' isn't defined. + // this allows us to merge an empty JSON block None => "{}".to_string(), }; // merge mock data into data @@ -91,8 +96,10 @@ pub fn start( let rendered_template = renderer.render(&template_path, &data).ok().unwrap(); if print { - ui.warn(format!("Rendered template: {}", &template_path))?; + ui.br()?; + ui.warn(format!("###======== Rendered template: {}", &template_path))?; println!("{}", rendered_template); + ui.warn(format!("========### End rendered template: {}", &template_path))?; } // Render our template file @@ -129,6 +136,8 @@ fn merge(a: &mut Json, b: Json) { } } +// This is almost a dupe of the method in plan/init, except we don't care if the file exists and go +// ahead and overwite it. I feel like maybe a different name would be good? fn create_with_template(ui: &mut UI, location: &str, template: &str) -> Result<()> { let path = Path::new(&location); ui.status(Status::Creating, format!("file: {}", location))?; diff --git a/test/fixtures/render/README.md b/test/fixtures/render/README.md new file mode 100644 index 0000000000..20d9698dcc --- /dev/null +++ b/test/fixtures/render/README.md @@ -0,0 +1,87 @@ +# About + +These files are for testing `hab plan render` command. + +see `hab plan render --help` for full usage instructions. + +# Usage + +`cd` to `habitat/components/hab` + +Try: + + +``` +cargo run -- plan render ../../test/fixtures/render/consul/config/consul_config.json \ + --default-toml ../../test/fixtures/render/consul/default.toml \ + --user-toml ../../test/fixtures/render/consul/user.toml \ + --mock-data ../../test/fixtures/render/consul/override.json \ + --render-dir result/config \ + --print +``` + +``` +cargo run -- plan render ../../test/fixtures/render/consul/config/consul_config.json \ + --default-toml ../../test/fixtures/render/consul/default.toml \ + --render-dir result/config \ + --print +``` + +or + +``` +cargo run -- plan render ../../test/fixtures/render/consul/hooks/run \ + --default-toml ../../test/fixtures/render/consul/default.toml \ + --user-toml ../../test/fixtures/render/consul/user.toml \ + --mock-data ../../test/fixtures/render/consul/override.json \ + --render-dir result/hooks \ + --print +``` + +# Example output + +* `consul/config/basic_config.json` render: + +``` +{ + "datacenter": "IN_OVERRIDE_JSON", + "data_dir": "IN_DEFAULT_TOML", + "log_level": "IN_USER_TOML", + "bind_addr": "9.9.9.9", + "client_addr": "9.9.9.9", + "server": true, + "retry_join": [ + ], + "ports": { + "dns": 6666, + "http": 6667, + "https": 6668, + "serf_lan": 8888, + "serf_wan": 8302, + "server": 9999 + } +} +``` + +* `consul/hook/run` render: + +``` +#!/bin/sh + +exec 2>&1 + +SERVERMODE=true +export CONSUL_UI_LEGACY=false + +CONSUL_OPTS="-dev" +if [ "$SERVERMODE" = true ]; then + CONSUL_OPTS=" -ui -server -bootstrap-expect 3 -config-file=/basic_config.json" +fi + +exec consul agent ${CONSUL_OPTS} +``` + +# TODO: + +* Figure out how to load `svc` data for `eachAlive` helper +* figure out how to load `pkg.` data. e.g. for `{{pkg.svc_config_path}}` diff --git a/test/fixtures/render/config/consul_config.json b/test/fixtures/render/consul/config/consul_config.json similarity index 100% rename from test/fixtures/render/config/consul_config.json rename to test/fixtures/render/consul/config/consul_config.json diff --git a/test/fixtures/render/default.toml b/test/fixtures/render/consul/default.toml similarity index 100% rename from test/fixtures/render/default.toml rename to test/fixtures/render/consul/default.toml diff --git a/test/fixtures/render/hooks/run b/test/fixtures/render/consul/hooks/run similarity index 100% rename from test/fixtures/render/hooks/run rename to test/fixtures/render/consul/hooks/run diff --git a/test/fixtures/render/override.json b/test/fixtures/render/consul/override.json similarity index 100% rename from test/fixtures/render/override.json rename to test/fixtures/render/consul/override.json diff --git a/test/fixtures/render/user.toml b/test/fixtures/render/consul/user.toml similarity index 100% rename from test/fixtures/render/user.toml rename to test/fixtures/render/consul/user.toml From 312a53a6f09cbad680b40e934c25204b5d6786c4 Mon Sep 17 00:00:00 2001 From: qubitrenagade Date: Sun, 3 Feb 2019 01:58:09 -0700 Subject: [PATCH 08/39] add --no-render-dir flag to disable writing config to disk. --- components/hab/src/cli.rs | 1 + components/hab/src/command/plan/render.rs | 8 ++++++-- components/hab/src/main.rs | 2 ++ 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/components/hab/src/cli.rs b/components/hab/src/cli.rs index 2a5539c2e8..0df9848e87 100644 --- a/components/hab/src/cli.rs +++ b/components/hab/src/cli.rs @@ -589,6 +589,7 @@ pub fn get() -> App<'static, 'static> { (@arg MOCK_DATA: -m --("mock-data") +takes_value "Path to json file with mock data for template, defaults to none") (@arg PRINT: -p --("print") "Prints config to STDOUT") (@arg RENDER_DIR: -r --("render-dir") +takes_value "Path to render templates to, defaults to ./results/") + (@arg NO_WRITE_FILE: -n --("no-render") --("no-render-dir") "Don't write anything to disk, ignores --render-dir") ) ) (@subcommand ring => diff --git a/components/hab/src/command/plan/render.rs b/components/hab/src/command/plan/render.rs index e8a1f3417e..f3df0f356b 100644 --- a/components/hab/src/command/plan/render.rs +++ b/components/hab/src/command/plan/render.rs @@ -30,6 +30,7 @@ pub fn start( user_toml_path: Option, mock_data_path: Option, print: bool, + no_render_dir: bool, render_dir: String, ) -> Result<()> { // Strip the file name out of our passed template @@ -102,8 +103,11 @@ pub fn start( ui.warn(format!("========### End rendered template: {}", &template_path))?; } - // Render our template file - create_with_template(ui, &format!("{}/{}", render_dir, file_name), &rendered_template)?; + if !(no_render_dir) { + // Render our template file + create_with_template(ui, &format!("{}/{}", render_dir, file_name), &rendered_template)?; + } + ui.br()?; // not really sure this is correct... Ok(()) diff --git a/components/hab/src/main.rs b/components/hab/src/main.rs index 74d55c7951..3c01344d83 100644 --- a/components/hab/src/main.rs +++ b/components/hab/src/main.rs @@ -725,6 +725,7 @@ fn sub_plan_render(ui: &mut UI, m: &ArgMatches<'_>) -> Result<()> { }; let print = m.is_present("PRINT"); + let no_render_dir = m.is_present("NO_WRITE_FILE"); let render_dir = match m.value_of("RENDER_DIR") { Some(name) => name.to_string(), @@ -738,6 +739,7 @@ fn sub_plan_render(ui: &mut UI, m: &ArgMatches<'_>) -> Result<()> { user_toml_path, mock_data_path, print, + no_render_dir, render_dir, ) } From 3fcd75ed859d18b8d7be5c265f3ac7508cad0cba Mon Sep 17 00:00:00 2001 From: qubitrenagade Date: Sun, 3 Feb 2019 07:27:58 -0700 Subject: [PATCH 09/39] fix typo of 'active' to 'alive'... duh. (solve mocking 'svc.'). add '--quiet' flag to suppress log messages. Update README with commands to output files to homedir to avoid having to keep unstaging the results/ dir... Signed-off-by: qubitrenagade --- components/hab/src/cli.rs | 3 ++ components/hab/src/command/plan/render.rs | 51 ++++++++++++++++------- components/hab/src/main.rs | 2 + test/fixtures/render/README.md | 15 ++++--- test/fixtures/render/consul/override.json | 10 +++-- 5 files changed, 58 insertions(+), 23 deletions(-) diff --git a/components/hab/src/cli.rs b/components/hab/src/cli.rs index 0df9848e87..b9dbd4aad1 100644 --- a/components/hab/src/cli.rs +++ b/components/hab/src/cli.rs @@ -589,7 +589,10 @@ pub fn get() -> App<'static, 'static> { (@arg MOCK_DATA: -m --("mock-data") +takes_value "Path to json file with mock data for template, defaults to none") (@arg PRINT: -p --("print") "Prints config to STDOUT") (@arg RENDER_DIR: -r --("render-dir") +takes_value "Path to render templates to, defaults to ./results/") + // --no-render doesn't work... (@arg NO_WRITE_FILE: -n --("no-render") --("no-render-dir") "Don't write anything to disk, ignores --render-dir") + (@arg QUIET: -q --("no-verbose") --quiet + "Don't print any helper messages. When used with `--print` will only print config file") ) ) (@subcommand ring => diff --git a/components/hab/src/command/plan/render.rs b/components/hab/src/command/plan/render.rs index f3df0f356b..465422fefe 100644 --- a/components/hab/src/command/plan/render.rs +++ b/components/hab/src/command/plan/render.rs @@ -32,6 +32,7 @@ pub fn start( print: bool, no_render_dir: bool, render_dir: String, + quiet: bool, ) -> Result<()> { // Strip the file name out of our passed template let file_name = match Path::new(&template_path).file_name() { @@ -39,8 +40,10 @@ pub fn start( None => panic!(format!("Something went wrong getting filename of {}", &template_path)), }; - ui.begin(format!("Rendering: {} into: {}/ as: {}", template_path, render_dir, file_name))?; - ui.br()?; + if !(quiet) { + ui.begin(format!("Rendering: {} into: {}/ as: {}", template_path, render_dir, file_name))?; + ui.br()?; + } // read our template from file let template = read_to_string(&template_path) @@ -49,8 +52,11 @@ pub fn start( // create a "data" json struct let mut data: Json = serde_json::from_str("{}").unwrap(); - // import default.toml values, convert to JSON - ui.begin(format!("Importing default.toml: {}", &default_toml_path))?; + if !(quiet) { + // import default.toml values, convert to JSON + ui.begin(format!("Importing default.toml: {}", &default_toml_path))?; + } + // we should always have a default.toml, would be nice to "autodiscover" based on package name, // for now assume we're working in the plan dir if --default-toml not passed let default_toml = read_to_string(&default_toml_path) @@ -62,8 +68,10 @@ pub fn start( // ui.begin(format!("Importing user.toml: {}", &user_toml_path)); let user_toml = match user_toml_path { Some(path) => { - // print helper message, maybe only print if '--verbose'? how? - ui.begin(format!("Importing user.toml: {}", path.to_string()))?; + if !(quiet) { + // print helper message, maybe only print if '--verbose'? how? + ui.begin(format!("Importing user.toml: {}", path.to_string()))?; + } read_to_string(path.to_string()) .expect(&format!("Something went wrong reading: {}", path.to_string())) }, @@ -75,8 +83,10 @@ pub fn start( // read mock data if provided let mock_data = match mock_data_path { Some(path) => { - // print helper message, maybe only print if '--verbose'? how? - ui.begin(format!("Importing override file: {}", path.to_string()))?; + if !(quiet) { + // print helper message, maybe only print if '--verbose'? how? + ui.begin(format!("Importing override file: {}", path.to_string()))?; + } read_to_string(path.to_string()) .expect(&format!("Something went wrong reading: {}", path.to_string())) }, @@ -97,18 +107,27 @@ pub fn start( let rendered_template = renderer.render(&template_path, &data).ok().unwrap(); if print { - ui.br()?; - ui.warn(format!("###======== Rendered template: {}", &template_path))?; + if !(quiet) { + ui.br()?; + ui.warn(format!("###======== Rendered template: {}", &template_path))?; + } + println!("{}", rendered_template); - ui.warn(format!("========### End rendered template: {}", &template_path))?; + + if !(quiet) { + ui.warn(format!("========### End rendered template: {}", &template_path))?; + } } + // if not no render dir (aka "unless no_render_dir == true") if !(no_render_dir) { // Render our template file - create_with_template(ui, &format!("{}/{}", render_dir, file_name), &rendered_template)?; + create_with_template(ui, &format!("{}/{}", render_dir, file_name), &rendered_template, quiet)?; } - ui.br()?; + if !(quiet) { + ui.br()?; + } // not really sure this is correct... Ok(()) } @@ -142,9 +161,11 @@ fn merge(a: &mut Json, b: Json) { // This is almost a dupe of the method in plan/init, except we don't care if the file exists and go // ahead and overwite it. I feel like maybe a different name would be good? -fn create_with_template(ui: &mut UI, location: &str, template: &str) -> Result<()> { +fn create_with_template(ui: &mut UI, location: &str, template: &str, quiet: bool) -> Result<()> { let path = Path::new(&location); - ui.status(Status::Creating, format!("file: {}", location))?; + if !(quiet) { + ui.status(Status::Creating, format!("file: {}", location))?; + } // If the directory doesn't exist we need to make it. if let Some(directory) = path.parent() { create_dir_all(directory)?; diff --git a/components/hab/src/main.rs b/components/hab/src/main.rs index 3c01344d83..fd7944e688 100644 --- a/components/hab/src/main.rs +++ b/components/hab/src/main.rs @@ -726,6 +726,7 @@ fn sub_plan_render(ui: &mut UI, m: &ArgMatches<'_>) -> Result<()> { let print = m.is_present("PRINT"); let no_render_dir = m.is_present("NO_WRITE_FILE"); + let quiet = m.is_present("QUIET"); let render_dir = match m.value_of("RENDER_DIR") { Some(name) => name.to_string(), @@ -741,6 +742,7 @@ fn sub_plan_render(ui: &mut UI, m: &ArgMatches<'_>) -> Result<()> { print, no_render_dir, render_dir, + quiet, ) } diff --git a/test/fixtures/render/README.md b/test/fixtures/render/README.md index 20d9698dcc..e9a71daa9d 100644 --- a/test/fixtures/render/README.md +++ b/test/fixtures/render/README.md @@ -16,14 +16,14 @@ cargo run -- plan render ../../test/fixtures/render/consul/config/consul_config. --default-toml ../../test/fixtures/render/consul/default.toml \ --user-toml ../../test/fixtures/render/consul/user.toml \ --mock-data ../../test/fixtures/render/consul/override.json \ - --render-dir result/config \ + --render-dir ~/result/config \ --print ``` ``` cargo run -- plan render ../../test/fixtures/render/consul/config/consul_config.json \ --default-toml ../../test/fixtures/render/consul/default.toml \ - --render-dir result/config \ + --render-dir ~/result/config \ --print ``` @@ -34,7 +34,7 @@ cargo run -- plan render ../../test/fixtures/render/consul/hooks/run \ --default-toml ../../test/fixtures/render/consul/default.toml \ --user-toml ../../test/fixtures/render/consul/user.toml \ --mock-data ../../test/fixtures/render/consul/override.json \ - --render-dir result/hooks \ + --render-dir ~/result/hooks \ --print ``` @@ -83,5 +83,10 @@ exec consul agent ${CONSUL_OPTS} # TODO: -* Figure out how to load `svc` data for `eachAlive` helper -* figure out how to load `pkg.` data. e.g. for `{{pkg.svc_config_path}}` +* [x] ! ~~Figure out how to load `svc` data for `eachAlive` helper~~ +* [x] ! Figured out how to mock that data... helps to spell things right... ("alive" not "active") duh... +* [ ] ? figure out how to load `pkg.` data. e.g. for `{{pkg.svc_config_path}}` +* [x] ! figured out how to mock `pkg.` data, which I think "override.json" should override. +* [ ] ? figure out how to have multiple `--mock-data` params.. e.g.: `--mock-data test/day00.json`, `--mock-data test/day01-with-failed-member.json` +* ~~[ ]~~ ~~I want to make it `ersatz_data` instead of `mock_data`.~~ that's dumb. + diff --git a/test/fixtures/render/consul/override.json b/test/fixtures/render/consul/override.json index 4d6b9bdcd1..df76993495 100644 --- a/test/fixtures/render/consul/override.json +++ b/test/fixtures/render/consul/override.json @@ -1,5 +1,6 @@ { "cfg": { + "website": false, "server": { "datacenter": "IN_OVERRIDE_JSON" }, @@ -14,9 +15,12 @@ }, "svc": { "members": [ - { "active": true, "sys": { "ip": "1.1.1.1" }}, - { "properties": { "active": true}, "sys": { "ip": "2.2.2.2" }}, - { "sys": { "ip": "3.3.3.3" }} + { "alive": true, "sys": { "ip": "1.1.1.1" }}, + { "alive": true, "sys": { "ip": "2.2.2.2" }}, + { "alive": true, "sys": { "ip": "3.3.3.3" }} ] + }, + "pkg": { + "svc_config_path": "/home/foo/bar" } } From 38d97ffb6896ab99bfc308e54caad3639932d373 Mon Sep 17 00:00:00 2001 From: baumanj Date: Mon, 18 Feb 2019 19:46:33 -0700 Subject: [PATCH 10/39] Update components/hab/src/cli.rs make value validator. Co-Authored-By: qubitrenegade --- components/hab/src/cli.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/hab/src/cli.rs b/components/hab/src/cli.rs index b9dbd4aad1..352451cbce 100644 --- a/components/hab/src/cli.rs +++ b/components/hab/src/cli.rs @@ -583,7 +583,7 @@ pub fn get() -> App<'static, 'static> { (@subcommand render => (about: "Renders plan config files") (aliases: &["r", "re", "ren", "rend", "rende"]) - (@arg TEMPLATE_PATH: +required +takes_value "Path to config to render") + (@arg TEMPLATE_PATH: +required {file_exists} "Path to config to render") (@arg DEFAULT_TOML: -d --("default-toml") +takes_value "Path to default.toml, defaults to ./default.toml") (@arg USER_TOML: -u --("user-toml") +takes_value "Path to user.toml, defaults to none") (@arg MOCK_DATA: -m --("mock-data") +takes_value "Path to json file with mock data for template, defaults to none") From 79acb382652f6f55a587f68a7b2dec1f856f5365 Mon Sep 17 00:00:00 2001 From: baumanj Date: Mon, 18 Feb 2019 19:58:37 -0700 Subject: [PATCH 11/39] Update components/hab/src/command/plan/render.rs Co-Authored-By: qubitrenegade --- components/hab/src/command/plan/render.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/hab/src/command/plan/render.rs b/components/hab/src/command/plan/render.rs index 465422fefe..90fb52a547 100644 --- a/components/hab/src/command/plan/render.rs +++ b/components/hab/src/command/plan/render.rs @@ -122,7 +122,7 @@ pub fn start( // if not no render dir (aka "unless no_render_dir == true") if !(no_render_dir) { // Render our template file - create_with_template(ui, &format!("{}/{}", render_dir, file_name), &rendered_template, quiet)?; + create_with_template(ui, &Path::new(render_dir).join(file_name), &rendered_template, quiet)?; } if !(quiet) { From 233f3e4ff94e75f54b434b1cf060d32edb08a30a Mon Sep 17 00:00:00 2001 From: baumanj Date: Mon, 18 Feb 2019 20:29:28 -0700 Subject: [PATCH 12/39] Update components/hab/src/cli.rs Specify default value for `--default-toml` Co-Authored-By: qubitrenegade --- components/hab/src/cli.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/hab/src/cli.rs b/components/hab/src/cli.rs index 352451cbce..dbee36308f 100644 --- a/components/hab/src/cli.rs +++ b/components/hab/src/cli.rs @@ -584,7 +584,7 @@ pub fn get() -> App<'static, 'static> { (about: "Renders plan config files") (aliases: &["r", "re", "ren", "rend", "rende"]) (@arg TEMPLATE_PATH: +required {file_exists} "Path to config to render") - (@arg DEFAULT_TOML: -d --("default-toml") +takes_value "Path to default.toml, defaults to ./default.toml") + (@arg DEFAULT_TOML: -d --("default-toml") +takes_value default_value("./default.toml") "Path to default.toml") (@arg USER_TOML: -u --("user-toml") +takes_value "Path to user.toml, defaults to none") (@arg MOCK_DATA: -m --("mock-data") +takes_value "Path to json file with mock data for template, defaults to none") (@arg PRINT: -p --("print") "Prints config to STDOUT") From d28e9300459003a97896d29945a7d6d3e13d8d8f Mon Sep 17 00:00:00 2001 From: qubitrenagade Date: Sat, 23 Feb 2019 18:09:36 -0700 Subject: [PATCH 13/39] revert changes to support/linux/install_dev_9_linux.sh --- components/hab/src/cli.rs | 3 +-- support/linux/install_dev_9_linux.sh | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/components/hab/src/cli.rs b/components/hab/src/cli.rs index dbee36308f..5a3b100fb8 100644 --- a/components/hab/src/cli.rs +++ b/components/hab/src/cli.rs @@ -589,8 +589,7 @@ pub fn get() -> App<'static, 'static> { (@arg MOCK_DATA: -m --("mock-data") +takes_value "Path to json file with mock data for template, defaults to none") (@arg PRINT: -p --("print") "Prints config to STDOUT") (@arg RENDER_DIR: -r --("render-dir") +takes_value "Path to render templates to, defaults to ./results/") - // --no-render doesn't work... - (@arg NO_WRITE_FILE: -n --("no-render") --("no-render-dir") "Don't write anything to disk, ignores --render-dir") + (@arg NO_WRITE_FILE: -n --("no-render") "Don't write anything to disk, ignores --render-dir") (@arg QUIET: -q --("no-verbose") --quiet "Don't print any helper messages. When used with `--print` will only print config file") ) diff --git a/support/linux/install_dev_9_linux.sh b/support/linux/install_dev_9_linux.sh index 01a98b28a6..9438736707 100755 --- a/support/linux/install_dev_9_linux.sh +++ b/support/linux/install_dev_9_linux.sh @@ -43,6 +43,6 @@ else sudo -E addgroup --system hab || true fi -sudo bash /tmp/install.sh +sudo sh /tmp/install.sh sudo hab install core/busybox-static core/hab-studio sudo rm -f /tmp/install.sh From ea3a6c9a0b13d9c9c44428b1d0bfa701fdc7d962 Mon Sep 17 00:00:00 2001 From: qubitrenagade Date: Sat, 23 Feb 2019 18:51:38 -0700 Subject: [PATCH 14/39] Apply PathBuf recommendations instead of treating paths as strings --- components/hab/src/command/plan/render.rs | 49 +++++++++++------------ components/hab/src/main.rs | 14 +++---- 2 files changed, 31 insertions(+), 32 deletions(-) diff --git a/components/hab/src/command/plan/render.rs b/components/hab/src/command/plan/render.rs index 90fb52a547..f3abbbcc64 100644 --- a/components/hab/src/command/plan/render.rs +++ b/components/hab/src/command/plan/render.rs @@ -16,7 +16,7 @@ use std::fs::create_dir_all; use std::fs::{File, read_to_string}; use std::io::{Write}; use std::path::Path; -use serde_json::{self, Value as Json}; +use serde_json::{self, json, Value as Json}; use toml::Value; use crate::common::templating::TemplateRenderer; @@ -25,55 +25,54 @@ use crate::error::Result; pub fn start( ui: &mut UI, - template_path: String, - default_toml_path: String, - user_toml_path: Option, - mock_data_path: Option, + template_path: &Path, + default_toml_path: &Path, + user_toml_path: Option<&Path>, + mock_data_path: Option<&Path>, print: bool, no_render_dir: bool, - render_dir: String, + render_dir: &Path, quiet: bool, ) -> Result<()> { // Strip the file name out of our passed template let file_name = match Path::new(&template_path).file_name() { Some(name) => name.to_str().clone().unwrap(), - None => panic!(format!("Something went wrong getting filename of {}", &template_path)), + None => panic!(format!("Something went wrong getting filename of {:?}", &template_path)), }; if !(quiet) { - ui.begin(format!("Rendering: {} into: {}/ as: {}", template_path, render_dir, file_name))?; + ui.begin(format!("Rendering: {:?} into: {:?} as: {:?}", template_path, render_dir, file_name))?; ui.br()?; } // read our template from file let template = read_to_string(&template_path) - .expect(&format!("something went wrong reading: {}", template_path)); + .expect(&format!("something went wrong reading: {:?}", template_path)); // create a "data" json struct - let mut data: Json = serde_json::from_str("{}").unwrap(); + let mut data = json!({}); if !(quiet) { // import default.toml values, convert to JSON - ui.begin(format!("Importing default.toml: {}", &default_toml_path))?; + ui.begin(format!("Importing default.toml: {:?}", &default_toml_path))?; } // we should always have a default.toml, would be nice to "autodiscover" based on package name, // for now assume we're working in the plan dir if --default-toml not passed let default_toml = read_to_string(&default_toml_path) - .expect(&format!("Something went wrong reading: {}", &default_toml_path)); + .expect(&format!("Something went wrong reading: {:?}", &default_toml_path)); // merge default into data struct merge(&mut data, toml_to_json(&default_toml)); // import default.toml values, convert to JSON - // ui.begin(format!("Importing user.toml: {}", &user_toml_path)); let user_toml = match user_toml_path { Some(path) => { if !(quiet) { // print helper message, maybe only print if '--verbose'? how? - ui.begin(format!("Importing user.toml: {}", path.to_string()))?; + ui.begin(format!("Importing user.toml: {:?}", path))?; } - read_to_string(path.to_string()) - .expect(&format!("Something went wrong reading: {}", path.to_string())) + read_to_string(path) + .expect(&format!("Something went wrong reading: {:?}", path)) }, None => "".to_string(), }; @@ -85,10 +84,10 @@ pub fn start( Some(path) => { if !(quiet) { // print helper message, maybe only print if '--verbose'? how? - ui.begin(format!("Importing override file: {}", path.to_string()))?; + ui.begin(format!("Importing override file: {:?}", path))?; } - read_to_string(path.to_string()) - .expect(&format!("Something went wrong reading: {}", path.to_string())) + read_to_string(path) + .expect(&format!("Something went wrong reading: {:?}", path)) }, // return an empty json block if '--mock-data' isn't defined. // this allows us to merge an empty JSON block @@ -101,21 +100,21 @@ pub fn start( let mut renderer = TemplateRenderer::new(); // register our template renderer - .register_template_string(&template_path, &template) + .register_template_string(&template, &template) .expect("Could not register template content"); // render our JSON override in our template. - let rendered_template = renderer.render(&template_path, &data).ok().unwrap(); + let rendered_template = renderer.render(&template, &data).ok().unwrap(); if print { if !(quiet) { ui.br()?; - ui.warn(format!("###======== Rendered template: {}", &template_path))?; + ui.warn(format!("###======== Rendered template: {:?}", &template_path))?; } println!("{}", rendered_template); if !(quiet) { - ui.warn(format!("========### End rendered template: {}", &template_path))?; + ui.warn(format!("========### End rendered template: {:?}", &template_path))?; } } @@ -161,10 +160,10 @@ fn merge(a: &mut Json, b: Json) { // This is almost a dupe of the method in plan/init, except we don't care if the file exists and go // ahead and overwite it. I feel like maybe a different name would be good? -fn create_with_template(ui: &mut UI, location: &str, template: &str, quiet: bool) -> Result<()> { +fn create_with_template(ui: &mut UI, location: &std::path::PathBuf, template: &str, quiet: bool) -> Result<()> { let path = Path::new(&location); if !(quiet) { - ui.status(Status::Creating, format!("file: {}", location))?; + ui.status(Status::Creating, format!("file: {:?}", location))?; } // If the directory doesn't exist we need to make it. if let Some(directory) = path.parent() { diff --git a/components/hab/src/main.rs b/components/hab/src/main.rs index fd7944e688..ecefdbfe09 100644 --- a/components/hab/src/main.rs +++ b/components/hab/src/main.rs @@ -705,22 +705,22 @@ fn sub_plan_init(ui: &mut UI, m: &ArgMatches<'_>) -> Result<()> { fn sub_plan_render(ui: &mut UI, m: &ArgMatches<'_>) -> Result<()> { let template_path = match m.value_of("TEMPLATE_PATH") { - Some(o) => o.to_string(), + Some(o) => Path::new(o), None => return Err(Error::CryptoCLI("No config to render specified".to_string())), }; let default_toml_path = match m.value_of("DEFAULT_TOML") { - Some(o) => o.to_string(), - None => "./default.toml".to_string(), + Some(o) => Path::new(o), + None => Path::new("./default.toml") }; let user_toml_path = match m.value_of("USER_TOML") { - Some(o) => Some(o.to_string()), + Some(o) => Some(Path::new(o)), None => None }; let mock_data_path = match m.value_of("MOCK_DATA") { - Some(o) => Some(o.to_string()), + Some(o) => Some(Path::new(o)), None => None }; @@ -729,8 +729,8 @@ fn sub_plan_render(ui: &mut UI, m: &ArgMatches<'_>) -> Result<()> { let quiet = m.is_present("QUIET"); let render_dir = match m.value_of("RENDER_DIR") { - Some(name) => name.to_string(), - None => "result".into(), + Some(name) => Path::new(name), + None => Path::new("result"), }; command::plan::render::start( From cd7b7126bb987255c34980dfef676ed1fdcdbf58 Mon Sep 17 00:00:00 2001 From: qubitrenagade Date: Sat, 23 Feb 2019 19:01:19 -0700 Subject: [PATCH 15/39] Fix read_to_string to propagate error back up stack instead of panicing Signed-off-by: qubitrenagade --- components/hab/src/command/plan/render.rs | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/components/hab/src/command/plan/render.rs b/components/hab/src/command/plan/render.rs index f3abbbcc64..e870c702f7 100644 --- a/components/hab/src/command/plan/render.rs +++ b/components/hab/src/command/plan/render.rs @@ -46,8 +46,7 @@ pub fn start( } // read our template from file - let template = read_to_string(&template_path) - .expect(&format!("something went wrong reading: {:?}", template_path)); + let template = read_to_string(&template_path)?; // create a "data" json struct let mut data = json!({}); @@ -59,8 +58,8 @@ pub fn start( // we should always have a default.toml, would be nice to "autodiscover" based on package name, // for now assume we're working in the plan dir if --default-toml not passed - let default_toml = read_to_string(&default_toml_path) - .expect(&format!("Something went wrong reading: {:?}", &default_toml_path)); + let default_toml = read_to_string(&default_toml_path)?; + // merge default into data struct merge(&mut data, toml_to_json(&default_toml)); @@ -71,8 +70,7 @@ pub fn start( // print helper message, maybe only print if '--verbose'? how? ui.begin(format!("Importing user.toml: {:?}", path))?; } - read_to_string(path) - .expect(&format!("Something went wrong reading: {:?}", path)) + read_to_string(path)? }, None => "".to_string(), }; @@ -86,8 +84,7 @@ pub fn start( // print helper message, maybe only print if '--verbose'? how? ui.begin(format!("Importing override file: {:?}", path))?; } - read_to_string(path) - .expect(&format!("Something went wrong reading: {:?}", path)) + read_to_string(path)? }, // return an empty json block if '--mock-data' isn't defined. // this allows us to merge an empty JSON block From 891a6a59bd846b4932650a1b1b33b99b4832f506 Mon Sep 17 00:00:00 2001 From: qubitrenagade Date: Sat, 23 Feb 2019 19:06:39 -0700 Subject: [PATCH 16/39] Fix copyright date, use String::New() Signed-off-by: qubitrenagade --- components/hab/src/command/plan/render.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/hab/src/command/plan/render.rs b/components/hab/src/command/plan/render.rs index e870c702f7..6b2e998ca7 100644 --- a/components/hab/src/command/plan/render.rs +++ b/components/hab/src/command/plan/render.rs @@ -1,4 +1,4 @@ -// Copyright (c) 2016 Chef Software Inc. and/or applicable contributors +// Copyright (c) 2019 Chef Software Inc. and/or applicable contributors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -72,7 +72,7 @@ pub fn start( } read_to_string(path)? }, - None => "".to_string(), + None => String::new(), }; // merge default into data struct merge(&mut data, toml_to_json(&user_toml)); From 1e1905f747a2aa572c952e15e43ef15d781c6dfe Mon Sep 17 00:00:00 2001 From: qubitrenagade Date: Sat, 23 Feb 2019 19:44:19 -0700 Subject: [PATCH 17/39] remove unneeded comments Signed-off-by: qubitrenagade --- components/hab/src/command/plan/render.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/components/hab/src/command/plan/render.rs b/components/hab/src/command/plan/render.rs index 6b2e998ca7..41b59d7362 100644 --- a/components/hab/src/command/plan/render.rs +++ b/components/hab/src/command/plan/render.rs @@ -129,11 +129,8 @@ pub fn start( } fn toml_to_json(cfg: &str) -> Json { - // parse TOML string to Value let toml_value = cfg.parse::().expect("Error parsing TOML"); - // convert toml to json string let toml_string = serde_json::to_string(&toml_value).expect("Error encoding JSON"); - // convert to Json::Value serde_json::from_str(&format!(r#"{{ "cfg": {} }}"#, &toml_string)).unwrap() } From 38e5446a8de2834114c3dea52531534be408a6da Mon Sep 17 00:00:00 2001 From: qubitrenagade Date: Sat, 23 Feb 2019 19:48:17 -0700 Subject: [PATCH 18/39] remove unneeded comments Signed-off-by: qubitrenagade --- components/hab/src/command/plan/render.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/components/hab/src/command/plan/render.rs b/components/hab/src/command/plan/render.rs index 41b59d7362..df81aa5e85 100644 --- a/components/hab/src/command/plan/render.rs +++ b/components/hab/src/command/plan/render.rs @@ -124,7 +124,6 @@ pub fn start( if !(quiet) { ui.br()?; } - // not really sure this is correct... Ok(()) } @@ -152,8 +151,6 @@ fn merge(a: &mut Json, b: Json) { } } -// This is almost a dupe of the method in plan/init, except we don't care if the file exists and go -// ahead and overwite it. I feel like maybe a different name would be good? fn create_with_template(ui: &mut UI, location: &std::path::PathBuf, template: &str, quiet: bool) -> Result<()> { let path = Path::new(&location); if !(quiet) { From ef787a8cb952d1bfea07203d41eace1936bd4f2e Mon Sep 17 00:00:00 2001 From: qubitrenagade Date: Sat, 23 Feb 2019 20:18:41 -0700 Subject: [PATCH 19/39] update create_with_template to not check if "render_dir" exists before attempting to create. This also resolves the need to "name.to_str().clone().unwrap()" the filename. --- components/hab/src/command/plan/render.rs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/components/hab/src/command/plan/render.rs b/components/hab/src/command/plan/render.rs index df81aa5e85..62c0ff6316 100644 --- a/components/hab/src/command/plan/render.rs +++ b/components/hab/src/command/plan/render.rs @@ -36,7 +36,7 @@ pub fn start( ) -> Result<()> { // Strip the file name out of our passed template let file_name = match Path::new(&template_path).file_name() { - Some(name) => name.to_str().clone().unwrap(), + Some(name) => Path::new(name), None => panic!(format!("Something went wrong getting filename of {:?}", &template_path)), }; @@ -118,7 +118,7 @@ pub fn start( // if not no render dir (aka "unless no_render_dir == true") if !(no_render_dir) { // Render our template file - create_with_template(ui, &Path::new(render_dir).join(file_name), &rendered_template, quiet)?; + create_with_template(ui, &render_dir, &file_name, &rendered_template, quiet)?; } if !(quiet) { @@ -151,15 +151,14 @@ fn merge(a: &mut Json, b: Json) { } } -fn create_with_template(ui: &mut UI, location: &std::path::PathBuf, template: &str, quiet: bool) -> Result<()> { - let path = Path::new(&location); +fn create_with_template(ui: &mut UI, render_dir: &std::path::Path, file_name: &std::path::Path, template: &str, quiet: bool) -> Result<()> { + let path = Path::new(&render_dir).join(&file_name); if !(quiet) { - ui.status(Status::Creating, format!("file: {:?}", location))?; - } - // If the directory doesn't exist we need to make it. - if let Some(directory) = path.parent() { - create_dir_all(directory)?; + ui.status(Status::Creating, format!("file: {:?}", path))?; } + + create_dir_all(render_dir)?; + // Write file to disk File::create(path).and_then(|mut file| file.write(template.as_bytes()))?; Ok(()) From 14b171b90885a8bad9459699afe2e9c3232b17c6 Mon Sep 17 00:00:00 2001 From: qubitrenagade Date: Sat, 23 Feb 2019 20:33:24 -0700 Subject: [PATCH 20/39] drop TODO from testing README --- test/fixtures/render/README.md | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/test/fixtures/render/README.md b/test/fixtures/render/README.md index e9a71daa9d..6561148a83 100644 --- a/test/fixtures/render/README.md +++ b/test/fixtures/render/README.md @@ -80,13 +80,3 @@ fi exec consul agent ${CONSUL_OPTS} ``` - -# TODO: - -* [x] ! ~~Figure out how to load `svc` data for `eachAlive` helper~~ -* [x] ! Figured out how to mock that data... helps to spell things right... ("alive" not "active") duh... -* [ ] ? figure out how to load `pkg.` data. e.g. for `{{pkg.svc_config_path}}` -* [x] ! figured out how to mock `pkg.` data, which I think "override.json" should override. -* [ ] ? figure out how to have multiple `--mock-data` params.. e.g.: `--mock-data test/day00.json`, `--mock-data test/day01-with-failed-member.json` -* ~~[ ]~~ ~~I want to make it `ersatz_data` instead of `mock_data`.~~ that's dumb. - From 80fe8bccb6af0bf96cbd938a8d53ad5960448064 Mon Sep 17 00:00:00 2001 From: qubitrenagade Date: Sat, 23 Feb 2019 20:35:29 -0700 Subject: [PATCH 21/39] use cargo run -p instead of CDing to the hab dir. --- test/fixtures/render/README.md | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/test/fixtures/render/README.md b/test/fixtures/render/README.md index 6561148a83..e9a587fe18 100644 --- a/test/fixtures/render/README.md +++ b/test/fixtures/render/README.md @@ -6,23 +6,21 @@ see `hab plan render --help` for full usage instructions. # Usage -`cd` to `habitat/components/hab` - Try: ``` -cargo run -- plan render ../../test/fixtures/render/consul/config/consul_config.json \ - --default-toml ../../test/fixtures/render/consul/default.toml \ - --user-toml ../../test/fixtures/render/consul/user.toml \ - --mock-data ../../test/fixtures/render/consul/override.json \ +cargo run -p hab plan render ./test/fixtures/render/consul/config/consul_config.json \ + --default-toml ./test/fixtures/render/consul/default.toml \ + --user-toml ./test/fixtures/render/consul/user.toml \ + --mock-data ./test/fixtures/render/consul/override.json \ --render-dir ~/result/config \ --print ``` ``` -cargo run -- plan render ../../test/fixtures/render/consul/config/consul_config.json \ - --default-toml ../../test/fixtures/render/consul/default.toml \ +cargo run -p hab plan render ./test/fixtures/render/consul/config/consul_config.json \ + --default-toml ./test/fixtures/render/consul/default.toml \ --render-dir ~/result/config \ --print ``` @@ -30,10 +28,10 @@ cargo run -- plan render ../../test/fixtures/render/consul/config/consul_config. or ``` -cargo run -- plan render ../../test/fixtures/render/consul/hooks/run \ - --default-toml ../../test/fixtures/render/consul/default.toml \ - --user-toml ../../test/fixtures/render/consul/user.toml \ - --mock-data ../../test/fixtures/render/consul/override.json \ +cargo run -p hab plan render ./test/fixtures/render/consul/hooks/run \ + --default-toml ./test/fixtures/render/consul/default.toml \ + --user-toml ./test/fixtures/render/consul/user.toml \ + --mock-data ./test/fixtures/render/consul/override.json \ --render-dir ~/result/hooks \ --print ``` From aeece6654660895220f30e2df0db3ec79a09fa6a Mon Sep 17 00:00:00 2001 From: qubitrenagade Date: Sat, 23 Feb 2019 21:00:26 -0700 Subject: [PATCH 22/39] no_render_dir to no_render Signed-off-by: qubitrenagade --- components/hab/src/command/plan/render.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/hab/src/command/plan/render.rs b/components/hab/src/command/plan/render.rs index 62c0ff6316..f427978300 100644 --- a/components/hab/src/command/plan/render.rs +++ b/components/hab/src/command/plan/render.rs @@ -30,7 +30,7 @@ pub fn start( user_toml_path: Option<&Path>, mock_data_path: Option<&Path>, print: bool, - no_render_dir: bool, + no_render: bool, render_dir: &Path, quiet: bool, ) -> Result<()> { @@ -115,8 +115,8 @@ pub fn start( } } - // if not no render dir (aka "unless no_render_dir == true") - if !(no_render_dir) { + // if not no render dir (aka "unless no_render == true") + if !(no_render) { // Render our template file create_with_template(ui, &render_dir, &file_name, &rendered_template, quiet)?; } From ec8cb3a6a30b24c1c49e5a86d79781928a8cae70 Mon Sep 17 00:00:00 2001 From: qubitrenagade Date: Sat, 23 Feb 2019 21:07:58 -0700 Subject: [PATCH 23/39] rustfmt fueled cleanup --- components/hab/src/command/plan/render.rs | 62 +++++++++++++++-------- components/hab/src/main.rs | 30 ++++++----- 2 files changed, 57 insertions(+), 35 deletions(-) diff --git a/components/hab/src/command/plan/render.rs b/components/hab/src/command/plan/render.rs index f427978300..9c48ab1e90 100644 --- a/components/hab/src/command/plan/render.rs +++ b/components/hab/src/command/plan/render.rs @@ -12,11 +12,11 @@ // See the License for the specific language governing permissions and // limitations under the License. +use serde_json::{self, json, Value as Json}; use std::fs::create_dir_all; -use std::fs::{File, read_to_string}; -use std::io::{Write}; +use std::fs::{read_to_string, File}; +use std::io::Write; use std::path::Path; -use serde_json::{self, json, Value as Json}; use toml::Value; use crate::common::templating::TemplateRenderer; @@ -37,12 +37,18 @@ pub fn start( // Strip the file name out of our passed template let file_name = match Path::new(&template_path).file_name() { Some(name) => Path::new(name), - None => panic!(format!("Something went wrong getting filename of {:?}", &template_path)), - }; + None => panic!(format!( + "Something went wrong getting filename of {:?}", + &template_path + )), + }; if !(quiet) { - ui.begin(format!("Rendering: {:?} into: {:?} as: {:?}", template_path, render_dir, file_name))?; - ui.br()?; + ui.begin(format!( + "Rendering: {:?} into: {:?} as: {:?}", + template_path, render_dir, file_name + ))?; + ui.br()?; } // read our template from file @@ -67,11 +73,11 @@ pub fn start( let user_toml = match user_toml_path { Some(path) => { if !(quiet) { - // print helper message, maybe only print if '--verbose'? how? - ui.begin(format!("Importing user.toml: {:?}", path))?; + // print helper message, maybe only print if '--verbose'? how? + ui.begin(format!("Importing user.toml: {:?}", path))?; } read_to_string(path)? - }, + } None => String::new(), }; // merge default into data struct @@ -85,7 +91,7 @@ pub fn start( ui.begin(format!("Importing override file: {:?}", path))?; } read_to_string(path)? - }, + } // return an empty json block if '--mock-data' isn't defined. // this allows us to merge an empty JSON block None => "{}".to_string(), @@ -95,34 +101,40 @@ pub fn start( // create a template renderer let mut renderer = TemplateRenderer::new(); - // register our template + // register our template renderer .register_template_string(&template, &template) .expect("Could not register template content"); // render our JSON override in our template. let rendered_template = renderer.render(&template, &data).ok().unwrap(); - + if print { if !(quiet) { - ui.br()?; - ui.warn(format!("###======== Rendered template: {:?}", &template_path))?; + ui.br()?; + ui.warn(format!( + "###======== Rendered template: {:?}", + &template_path + ))?; } println!("{}", rendered_template); if !(quiet) { - ui.warn(format!("========### End rendered template: {:?}", &template_path))?; + ui.warn(format!( + "========### End rendered template: {:?}", + &template_path + ))?; } } // if not no render dir (aka "unless no_render == true") if !(no_render) { - // Render our template file - create_with_template(ui, &render_dir, &file_name, &rendered_template, quiet)?; + // Render our template file + create_with_template(ui, &render_dir, &file_name, &rendered_template, quiet)?; } if !(quiet) { - ui.br()?; + ui.br()?; } Ok(()) } @@ -136,11 +148,11 @@ fn toml_to_json(cfg: &str) -> Json { // merge two Json structs fn merge(a: &mut Json, b: Json) { match (a, b) { - // not sure I understand this... + // not sure I understand this... (a @ &mut Json::Object(_), Json::Object(b)) => { // not sure I understand why we unwrap this let a = a.as_object_mut().unwrap(); - // Iterate through key/values in Json object b, + // Iterate through key/values in Json object b, // merge with Json object b for (k, v) in b { merge(a.entry(k).or_insert(Json::Null), v); @@ -151,7 +163,13 @@ fn merge(a: &mut Json, b: Json) { } } -fn create_with_template(ui: &mut UI, render_dir: &std::path::Path, file_name: &std::path::Path, template: &str, quiet: bool) -> Result<()> { +fn create_with_template( + ui: &mut UI, + render_dir: &std::path::Path, + file_name: &std::path::Path, + template: &str, + quiet: bool, +) -> Result<()> { let path = Path::new(&render_dir).join(&file_name); if !(quiet) { ui.status(Status::Creating, format!("file: {:?}", path))?; diff --git a/components/hab/src/main.rs b/components/hab/src/main.rs index ecefdbfe09..920ad46251 100644 --- a/components/hab/src/main.rs +++ b/components/hab/src/main.rs @@ -706,22 +706,26 @@ fn sub_plan_init(ui: &mut UI, m: &ArgMatches<'_>) -> Result<()> { fn sub_plan_render(ui: &mut UI, m: &ArgMatches<'_>) -> Result<()> { let template_path = match m.value_of("TEMPLATE_PATH") { Some(o) => Path::new(o), - None => return Err(Error::CryptoCLI("No config to render specified".to_string())), + None => { + return Err(Error::CryptoCLI( + "No config to render specified".to_string(), + )); + } }; let default_toml_path = match m.value_of("DEFAULT_TOML") { Some(o) => Path::new(o), - None => Path::new("./default.toml") + None => Path::new("./default.toml"), }; let user_toml_path = match m.value_of("USER_TOML") { Some(o) => Some(Path::new(o)), - None => None + None => None, }; let mock_data_path = match m.value_of("MOCK_DATA") { Some(o) => Some(Path::new(o)), - None => None + None => None, }; let print = m.is_present("PRINT"); @@ -734,15 +738,15 @@ fn sub_plan_render(ui: &mut UI, m: &ArgMatches<'_>) -> Result<()> { }; command::plan::render::start( - ui, - template_path, - default_toml_path, - user_toml_path, - mock_data_path, - print, - no_render_dir, - render_dir, - quiet, + ui, + template_path, + default_toml_path, + user_toml_path, + mock_data_path, + print, + no_render_dir, + render_dir, + quiet, ) } From a4886f151a0203d994427b56384db32700e08d00 Mon Sep 17 00:00:00 2001 From: qubitrenagade Date: Sat, 23 Feb 2019 21:14:44 -0700 Subject: [PATCH 24/39] use @baumanj method of merging json structs. Signed-off-by: qubitrenagade --- components/hab/src/command/plan/render.rs | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/components/hab/src/command/plan/render.rs b/components/hab/src/command/plan/render.rs index 9c48ab1e90..42361c76e4 100644 --- a/components/hab/src/command/plan/render.rs +++ b/components/hab/src/command/plan/render.rs @@ -97,7 +97,7 @@ pub fn start( None => "{}".to_string(), }; // merge mock data into data - merge(&mut data, serde_json::from_str(&mock_data).unwrap()); + merge(&mut data, serde_json::from_str(&mock_data)?); // create a template renderer let mut renderer = TemplateRenderer::new(); @@ -147,20 +147,15 @@ fn toml_to_json(cfg: &str) -> Json { // merge two Json structs fn merge(a: &mut Json, b: Json) { - match (a, b) { - // not sure I understand this... - (a @ &mut Json::Object(_), Json::Object(b)) => { - // not sure I understand why we unwrap this - let a = a.as_object_mut().unwrap(); - // Iterate through key/values in Json object b, - // merge with Json object b - for (k, v) in b { - merge(a.entry(k).or_insert(Json::Null), v); + if let Json::Object(a_map) = a { + if let Json::Object(b_map) = b { + for (k, v) in b_map { + merge(a_map.entry(k).or_insert(Json::Null), v); } + return; } - // or this... - (a, b) => *a = b, } + *a = b; } fn create_with_template( From 9a5f35f749699020ab14d7aecdbd3694eecc96a0 Mon Sep 17 00:00:00 2001 From: qubitrenagade Date: Sun, 24 Feb 2019 00:02:49 -0700 Subject: [PATCH 25/39] rebase master. add back the unwrap for now... does #TODO: fix using '.unwrap()' work? Signed-off-by: qubitrenagade --- components/hab/src/command/plan/render.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/hab/src/command/plan/render.rs b/components/hab/src/command/plan/render.rs index 42361c76e4..d4c9ed026d 100644 --- a/components/hab/src/command/plan/render.rs +++ b/components/hab/src/command/plan/render.rs @@ -97,7 +97,7 @@ pub fn start( None => "{}".to_string(), }; // merge mock data into data - merge(&mut data, serde_json::from_str(&mock_data)?); + merge(&mut data, serde_json::from_str(&mock_data).unwrap()); // create a template renderer let mut renderer = TemplateRenderer::new(); From a1595010d1f73d65c693b53a41d57d46e9cb0b1d Mon Sep 17 00:00:00 2001 From: qubitrenagade Date: Sun, 24 Feb 2019 00:35:39 -0700 Subject: [PATCH 26/39] Add inspec file for consul_config.json Signed-off-by: qubitrenagade --- .gitignore | 1 + test/fixtures/render/consul/consul-config.inspec.rb | 13 +++++++++++++ 2 files changed, 14 insertions(+) create mode 100644 test/fixtures/render/consul/consul-config.inspec.rb diff --git a/.gitignore b/.gitignore index b4b613fa82..3972825143 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,7 @@ dump.rdb log/ results/ +result tags terraform.tfstate* test/builder-api/built/* diff --git a/test/fixtures/render/consul/consul-config.inspec.rb b/test/fixtures/render/consul/consul-config.inspec.rb new file mode 100644 index 0000000000..a98374a620 --- /dev/null +++ b/test/fixtures/render/consul/consul-config.inspec.rb @@ -0,0 +1,13 @@ +describe json('result/consul_config.json') do + its('datacenter') { should eq 'IN_OVERRIDE_JSON' } + its('data_dir') { should eq 'IN_DEFAULT_TOML' } + its('log_level') { should eq 'IN_USER_TOML' } + its('bind_addr') { should eq '9.9.9.9' } + its('server') { should eq true } + + its(['retry_join', 0]) { should eq '1.1.1.1' } + its(['retry_join', 1]) { should eq '2.2.2.2' } + its(['retry_join', 2]) { should eq '3.3.3.3' } + its(['ports','dns']) { should eq 6666 } + its(['ports','server']) { should eq 9999 } +end From bff2b63d2b91d9a24bdd419b3be84d76cf377c11 Mon Sep 17 00:00:00 2001 From: qubitrenagade Date: Thu, 28 Feb 2019 18:06:59 -0700 Subject: [PATCH 27/39] return Result instead of Json --- components/hab/src/command/plan/render.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/components/hab/src/command/plan/render.rs b/components/hab/src/command/plan/render.rs index d4c9ed026d..d18bfb206a 100644 --- a/components/hab/src/command/plan/render.rs +++ b/components/hab/src/command/plan/render.rs @@ -67,7 +67,7 @@ pub fn start( let default_toml = read_to_string(&default_toml_path)?; // merge default into data struct - merge(&mut data, toml_to_json(&default_toml)); + merge(&mut data, toml_to_json(&default_toml)?); // import default.toml values, convert to JSON let user_toml = match user_toml_path { @@ -81,7 +81,7 @@ pub fn start( None => String::new(), }; // merge default into data struct - merge(&mut data, toml_to_json(&user_toml)); + merge(&mut data, toml_to_json(&user_toml)?); // read mock data if provided let mock_data = match mock_data_path { @@ -139,10 +139,11 @@ pub fn start( Ok(()) } -fn toml_to_json(cfg: &str) -> Json { +fn toml_to_json(cfg: &str) -> Result { let toml_value = cfg.parse::().expect("Error parsing TOML"); let toml_string = serde_json::to_string(&toml_value).expect("Error encoding JSON"); - serde_json::from_str(&format!(r#"{{ "cfg": {} }}"#, &toml_string)).unwrap() + let json = serde_json::from_str(&format!(r#"{{ "cfg": {} }}"#, &toml_string))?; + Ok(json) } // merge two Json structs From c960a8856230d88d51d8e4f81defcd6453c33934 Mon Sep 17 00:00:00 2001 From: qubitrenagade Date: Thu, 28 Feb 2019 18:13:35 -0700 Subject: [PATCH 28/39] First pass at adding Error type for serde_json::Error Signed-off-by: qubitrenagade --- components/hab/src/error.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/components/hab/src/error.rs b/components/hab/src/error.rs index 7af1cb5265..40967d444d 100644 --- a/components/hab/src/error.rs +++ b/components/hab/src/error.rs @@ -62,6 +62,7 @@ pub enum Error { JobGroupPromoteOrDemote(api_client::Error, bool /* promote */), JobGroupCancel(api_client::Error), JobGroupPromoteOrDemoteUnprocessable(bool /* promote */), + JsonErr(serde_json::Error), NameLookup, NetErr(net::NetErr), PackageArchiveMalformed(String), @@ -156,6 +157,7 @@ impl fmt::Display for Error { if promote { "promote" } else { "demote" }, e) } + Error::JsonErr(ref e) => e.to_string(), Error::JobGroupCancel(ref e) => format!("Failed to cancel job group: {:?}", e), Error::NameLookup => "Error resolving a name or IP address".to_string(), Error::NetErr(ref e) => e.to_string(), @@ -238,6 +240,7 @@ impl error::Error for Error { Error::ProvidesError(_) => { "Can't find a package that provides the given search parameter" } + Error::JsonErr(ref err) => err.description(), Error::RemoteSupResolutionError(_, ref err) => err.description(), Error::RootRequired => { "Root or administrator permissions required to complete operation" @@ -300,3 +303,9 @@ impl From for Error { impl From for Error { fn from(err: net::NetErr) -> Self { Error::NetErr(err) } } + +impl From for Error { + fn from(err: serde_json::Error) -> Self { + Error::JsonErr(err) + } +} From ff0e44f9b4b2f12be2a86f682173038a8146a085 Mon Sep 17 00:00:00 2001 From: qubitrenagade Date: Thu, 28 Feb 2019 18:33:39 -0700 Subject: [PATCH 29/39] Remove unwrap() and .expect(); propagate errors. Add broken test toml/json files. Signed-off-by: qubitrenagade --- components/hab/src/command/plan/render.rs | 8 +++--- test/fixtures/render/error/default.toml | 31 +++++++++++++++++++++++ test/fixtures/render/error/override.json | 26 +++++++++++++++++++ 3 files changed, 61 insertions(+), 4 deletions(-) create mode 100644 test/fixtures/render/error/default.toml create mode 100644 test/fixtures/render/error/override.json diff --git a/components/hab/src/command/plan/render.rs b/components/hab/src/command/plan/render.rs index d18bfb206a..4242499f18 100644 --- a/components/hab/src/command/plan/render.rs +++ b/components/hab/src/command/plan/render.rs @@ -97,7 +97,7 @@ pub fn start( None => "{}".to_string(), }; // merge mock data into data - merge(&mut data, serde_json::from_str(&mock_data).unwrap()); + merge(&mut data, serde_json::from_str(&mock_data)?); // create a template renderer let mut renderer = TemplateRenderer::new(); @@ -106,7 +106,7 @@ pub fn start( .register_template_string(&template, &template) .expect("Could not register template content"); // render our JSON override in our template. - let rendered_template = renderer.render(&template, &data).ok().unwrap(); + let rendered_template = renderer.render(&template, &data)?; if print { if !(quiet) { @@ -140,8 +140,8 @@ pub fn start( } fn toml_to_json(cfg: &str) -> Result { - let toml_value = cfg.parse::().expect("Error parsing TOML"); - let toml_string = serde_json::to_string(&toml_value).expect("Error encoding JSON"); + let toml_value = cfg.parse::()?; + let toml_string = serde_json::to_string(&toml_value)?; let json = serde_json::from_str(&format!(r#"{{ "cfg": {} }}"#, &toml_string))?; Ok(json) } diff --git a/test/fixtures/render/error/default.toml b/test/fixtures/render/error/default.toml new file mode 100644 index 0000000000..19e50fa74b --- /dev/null +++ b/test/fixtures/render/error/default.toml @@ -0,0 +1,31 @@ +# If you would like the web gui on the agent +website = true + +# The options for consul are available here +# https://www.consul.io/docs/agent/options.html +[[bootstrap] +expect = "3" + +[server] +data-dir = "IN_DEFAULT_TOML" +datacenter = "dc1" +loglevel = "INFO" +# Revert back to the Legacy UI +legacy_ui = false +# switch this to false you want to start in DEVMODE +# https://www.consul.io/docs/guides/bootstrapping.html +mode = true + +[ports] +# The DNS server, -1 to disable +dns = 8600 +# The HTTP API, -1 to disable +http = 8500 +# The HTTPS API, -1 to disable +https = -1 +# The Serf LAN port +serf_lan = 8301 +# The Serf WAN port +serf_wan = 8302 +# Server RPC address +server = 8300 diff --git a/test/fixtures/render/error/override.json b/test/fixtures/render/error/override.json new file mode 100644 index 0000000000..512e04a361 --- /dev/null +++ b/test/fixtures/render/error/override.json @@ -0,0 +1,26 @@ +{ + "cfg": { + "website": false + "server": { + "datacenter": "IN_OVERRIDE_JSON" + }, + "ports": { + "dns": 6666, + "http": 6667, + "https": 6668 + } + }, + "sys": { + "ip": "9.9.9.9" + }, + "svc": { + "members": [ + { "alive": true, "sys": { "ip": "1.1.1.1" }}, + { "alive": true, "sys": { "ip": "2.2.2.2" }}, + { "alive": true, "sys": { "ip": "3.3.3.3" }} + ] + }, + "pkg": { + "svc_config_path": "/home/foo/bar" + } +} From 60339a3f2711cc175f4e4b2b5eca63057cb6a4f3 Mon Sep 17 00:00:00 2001 From: qubitrenagade Date: Fri, 8 Mar 2019 18:52:11 -0700 Subject: [PATCH 30/39] re-revert changes to support/linux/install_dev_9_linux.sh Signed-off-by: qubitrenagade --- support/linux/install_dev_9_linux.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/support/linux/install_dev_9_linux.sh b/support/linux/install_dev_9_linux.sh index 9438736707..6ecd3156c5 100755 --- a/support/linux/install_dev_9_linux.sh +++ b/support/linux/install_dev_9_linux.sh @@ -45,4 +45,4 @@ fi sudo sh /tmp/install.sh sudo hab install core/busybox-static core/hab-studio -sudo rm -f /tmp/install.sh +sudo rm -rf /tmp/install.sh From 6508e13d66102f6f25ed139545010a38f28e9f4a Mon Sep 17 00:00:00 2001 From: qubitrenagade Date: Fri, 8 Mar 2019 19:11:28 -0700 Subject: [PATCH 31/39] apply shellcheck-and-rustfmt-fixes.patch.txt Signed-off-by: qubitrenagade --- components/hab/src/command/plan/render.rs | 86 +++++++++++------------ components/hab/src/error.rs | 4 +- components/hab/src/main.rs | 24 +++---- test/shellcheck.sh | 1 + 4 files changed, 52 insertions(+), 63 deletions(-) diff --git a/components/hab/src/command/plan/render.rs b/components/hab/src/command/plan/render.rs index 4242499f18..10d0eacf87 100644 --- a/components/hab/src/command/plan/render.rs +++ b/components/hab/src/command/plan/render.rs @@ -12,42 +12,44 @@ // See the License for the specific language governing permissions and // limitations under the License. -use serde_json::{self, json, Value as Json}; -use std::fs::create_dir_all; -use std::fs::{read_to_string, File}; -use std::io::Write; -use std::path::Path; +use serde_json::{self, + json, + Value as Json}; +use std::{fs::{create_dir_all, + read_to_string, + File}, + io::Write, + path::Path}; use toml::Value; -use crate::common::templating::TemplateRenderer; -use crate::common::ui::{Status, UIWriter, UI}; -use crate::error::Result; - -pub fn start( - ui: &mut UI, - template_path: &Path, - default_toml_path: &Path, - user_toml_path: Option<&Path>, - mock_data_path: Option<&Path>, - print: bool, - no_render: bool, - render_dir: &Path, - quiet: bool, -) -> Result<()> { +use crate::{common::{templating::TemplateRenderer, + ui::{Status, + UIWriter, + UI}}, + error::Result}; + +pub fn start(ui: &mut UI, + template_path: &Path, + default_toml_path: &Path, + user_toml_path: Option<&Path>, + mock_data_path: Option<&Path>, + print: bool, + no_render: bool, + render_dir: &Path, + quiet: bool) + -> Result<()> { // Strip the file name out of our passed template let file_name = match Path::new(&template_path).file_name() { Some(name) => Path::new(name), - None => panic!(format!( - "Something went wrong getting filename of {:?}", - &template_path - )), + None => { + panic!(format!("Something went wrong getting filename of {:?}", + &template_path)) + } }; if !(quiet) { - ui.begin(format!( - "Rendering: {:?} into: {:?} as: {:?}", - template_path, render_dir, file_name - ))?; + ui.begin(format!("Rendering: {:?} into: {:?} as: {:?}", + template_path, render_dir, file_name))?; ui.br()?; } @@ -102,28 +104,21 @@ pub fn start( // create a template renderer let mut renderer = TemplateRenderer::new(); // register our template - renderer - .register_template_string(&template, &template) - .expect("Could not register template content"); + renderer.register_template_string(&template, &template) + .expect("Could not register template content"); // render our JSON override in our template. let rendered_template = renderer.render(&template, &data)?; if print { if !(quiet) { ui.br()?; - ui.warn(format!( - "###======== Rendered template: {:?}", - &template_path - ))?; + ui.warn(format!("###======== Rendered template: {:?}", &template_path))?; } println!("{}", rendered_template); if !(quiet) { - ui.warn(format!( - "========### End rendered template: {:?}", - &template_path - ))?; + ui.warn(format!("========### End rendered template: {:?}", &template_path))?; } } @@ -159,13 +154,12 @@ fn merge(a: &mut Json, b: Json) { *a = b; } -fn create_with_template( - ui: &mut UI, - render_dir: &std::path::Path, - file_name: &std::path::Path, - template: &str, - quiet: bool, -) -> Result<()> { +fn create_with_template(ui: &mut UI, + render_dir: &std::path::Path, + file_name: &std::path::Path, + template: &str, + quiet: bool) + -> Result<()> { let path = Path::new(&render_dir).join(&file_name); if !(quiet) { ui.status(Status::Creating, format!("file: {:?}", path))?; diff --git a/components/hab/src/error.rs b/components/hab/src/error.rs index 40967d444d..43cdce1f10 100644 --- a/components/hab/src/error.rs +++ b/components/hab/src/error.rs @@ -305,7 +305,5 @@ impl From for Error { } impl From for Error { - fn from(err: serde_json::Error) -> Self { - Error::JsonErr(err) - } + fn from(err: serde_json::Error) -> Self { Error::JsonErr(err) } } diff --git a/components/hab/src/main.rs b/components/hab/src/main.rs index 920ad46251..e1ed32c5c7 100644 --- a/components/hab/src/main.rs +++ b/components/hab/src/main.rs @@ -707,9 +707,7 @@ fn sub_plan_render(ui: &mut UI, m: &ArgMatches<'_>) -> Result<()> { let template_path = match m.value_of("TEMPLATE_PATH") { Some(o) => Path::new(o), None => { - return Err(Error::CryptoCLI( - "No config to render specified".to_string(), - )); + return Err(Error::CryptoCLI("No config to render specified".to_string())); } }; @@ -737,17 +735,15 @@ fn sub_plan_render(ui: &mut UI, m: &ArgMatches<'_>) -> Result<()> { None => Path::new("result"), }; - command::plan::render::start( - ui, - template_path, - default_toml_path, - user_toml_path, - mock_data_path, - print, - no_render_dir, - render_dir, - quiet, - ) + command::plan::render::start(ui, + template_path, + default_toml_path, + user_toml_path, + mock_data_path, + print, + no_render_dir, + render_dir, + quiet) } fn sub_pkg_install(ui: &mut UI, m: &ArgMatches<'_>) -> Result<()> { diff --git a/test/shellcheck.sh b/test/shellcheck.sh index 8910c3ccb2..f3d87abc1f 100755 --- a/test/shellcheck.sh +++ b/test/shellcheck.sh @@ -32,6 +32,7 @@ find . -type f \ -and \! -path "./test/integration/test_helper/bats-assert/*" \ -and \! -path "./test/integration/test_helper/bats-file/*" \ -and \! -path "./test/integration/test_helper/bats-support/*" \ + -and \! -path "./test/fixtures/render/consul/hooks/run" \ -print \ | xargs shellcheck --external-sources --exclude=1090,1091,1117,2148,2034 From f7e7be7f30dce1e6e1f10d6876a1149965a8432d Mon Sep 17 00:00:00 2001 From: qubitrenagade Date: Fri, 8 Mar 2019 19:23:47 -0700 Subject: [PATCH 32/39] Fix use of no_render_dir Signed-off-by: qubitrenagade --- components/hab/src/command/plan/render.rs | 5 ++--- components/hab/src/main.rs | 4 ++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/components/hab/src/command/plan/render.rs b/components/hab/src/command/plan/render.rs index 10d0eacf87..7e77490caa 100644 --- a/components/hab/src/command/plan/render.rs +++ b/components/hab/src/command/plan/render.rs @@ -34,7 +34,7 @@ pub fn start(ui: &mut UI, user_toml_path: Option<&Path>, mock_data_path: Option<&Path>, print: bool, - no_render: bool, + render: bool, render_dir: &Path, quiet: bool) -> Result<()> { @@ -122,8 +122,7 @@ pub fn start(ui: &mut UI, } } - // if not no render dir (aka "unless no_render == true") - if !(no_render) { + if render { // Render our template file create_with_template(ui, &render_dir, &file_name, &rendered_template, quiet)?; } diff --git a/components/hab/src/main.rs b/components/hab/src/main.rs index e1ed32c5c7..219f7dba96 100644 --- a/components/hab/src/main.rs +++ b/components/hab/src/main.rs @@ -727,7 +727,7 @@ fn sub_plan_render(ui: &mut UI, m: &ArgMatches<'_>) -> Result<()> { }; let print = m.is_present("PRINT"); - let no_render_dir = m.is_present("NO_WRITE_FILE"); + let render = !m.is_present("NO_WRITE_FILE"); let quiet = m.is_present("QUIET"); let render_dir = match m.value_of("RENDER_DIR") { @@ -741,7 +741,7 @@ fn sub_plan_render(ui: &mut UI, m: &ArgMatches<'_>) -> Result<()> { user_toml_path, mock_data_path, print, - no_render_dir, + render, render_dir, quiet) } From 3b08980f52e729c7ce60920fc441c2ff64545b64 Mon Sep 17 00:00:00 2001 From: qubitrenagade Date: Sat, 9 Mar 2019 11:57:25 -0700 Subject: [PATCH 33/39] simplify parsing *_path variables Signed-off-by: qubitrenagade --- components/hab/src/cli.rs | 2 +- components/hab/src/main.rs | 27 +++++---------------------- 2 files changed, 6 insertions(+), 23 deletions(-) diff --git a/components/hab/src/cli.rs b/components/hab/src/cli.rs index 5a3b100fb8..55c0fde079 100644 --- a/components/hab/src/cli.rs +++ b/components/hab/src/cli.rs @@ -588,7 +588,7 @@ pub fn get() -> App<'static, 'static> { (@arg USER_TOML: -u --("user-toml") +takes_value "Path to user.toml, defaults to none") (@arg MOCK_DATA: -m --("mock-data") +takes_value "Path to json file with mock data for template, defaults to none") (@arg PRINT: -p --("print") "Prints config to STDOUT") - (@arg RENDER_DIR: -r --("render-dir") +takes_value "Path to render templates to, defaults to ./results/") + (@arg RENDER_DIR: -r --("render-dir") +takes_value default_value("./results") "Path to render templates") (@arg NO_WRITE_FILE: -n --("no-render") "Don't write anything to disk, ignores --render-dir") (@arg QUIET: -q --("no-verbose") --quiet "Don't print any helper messages. When used with `--print` will only print config file") diff --git a/components/hab/src/main.rs b/components/hab/src/main.rs index 219f7dba96..b1d2d8ef6b 100644 --- a/components/hab/src/main.rs +++ b/components/hab/src/main.rs @@ -704,36 +704,19 @@ fn sub_plan_init(ui: &mut UI, m: &ArgMatches<'_>) -> Result<()> { } fn sub_plan_render(ui: &mut UI, m: &ArgMatches<'_>) -> Result<()> { - let template_path = match m.value_of("TEMPLATE_PATH") { - Some(o) => Path::new(o), - None => { - return Err(Error::CryptoCLI("No config to render specified".to_string())); - } - }; + let template_path = Path::new(m.value_of("TEMPLATE_PATH").unwrap()); - let default_toml_path = match m.value_of("DEFAULT_TOML") { - Some(o) => Path::new(o), - None => Path::new("./default.toml"), - }; + let default_toml_path = Path::new(m.value_of("DEFAULT_TOML").unwrap()); - let user_toml_path = match m.value_of("USER_TOML") { - Some(o) => Some(Path::new(o)), - None => None, - }; + let user_toml_path = m.value_of("USER_TOML").map(Path::new); - let mock_data_path = match m.value_of("MOCK_DATA") { - Some(o) => Some(Path::new(o)), - None => None, - }; + let mock_data_path = m.value_of("MOCK_DATA").map(Path::new); let print = m.is_present("PRINT"); let render = !m.is_present("NO_WRITE_FILE"); let quiet = m.is_present("QUIET"); - let render_dir = match m.value_of("RENDER_DIR") { - Some(name) => Path::new(name), - None => Path::new("result"), - }; + let render_dir = Path::new(m.value_of("RENDER_DIR").unwrap()); command::plan::render::start(ui, template_path, From e7c43c5c8c409bf89e7d8d028575333179a1d933 Mon Sep 17 00:00:00 2001 From: qubitrenagade Date: Sat, 9 Mar 2019 12:04:54 -0700 Subject: [PATCH 34/39] !(quiet) to !quiet Signed-off-by: qubitrenagade --- components/hab/src/command/plan/render.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/components/hab/src/command/plan/render.rs b/components/hab/src/command/plan/render.rs index 7e77490caa..8eac9f6769 100644 --- a/components/hab/src/command/plan/render.rs +++ b/components/hab/src/command/plan/render.rs @@ -47,7 +47,7 @@ pub fn start(ui: &mut UI, } }; - if !(quiet) { + if !quiet { ui.begin(format!("Rendering: {:?} into: {:?} as: {:?}", template_path, render_dir, file_name))?; ui.br()?; @@ -59,7 +59,7 @@ pub fn start(ui: &mut UI, // create a "data" json struct let mut data = json!({}); - if !(quiet) { + if !quiet { // import default.toml values, convert to JSON ui.begin(format!("Importing default.toml: {:?}", &default_toml_path))?; } @@ -74,7 +74,7 @@ pub fn start(ui: &mut UI, // import default.toml values, convert to JSON let user_toml = match user_toml_path { Some(path) => { - if !(quiet) { + if !quiet { // print helper message, maybe only print if '--verbose'? how? ui.begin(format!("Importing user.toml: {:?}", path))?; } @@ -88,7 +88,7 @@ pub fn start(ui: &mut UI, // read mock data if provided let mock_data = match mock_data_path { Some(path) => { - if !(quiet) { + if !quiet { // print helper message, maybe only print if '--verbose'? how? ui.begin(format!("Importing override file: {:?}", path))?; } @@ -110,14 +110,14 @@ pub fn start(ui: &mut UI, let rendered_template = renderer.render(&template, &data)?; if print { - if !(quiet) { + if !quiet { ui.br()?; ui.warn(format!("###======== Rendered template: {:?}", &template_path))?; } println!("{}", rendered_template); - if !(quiet) { + if !quiet { ui.warn(format!("========### End rendered template: {:?}", &template_path))?; } } @@ -127,7 +127,7 @@ pub fn start(ui: &mut UI, create_with_template(ui, &render_dir, &file_name, &rendered_template, quiet)?; } - if !(quiet) { + if !quiet { ui.br()?; } Ok(()) @@ -160,7 +160,7 @@ fn create_with_template(ui: &mut UI, quiet: bool) -> Result<()> { let path = Path::new(&render_dir).join(&file_name); - if !(quiet) { + if !quiet { ui.status(Status::Creating, format!("file: {:?}", path))?; } From e1f94c9e2b33465ef25f01949df4937fc3d9be26 Mon Sep 17 00:00:00 2001 From: qubitrenagade Date: Sat, 9 Mar 2019 12:10:54 -0700 Subject: [PATCH 35/39] {:?} to {} Signed-off-by: qubitrenagade --- components/hab/src/command/plan/render.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/components/hab/src/command/plan/render.rs b/components/hab/src/command/plan/render.rs index 8eac9f6769..d8a6eae9a4 100644 --- a/components/hab/src/command/plan/render.rs +++ b/components/hab/src/command/plan/render.rs @@ -48,8 +48,8 @@ pub fn start(ui: &mut UI, }; if !quiet { - ui.begin(format!("Rendering: {:?} into: {:?} as: {:?}", - template_path, render_dir, file_name))?; + ui.begin(format!("Rendering: {} into: {} as: {}", + template_path.display(), render_dir.display(), file_name.display()))?; ui.br()?; } @@ -61,7 +61,7 @@ pub fn start(ui: &mut UI, if !quiet { // import default.toml values, convert to JSON - ui.begin(format!("Importing default.toml: {:?}", &default_toml_path))?; + ui.begin(format!("Importing default.toml: {}", &default_toml_path.display()))?; } // we should always have a default.toml, would be nice to "autodiscover" based on package name, @@ -76,7 +76,7 @@ pub fn start(ui: &mut UI, Some(path) => { if !quiet { // print helper message, maybe only print if '--verbose'? how? - ui.begin(format!("Importing user.toml: {:?}", path))?; + ui.begin(format!("Importing user.toml: {}", path.display()))?; } read_to_string(path)? } @@ -90,7 +90,7 @@ pub fn start(ui: &mut UI, Some(path) => { if !quiet { // print helper message, maybe only print if '--verbose'? how? - ui.begin(format!("Importing override file: {:?}", path))?; + ui.begin(format!("Importing override file: {}", path.display()))?; } read_to_string(path)? } @@ -112,13 +112,13 @@ pub fn start(ui: &mut UI, if print { if !quiet { ui.br()?; - ui.warn(format!("###======== Rendered template: {:?}", &template_path))?; + ui.warn(format!("###======== Rendered template: {}", &template_path.display()))?; } println!("{}", rendered_template); if !quiet { - ui.warn(format!("========### End rendered template: {:?}", &template_path))?; + ui.warn(format!("========### End rendered template: {}", &template_path.display()))?; } } @@ -161,7 +161,7 @@ fn create_with_template(ui: &mut UI, -> Result<()> { let path = Path::new(&render_dir).join(&file_name); if !quiet { - ui.status(Status::Creating, format!("file: {:?}", path))?; + ui.status(Status::Creating, format!("file: {}", path.display()))?; } create_dir_all(render_dir)?; From 874bee580cf9dadabf37eee439cca63601156394 Mon Sep 17 00:00:00 2001 From: qubitrenagade Date: Sat, 9 Mar 2019 12:26:50 -0700 Subject: [PATCH 36/39] simplify getting file_name Signed-off-by: qubitrenagade --- components/hab/src/command/plan/render.rs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/components/hab/src/command/plan/render.rs b/components/hab/src/command/plan/render.rs index d8a6eae9a4..02fb3d870a 100644 --- a/components/hab/src/command/plan/render.rs +++ b/components/hab/src/command/plan/render.rs @@ -39,13 +39,7 @@ pub fn start(ui: &mut UI, quiet: bool) -> Result<()> { // Strip the file name out of our passed template - let file_name = match Path::new(&template_path).file_name() { - Some(name) => Path::new(name), - None => { - panic!(format!("Something went wrong getting filename of {:?}", - &template_path)) - } - }; + let file_name = Path::new(template_path.file_name().expect("valid template file")); if !quiet { ui.begin(format!("Rendering: {} into: {} as: {}", From cbaa742b941571d5eade13f9fb8783099b010649 Mon Sep 17 00:00:00 2001 From: qubitrenagade Date: Sat, 9 Mar 2019 12:31:24 -0700 Subject: [PATCH 37/39] add broken template to test/fixtues and test/fixtures/render/error directory to shellcheck exclude --- test/fixtures/render/error/consul_config.json | 21 +++++++++++++++++++ test/shellcheck.sh | 1 + 2 files changed, 22 insertions(+) create mode 100644 test/fixtures/render/error/consul_config.json diff --git a/test/fixtures/render/error/consul_config.json b/test/fixtures/render/error/consul_config.json new file mode 100644 index 0000000000..71042ad7eb --- /dev/null +++ b/test/fixtures/render/error/consul_config.json @@ -0,0 +1,21 @@ +{ + "datacenter": "{{cfg.server.datacenter", + "data_dir": "{{cfg.server.data-dir}}", + "log_level": "{{cfg.server.loglevel}}", + "bind_addr": "{{sys.ip}}", + "client_addr": "{{sys.ip}}", + "server": {{cfg.server.mode}}, + "retry_join": [ + {{#eachAlive svc.members as |member| ~}} + "{{member.sys.ip}}" {{~#unless @last}},{{/unless}} + {{/eachAlive ~}} + ], + "ports": { + "dns": {{cfg.ports.dns}}, + "http": {{cfg.ports.http}}, + "https": {{cfg.ports.https}}, + "serf_lan": {{cfg.ports.serf_lan}}, + "serf_wan": {{cfg.ports.serf_wan}}, + "server": {{cfg.ports.server}} + } +} diff --git a/test/shellcheck.sh b/test/shellcheck.sh index f3d87abc1f..0b3295f88c 100755 --- a/test/shellcheck.sh +++ b/test/shellcheck.sh @@ -33,6 +33,7 @@ find . -type f \ -and \! -path "./test/integration/test_helper/bats-file/*" \ -and \! -path "./test/integration/test_helper/bats-support/*" \ -and \! -path "./test/fixtures/render/consul/hooks/run" \ + -and \! -path "./test/fixtures/render/error/*" \ -print \ | xargs shellcheck --external-sources --exclude=1090,1091,1117,2148,2034 From 0f3c654ebfd8f906a94537f867dff0f786ea1f0d Mon Sep 17 00:00:00 2001 From: qubitrenagade Date: Sat, 9 Mar 2019 12:37:22 -0700 Subject: [PATCH 38/39] rustfmt cleanup Signed-off-by: qubitrenagade --- components/hab/src/command/plan/render.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/components/hab/src/command/plan/render.rs b/components/hab/src/command/plan/render.rs index 02fb3d870a..e66c7fd147 100644 --- a/components/hab/src/command/plan/render.rs +++ b/components/hab/src/command/plan/render.rs @@ -43,7 +43,9 @@ pub fn start(ui: &mut UI, if !quiet { ui.begin(format!("Rendering: {} into: {} as: {}", - template_path.display(), render_dir.display(), file_name.display()))?; + template_path.display(), + render_dir.display(), + file_name.display()))?; ui.br()?; } @@ -106,13 +108,15 @@ pub fn start(ui: &mut UI, if print { if !quiet { ui.br()?; - ui.warn(format!("###======== Rendered template: {}", &template_path.display()))?; + ui.warn(format!("###======== Rendered template: {}", + &template_path.display()))?; } println!("{}", rendered_template); if !quiet { - ui.warn(format!("========### End rendered template: {}", &template_path.display()))?; + ui.warn(format!("========### End rendered template: {}", + &template_path.display()))?; } } From e3e7666a84c19e18969aa6702889fc65a0d43243 Mon Sep 17 00:00:00 2001 From: qubitrenagade Date: Sat, 9 Mar 2019 12:59:17 -0700 Subject: [PATCH 39/39] NO_WRITE_FILE to NO_RENDER Signed-off-by: qubitrenagade --- components/hab/src/cli.rs | 2 +- components/hab/src/main.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/components/hab/src/cli.rs b/components/hab/src/cli.rs index 55c0fde079..017a1f6a36 100644 --- a/components/hab/src/cli.rs +++ b/components/hab/src/cli.rs @@ -589,7 +589,7 @@ pub fn get() -> App<'static, 'static> { (@arg MOCK_DATA: -m --("mock-data") +takes_value "Path to json file with mock data for template, defaults to none") (@arg PRINT: -p --("print") "Prints config to STDOUT") (@arg RENDER_DIR: -r --("render-dir") +takes_value default_value("./results") "Path to render templates") - (@arg NO_WRITE_FILE: -n --("no-render") "Don't write anything to disk, ignores --render-dir") + (@arg NO_RENDER: -n --("no-render") "Don't write anything to disk, ignores --render-dir") (@arg QUIET: -q --("no-verbose") --quiet "Don't print any helper messages. When used with `--print` will only print config file") ) diff --git a/components/hab/src/main.rs b/components/hab/src/main.rs index b1d2d8ef6b..bf3301c442 100644 --- a/components/hab/src/main.rs +++ b/components/hab/src/main.rs @@ -713,7 +713,7 @@ fn sub_plan_render(ui: &mut UI, m: &ArgMatches<'_>) -> Result<()> { let mock_data_path = m.value_of("MOCK_DATA").map(Path::new); let print = m.is_present("PRINT"); - let render = !m.is_present("NO_WRITE_FILE"); + let render = !m.is_present("NO_RENDER"); let quiet = m.is_present("QUIET"); let render_dir = Path::new(m.value_of("RENDER_DIR").unwrap());