start on cli - generate core config

This commit is contained in:
beckerinj
2022-12-11 04:15:19 -05:00
parent e81b6a14de
commit daf06a33f8
12 changed files with 231 additions and 41 deletions

26
Cargo.lock generated
View File

@@ -47,9 +47,9 @@ dependencies = [
[[package]]
name = "async_timing_util"
version = "0.1.11"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "621343e4b8a4aed1ed909b273e2fcb1bba6e0b476ba5096c0c27117d86f29335"
checksum = "62c38326e21188f3b8ccf75b2de994d2ca9fca9fcbc84420fd24569cf9aeb4b2"
dependencies = [
"serde",
"serde_derive",
@@ -343,14 +343,6 @@ dependencies = [
"os_str_bytes",
]
[[package]]
name = "cli"
version = "0.1.0"
dependencies = [
"bollard",
"clap",
]
[[package]]
name = "core"
version = "0.1.0"
@@ -1264,6 +1256,20 @@ dependencies = [
"zstd",
]
[[package]]
name = "monitor_cli"
version = "0.1.0"
dependencies = [
"async_timing_util",
"bollard",
"clap",
"monitor_types",
"rand",
"serde",
"serde_json",
"toml",
]
[[package]]
name = "monitor_client"
version = "0.1.1"

View File

@@ -1,10 +1,17 @@
[package]
name = "cli"
name = "monitor_cli"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
monitor_types = { path = "../lib/types" }
# monitor_types = "0.1.0"
clap = { version="4.0", features=["derive"] }
bollard = "0.13"
bollard = "0.13"
async_timing_util = "0.1.12"
rand = "0.8"
serde = "1.0"
serde_json = "1.0"
toml = "0.5"

85
cli/src/helpers.rs Normal file
View File

@@ -0,0 +1,85 @@
use std::{
fs::{self, File},
io::Write,
};
use async_timing_util::Timelength;
use clap::ArgMatches;
use monitor_types::{CoreConfig, MongoConfig};
use rand::{distributions::Alphanumeric, Rng};
use serde::Serialize;
pub fn gen_core_config(sub_matches: &ArgMatches) {
let path = sub_matches
.get_one::<String>("path")
.map(|p| p.as_str())
.unwrap_or("$HOME/.monitor/config.toml")
.to_string();
let port = sub_matches
.get_one::<String>("port")
.map(|p| p.as_str())
.unwrap_or("9000")
.parse::<u16>()
.expect("invalid port");
let mongo_uri = sub_matches
.get_one::<String>("mongo_uri")
.map(|p| p.as_str())
.unwrap_or("mongodb://mongo")
.to_string();
let mongo_db_name = sub_matches
.get_one::<String>("mongo_db_name")
.map(|p| p.as_str())
.unwrap_or("monitor")
.to_string();
let jwt_valid_for = sub_matches
.get_one::<String>("jwt_valid_for")
.map(|p| p.as_str())
.unwrap_or("1-wk")
.parse()
.expect("invalid jwt_valid_for");
let slack_url = sub_matches
.get_one::<String>("slack_url")
.map(|p| p.to_owned());
let config = CoreConfig {
port,
jwt_valid_for,
slack_url,
github_oauth: Default::default(),
mongo: MongoConfig {
uri: mongo_uri,
db_name: mongo_db_name,
app_name: "monitor".to_string(),
},
jwt_secret: generate_secret(40),
github_webhook_secret: generate_secret(30),
};
write_to_toml(&path, config);
println!("core config has been generated ✅");
}
pub fn start_mongo(sub_matches: &ArgMatches) {}
pub fn start_core(sub_matches: &ArgMatches) {}
pub fn get_periphery_config(sub_matches: &ArgMatches) {}
pub fn start_periphery(sub_matches: &ArgMatches) {}
fn write_to_toml(path: &str, toml: impl Serialize) {
fs::write(
path,
toml::to_string(&toml).expect("failed to parse config into toml"),
)
.expect("failed to write toml to file");
}
fn generate_secret(length: usize) -> String {
rand::thread_rng()
.sample_iter(&Alphanumeric)
.take(length)
.map(char::from)
.collect()
}

View File

@@ -1,3 +1,92 @@
fn main() {
println!("Hello, world!");
}
#![allow(unused)]
use clap::{arg, Arg, Command};
mod helpers;
use helpers::*;
fn cli() -> Command {
Command::new("monitor_cli")
.about("\na cli to set up monitor components")
.subcommand_required(true)
.arg_required_else_help(true)
.allow_external_subcommands(true)
.subcommand(
Command::new("core")
.about("tools to set up monitor core")
.subcommand_required(true)
.arg_required_else_help(true)
.allow_external_subcommands(true)
.subcommand(
Command::new("config_gen")
.about("generate a core config")
.arg(
arg!(--path <PATH> "sets path of generated config file. default is '~/.monitor/config.toml'")
.required(false)
)
.arg(
arg!(--port <PORT> "sets port core will run on. default is 9000")
.required(false)
)
.arg(
arg!(--mongo_uri <URI> "sets the mongo uri to use. default is 'mongodb://mongo'")
.required(false)
)
.arg(
arg!(--mongo_db_name <NAME> "sets the db name to use. default is 'monitor'")
.required(false)
)
.arg(
arg!(--jwt_valid_for <TIMELENGTH> "sets the length of time jwt stays valid for. default is 1-wk (one week)")
.required(false)
)
.arg(
arg!(--slack_url <URL> "sets the slack url to use for slack notifications")
.required(false)
),
)
.subcommand(Command::new("start_mongo").about("start up a mongo for monitor"))
.subcommand(Command::new("start").about("start up monitor core")),
)
.subcommand(
Command::new("periphery")
.about("tools to set up monitor periphery")
.subcommand_required(true)
.arg_required_else_help(true)
.allow_external_subcommands(true)
.subcommand(Command::new("config_gen").about("generate a periphery config"))
.subcommand(Command::new("start").about("start up monitor periphery")),
)
}
fn main() {
let matches = cli().get_matches();
match matches.subcommand() {
Some(("core", sub_matches)) => {
let core_command = sub_matches.subcommand().expect("invalid call, should be 'monitor_cli core <config_gen, start_mongo, start> <flags>'");
match core_command {
("config_gen", sub_matches) => gen_core_config(sub_matches),
("start_mongo", sub_matches) => start_mongo(sub_matches),
("start", sub_matches) => start_core(sub_matches),
_ => {
println!("invalid call, should be 'monitor_cli core <config_gen, start_mongo, start> <flags>'")
}
}
}
Some(("periphery", sub_matches)) => {
let periphery_command = sub_matches.subcommand().expect(
"invalid call, should be 'monitor_cli periphery <config_gen, start> <flags>'",
);
match periphery_command {
("config_gen", sub_matches) => get_periphery_config(sub_matches),
("start", sub_matches) => start_periphery(sub_matches),
_ => {
println!("invalid call, should be 'monitor_cli core <config_gen, start_mongo, start> <flags>'")
}
}
}
_ => unreachable!(),
}
}

View File

@@ -29,6 +29,6 @@ bcrypt = "0.13"
jwt = "0.16"
hmac = "0.12"
sha2 = "0.10"
async_timing_util = "0.1.11"
async_timing_util = "0.1.12"
futures-util = "0.3"
diff-struct = "0.5"

View File

@@ -7,7 +7,8 @@ use axum::{
use helpers::handle_anyhow_error;
use mungos::{Deserialize, Document};
use types::{
traits::Permissioned, ImageSummary, Log, Network, PermissionLevel, Server, SystemStats, BasicContainerInfo,
traits::Permissioned, BasicContainerInfo, ImageSummary, Log, Network, PermissionLevel, Server,
SystemStats,
};
use crate::{
@@ -311,7 +312,10 @@ impl State {
.periphery
.container_list(&server)
.await
.context(format!("failed to get containers from server {}", server.name))?;
.context(format!(
"failed to get containers from server {}",
server.name
))?;
Ok(images)
}
@@ -323,7 +327,10 @@ impl State {
.periphery
.container_prune(&server)
.await
.context(format!("failed to prune containers on server {}", server.name))?;
.context(format!(
"failed to prune containers on server {}",
server.name
))?;
Ok(log)
}
}

View File

@@ -19,9 +19,6 @@ pub fn load() -> CoreConfig {
fn print_startup_log(config: &CoreConfig) {
println!("starting monitor core on port {}", config.port);
if config.github_webhook_secret.is_none() {
println!("\nNOTE: you have not configured a github_webhook_secret. this is optional, but recommended if you use github repo webhooks")
}
}
pub fn default_config_path() -> String {

View File

@@ -7,7 +7,7 @@ edition = "2021"
[dependencies]
types = { package = "monitor_types", path = "../types" }
async_timing_util = "0.1.11"
async_timing_util = "0.1.12"
bollard = "0.13"
anyhow = "1.0"
axum = { version = "0.6", features = ["ws", "json"] }

View File

@@ -1,5 +1,5 @@
use anyhow::Context;
use monitor_types::{Log, Network, Server, SystemStats, ImageSummary, BasicContainerInfo};
use monitor_types::{BasicContainerInfo, ImageSummary, Log, Network, Server, SystemStats};
use serde::Serialize;
use serde_json::{json, Value};
@@ -58,9 +58,7 @@ impl MonitorClient {
Option::<()>::None,
)
.await
.context(format!(
"failed to get networks on server id {server_id}"
))
.context(format!("failed to get networks on server id {server_id}"))
}
pub async fn prune_docker_networks(&self, server_id: &str) -> anyhow::Result<Log> {
@@ -75,9 +73,7 @@ impl MonitorClient {
Option::<()>::None,
)
.await
.context(format!(
"failed to get images on server id {server_id}"
))
.context(format!("failed to get images on server id {server_id}"))
}
pub async fn prune_docker_images(&self, server_id: &str) -> anyhow::Result<Log> {
@@ -86,20 +82,23 @@ impl MonitorClient {
.context(format!("failed to prune images on server id {server_id}"))
}
pub async fn get_docker_containers(&self, server_id: &str) -> anyhow::Result<Vec<BasicContainerInfo>> {
pub async fn get_docker_containers(
&self,
server_id: &str,
) -> anyhow::Result<Vec<BasicContainerInfo>> {
self.get(
&format!("/api/server/{server_id}/containers"),
Option::<()>::None,
)
.await
.context(format!(
"failed to get containers on server id {server_id}"
))
.context(format!("failed to get containers on server id {server_id}"))
}
pub async fn prune_docker_containers(&self, server_id: &str) -> anyhow::Result<Log> {
self.post::<(), _>(&format!("/api/server/{server_id}/containers/prune"), None)
.await
.context(format!("failed to prune containers on server id {server_id}"))
.context(format!(
"failed to prune containers on server id {server_id}"
))
}
}

View File

@@ -14,6 +14,6 @@ serde_derive = "1.0"
mungos = "0.2.24"
strum = "0.24"
strum_macros = "0.24"
async_timing_util = "0.1.11"
async_timing_util = "0.1.12"
diff-struct = "0.5.1"
bollard = "0.13"

View File

@@ -478,13 +478,13 @@ pub struct EnvironmentVar {
pub value: String,
}
#[derive(Deserialize, Debug, Clone)]
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
pub struct OauthCredentials {
pub id: String,
pub secret: String,
}
#[derive(Deserialize, Debug, Clone)]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct CoreConfig {
// port the core web server runs on
#[serde(default = "default_core_port")]
@@ -499,8 +499,8 @@ pub struct CoreConfig {
pub slack_url: Option<String>,
// github integration
pub github_webhook_secret: String,
pub github_oauth: OauthCredentials,
pub github_webhook_secret: Option<String>,
// mongo config
pub mongo: MongoConfig,
@@ -514,7 +514,7 @@ fn default_jwt_valid_for() -> Timelength {
Timelength::OneWeek
}
#[derive(Deserialize, Debug, Clone)]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct MongoConfig {
pub uri: String,
#[serde(default = "default_core_mongo_app_name")]

View File

@@ -14,4 +14,4 @@ serde_derive = "1.0"
envy = "0.4"
anyhow = "1.0"
dotenv = "0.15"
async_timing_util = "0.1.11"
async_timing_util = "0.1.12"