Skip to content
This repository has been archived by the owner on Jul 25, 2022. It is now read-only.

Commit

Permalink
Create an iml-config cli tool (#1994)
Browse files Browse the repository at this point in the history
* Create an iml-config cli tool

Create an iml-config cli tool that will be used to perform config
related tasks. In this patch, a drop-in will be added to nginx that will
load all iml environment variables. These environment variables will
then be used to generate the nginx config file from the chroma template
any time nginx is restarted. This will allow the template variables to
change in the nginx config based on environment variable overloading.

Signed-off-by: johnsonw <wjohnson@whamcloud.com>

* -cleanups

Signed-off-by: johnsonw <wjohnson@whamcloud.com>

* - remove nginx setup from service config

Signed-off-by: johnsonw <wjohnson@whamcloud.com>

* - set_nginx_config is being used by the services test so i'm adding this
back in, but i'm not calling if from the setup function in the service
config.

Signed-off-by: johnsonw <wjohnson@whamcloud.com>

* - Updates

Signed-off-by: johnsonw <wjohnson@whamcloud.com>

* - CR Changes

Signed-off-by: johnsonw <wjohnson@whamcloud.com>

* cleanups

Signed-off-by: johnsonw <wjohnson@whamcloud.com>

* Add failing test

Add a failing test case for when there is more than 1 var to be replaced on a line.

Also pass in a HashMap of vars instead of an fn to make testing different cases easier

* - Move nginx config command into existing iml-manager-cli crate and
create a separate binary.
- Fix failing test

Signed-off-by: johnsonw <wjohnson@whamcloud.com>

* - use iml_tracing

Signed-off-by: johnsonw <wjohnson@whamcloud.com>

* - Fix clippy errors

Signed-off-by: johnsonw <wjohnson@whamcloud.com>

* - Tweak the regex a bit

Signed-off-by: johnsonw <wjohnson@whamcloud.com>

* - Remove set_config_config from service_config.

Signed-off-by: johnsonw <wjohnson@whamcloud.com>

* - test1

Signed-off-by: johnsonw <wjohnson@whamcloud.com>

Co-authored-by: Joe Grund <jgrund@whamcloud.io>
  • Loading branch information
johnsonw and jgrund authored Jun 23, 2020
1 parent d245ebf commit 83d0656
Show file tree
Hide file tree
Showing 16 changed files with 652 additions and 40 deletions.
2 changes: 2 additions & 0 deletions .copr/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ srpm:
iml-sfa.service \
${TMPDIR}/release/rust-iml
cp ${TARGET}/release/iml ${TMPDIR}/release/rust-iml
cp ${TARGET}/release/iml-config ${TMPDIR}/release/rust-iml
tar -czvf ${TMPDIR}/_topdir/SOURCES/rust-iml.tar.gz -C ${TMPDIR}/release/rust-iml .
cp rust-iml.spec ${TMPDIR}/_topdir/SPECS/
rpmbuild -bs -D "_topdir ${TMPDIR}/_topdir" ${TMPDIR}/_topdir/SPECS/rust-iml.spec
Expand Down Expand Up @@ -96,6 +97,7 @@ iml-srpm: iml-deps substs
cp ${BUILDROOT}/python-iml-manager.spec ${TMPDIR}/_topdir/SPECS

cp -r ${BUILDROOT}/grafana ${TMPDIR}/configuration
cp -r ${BUILDROOT}/nginx ${TMPDIR}/configuration
cp ${BUILDROOT}/iml-*.service \
${BUILDROOT}/rabbitmq-env.conf \
${BUILDROOT}/rabbitmq-server-dropin.conf \
Expand Down
3 changes: 3 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

36 changes: 0 additions & 36 deletions chroma_core/lib/service_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -676,40 +676,6 @@ def _configure_firewall(self):
self.try_shell(["firewall-cmd", "--permanent", "--add-port={}/tcp".format(port)])
self.try_shell(["firewall-cmd", "--add-port={}/tcp".format(port)])

def set_nginx_config(self):
project_dir = os.path.dirname(os.path.realpath(settings.__file__))
conf_template = os.path.join(project_dir, "chroma-manager.conf.template")

nginx_settings = [
"REPO_PATH",
"HTTP_FRONTEND_PORT",
"HTTPS_FRONTEND_PORT",
"HTTP_AGENT_PROXY_PASS",
"HTTP_AGENT2_PROXY_PASS",
"HTTP_API_PROXY_PASS",
"IML_API_PROXY_PASS",
"WARP_DRIVE_PROXY_PASS",
"MAILBOX_PATH",
"MAILBOX_PROXY_PASS",
"SSL_PATH",
"DEVICE_AGGREGATOR_PORT",
"DEVICE_AGGREGATOR_PROXY_PASS",
"UPDATE_HANDLER_PROXY_PASS",
"GRAFANA_PORT",
"GRAFANA_PROXY_PASS",
"INFLUXDB_PROXY_PASS",
"TIMER_PROXY_PASS",
"INCLUDES",
]

with open(conf_template, "r") as f:
config = f.read()
for setting in nginx_settings:
config = config.replace("{{%s}}" % setting, str(getattr(settings, setting)))

with open("/etc/nginx/conf.d/chroma-manager.conf", "w") as f2:
f2.write(config)

def _register_profiles(self):
for x in glob.glob("/usr/share/chroma-manager/*.profile"):
print("Registering profile: {}".format(x))
Expand Down Expand Up @@ -793,8 +759,6 @@ def setup(self, username, password, ntp_server, check_db_space):
self._configure_selinux()
self._configure_firewall()

self.set_nginx_config()

self._setup_influxdb()

error = self._setup_database(check_db_space)
Expand Down
15 changes: 15 additions & 0 deletions chroma_core/management/commands/print-settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,23 @@ def handle(self, *args, **kwargs):
"WARP_DRIVE_PORT": settings.WARP_DRIVE_PORT,
"MAILBOX_PORT": settings.MAILBOX_PORT,
"DEVICE_AGGREGATOR_PORT": settings.DEVICE_AGGREGATOR_PORT,
"HTTP_FRONTEND_PORT": settings.HTTP_FRONTEND_PORT,
"HTTPS_FRONTEND_PORT": settings.HTTPS_FRONTEND_PORT,
"HTTP_AGENT_PROXY_PASS": settings.HTTP_AGENT_PROXY_PASS,
"HTTP_AGENT2_PORT": settings.HTTP_AGENT2_PORT,
"HTTP_AGENT2_PROXY_PASS": settings.HTTP_AGENT2_PROXY_PASS,
"HTTP_API_PROXY_PASS": settings.HTTP_API_PROXY_PASS,
"IML_API_PORT": settings.IML_API_PORT,
"IML_API_PROXY_PASS": settings.IML_API_PROXY_PASS,
"WARP_DRIVE_PROXY_PASS": settings.WARP_DRIVE_PROXY_PASS,
"MAILBOX_PROXY_PASS": settings.MAILBOX_PROXY_PASS,
"SSL_PATH": settings.SSL_PATH,
"DEVICE_AGGREGATOR_PROXY_PASS": settings.DEVICE_AGGREGATOR_PROXY_PASS,
"UPDATE_HANDLER_PROXY_PASS": settings.UPDATE_HANDLER_PROXY_PASS,
"GRAFANA_PORT": settings.GRAFANA_PORT,
"GRAFANA_PROXY_PASS": settings.GRAFANA_PROXY_PASS,
"INFLUXDB_PROXY_PASS": settings.INFLUXDB_PROXY_PASS,
"TIMER_PROXY_PASS": settings.TIMER_PROXY_PASS,
"ALLOW_ANONYMOUS_READ": json.dumps(settings.ALLOW_ANONYMOUS_READ),
"BUILD": settings.BUILD,
"IS_RELEASE": json.dumps(settings.IS_RELEASE),
Expand All @@ -53,6 +66,7 @@ def handle(self, *args, **kwargs):
"DB_NAME": DB.get("NAME"),
"DB_USER": DB.get("USER"),
"DB_PASSWORD": DB.get("PASSWORD"),
"REPO_PATH": settings.REPO_PATH,
"AMQP_BROKER_USER": settings.AMQP_BROKER_USER,
"AMQP_BROKER_PASSWORD": settings.AMQP_BROKER_PASSWORD,
"AMQP_BROKER_VHOST": settings.AMQP_BROKER_VHOST,
Expand All @@ -61,6 +75,7 @@ def handle(self, *args, **kwargs):
"AMQP_BROKER_URL": settings.BROKER_URL,
"BRANDING": settings.BRANDING,
"USE_STRATAGEM": settings.USE_STRATAGEM,
"INCLUDES": settings.INCLUDES,
}

if settings.EXA_VERSION:
Expand Down
11 changes: 10 additions & 1 deletion iml-manager-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,27 @@ iml-orm = { path = "../iml-orm", version = "0.3", features = ["postgres-interop"
iml-tracing = { version = "0.2", path="../iml-tracing"}
iml-wire-types = { path = "../iml-wire-types", version = "0.3" }
indicatif = "0.14"
lazy_static = "1.4"
number-formatter = { path = "../number-formatter", version = "0.1" }
prettytable-rs = "0.8"
regex = "1.3"
reqwest = { version = "0.10", features = ["default-tls", "json"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
serde_yaml = "0.8"
spinners = "1.2.0"
structopt = "0.3"
thiserror = "1.0"
tokio = { version = "0.2", features = ["macros", "io-std", "io-util"] }
tokio = { version = "0.2", features = ["macros", "io-std", "io-util", "fs"] }
tracing = "0.1"

[dev-dependencies]
insta = "0.16"

[[bin]]
name = "iml"
path = "src/main.rs"

[[bin]]
name = "iml-config"
path = "src/config-main.rs"
42 changes: 42 additions & 0 deletions iml-manager-cli/src/config-main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Copyright (c) 2020 DDN. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

use iml_manager_cli::{
display_utils::display_error,
nginx::{self, nginx_cli},
};
use std::process::exit;
use structopt::StructOpt;

#[derive(Debug, StructOpt)]
#[structopt(name = "iml-config", setting = structopt::clap::AppSettings::ColoredHelp)]
/// The IML Config CLI
pub enum App {
#[structopt(name = "nginx")]
/// Nginx config file generator
Nginx {
#[structopt(subcommand)]
command: nginx::NginxCommand,
},
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
iml_tracing::init();

let matches = App::from_args();

tracing::debug!("Matching args {:?}", matches);

let r = match matches {
App::Nginx { command } => nginx_cli(command).await,
};

if let Err(e) = r {
display_error(e);
exit(1);
}

Ok(())
}
2 changes: 2 additions & 0 deletions iml-manager-cli/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ pub enum ImlManagerCliError {
CombineEasyError(combine::stream::easy::Errors<char, &'static str, usize>),
DoesNotExist(&'static str),
FailedCommandError(Vec<Command>),
FromUtf8Error(#[from] std::string::FromUtf8Error),
ImlOrmError(#[from] iml_orm::ImlOrmError),
IntParseError(#[from] std::num::ParseIntError),
IoError(#[from] std::io::Error),
Expand Down Expand Up @@ -90,6 +91,7 @@ impl std::fmt::Display for ImlManagerCliError {

write!(f, "{}", failed_msg)
}
ImlManagerCliError::FromUtf8Error(ref err) => write!(f, "{}", err),
ImlManagerCliError::ImlOrmError(ref err) => write!(f, "{}", err),
ImlManagerCliError::IntParseError(ref err) => write!(f, "{}", err),
ImlManagerCliError::IoError(ref err) => write!(f, "{}", err),
Expand Down
1 change: 1 addition & 0 deletions iml-manager-cli/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ pub mod api_utils;
pub mod display_utils;
pub mod error;
pub mod filesystem;
pub mod nginx;
pub mod ostpool;
pub mod profile;
pub mod server;
Expand Down
136 changes: 136 additions & 0 deletions iml-manager-cli/src/nginx.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
// Copyright (c) 2020 DDN. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

use crate::error::ImlManagerCliError;
use console::Term;
use lazy_static::*;
use regex::{Captures, Regex};
use std::{collections::HashMap, env, str};
use structopt::StructOpt;
use tokio::fs;

#[derive(Debug, StructOpt)]
pub enum NginxCommand {
/// Generate Nginx conf
#[structopt(name = "generate-config")]
GenerateConfig {
/// Set the nginx config path
#[structopt(short = "p", long = "path")]
template_path: String,

#[structopt(short = "o", long = "output")]
output_path: Option<String>,
},
}

fn replace_template_variables(contents: &str, vars: HashMap<String, String>) -> String {
lazy_static! {
static ref RE: Regex = Regex::new(r"(\{\{\w+\}\})").unwrap();
}

let config: String = contents
.lines()
.map(|l| {
RE.replace_all(l, |caps: &Captures| {
let key = &caps[1].replace("{", "").replace("}", "");
let val = vars
.get(key)
.unwrap_or_else(|| panic!("{} variable not set", key));

caps[0].replace(&caps[1], &val)
})
.to_string()
})
.collect::<Vec<String>>()
.join("\n");

config
}

pub async fn nginx_cli(command: NginxCommand) -> Result<(), ImlManagerCliError> {
match command {
NginxCommand::GenerateConfig {
template_path,
output_path,
} => {
let nginx_template_bytes = fs::read(template_path).await?;
let nginx_template = String::from_utf8(nginx_template_bytes)?;

let vars: HashMap<String, String> = env::vars().collect();

let config = replace_template_variables(&nginx_template, vars);

if let Some(path) = output_path {
fs::write(path, config).await?;
} else {
let term = Term::stdout();

iml_tracing::tracing::debug!("Nginx Config: {}", config);

term.write_line(&config).unwrap();
}
}
};

Ok(())
}

#[cfg(test)]
mod tests {
use super::*;
use insta::*;
use std::collections::HashMap;

#[test]
fn test_replace_template_variables() {
let template: &[u8] = include_bytes!("../../chroma-manager.conf.template");

let vars: HashMap<String, String> = [
("REPO_PATH", "/var/lib/chroma/repo"),
("HTTP_FRONTEND_PORT", "80"),
("HTTPS_FRONTEND_PORT", "443"),
("HTTP_AGENT_PROXY_PASS", "http://127.0.0.1:8002"),
("HTTP_AGENT2_PROXY_PASS", "http://127.0.0.1:8003"),
("HTTP_API_PROXY_PASS", "http://127.0.0.1:8001"),
("IML_API_PROXY_PASS", "http://127.0.0.1:8004"),
("WARP_DRIVE_PROXY_PASS", "http://127.0.0.1:8890"),
("MAILBOX_PATH", "/var/spool/iml/mailbox"),
("MAILBOX_PROXY_PASS", "http://127.0.0.1:8891"),
("SSL_PATH", "/var/lib/chroma"),
("DEVICE_AGGREGATOR_PORT", "8008"),
("DEVICE_AGGREGATOR_PROXY_PASS", "http://127.0.0.1:8008"),
(
"UPDATE_HANDLER_PROXY_PASS",
"http://unix:/var/run/iml-update-handler.sock",
),
("GRAFANA_PORT", "3000"),
("GRAFANA_PROXY_PASS", "http://127.0.0.1:3000"),
("INFLUXDB_PROXY_PASS", "http://127.0.0.1:8086"),
("TIMER_PROXY_PASS", "http://127.0.0.1:8892"),
("INCLUDES", ""),
]
.iter()
.map(|(k, v)| (k.to_string(), v.to_string()))
.collect();

let config = replace_template_variables(
&str::from_utf8(template).expect("Couldn't parse template"),
vars,
);

assert_display_snapshot!(config);
}

#[test]
fn test_multiple_replacements() {
let vars: HashMap<String, String> = [("FOO", "foo"), ("BAR", "bar")]
.iter()
.map(|(k, v)| (k.to_string(), v.to_string()))
.collect();

let cfg = replace_template_variables("{{FOO}}/{{BAR}}", vars);

assert_eq!(cfg, "foo/bar");
}
}
Loading

0 comments on commit 83d0656

Please sign in to comment.