mirror of
https://codeberg.org/icewind/haze.git
synced 2026-06-03 17:14:08 +02:00
basic subcommands
This commit is contained in:
parent
d426b537b2
commit
da1e184e42
3 changed files with 192 additions and 41 deletions
45
src/args.rs
45
src/args.rs
|
|
@ -1,12 +1,11 @@
|
||||||
use color_eyre::{eyre::WrapErr, Report, Result};
|
use color_eyre::{Report, Result};
|
||||||
use std::env::Args;
|
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||||
pub struct HazeArgs {
|
pub struct HazeArgs {
|
||||||
id: Option<String>,
|
pub id: Option<String>,
|
||||||
command: Command,
|
pub command: HazeCommand,
|
||||||
options: Vec<String>,
|
pub options: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HazeArgs {
|
impl HazeArgs {
|
||||||
|
|
@ -24,11 +23,11 @@ impl HazeArgs {
|
||||||
if let Some(sub) = args.next() {
|
if let Some(sub) = args.next() {
|
||||||
(Some(sub_or_id.to_string()), sub.as_ref().parse()?)
|
(Some(sub_or_id.to_string()), sub.as_ref().parse()?)
|
||||||
} else {
|
} else {
|
||||||
(Some(sub_or_id.to_string()), Command::List)
|
(Some(sub_or_id.to_string()), HazeCommand::List)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => (None, Command::List),
|
None => (None, HazeCommand::List),
|
||||||
};
|
};
|
||||||
let options = args.map(|s| s.to_string()).collect();
|
let options = args.map(|s| s.to_string()).collect();
|
||||||
Ok(HazeArgs {
|
Ok(HazeArgs {
|
||||||
|
|
@ -40,7 +39,7 @@ impl HazeArgs {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
||||||
pub enum Command {
|
pub enum HazeCommand {
|
||||||
List,
|
List,
|
||||||
Start,
|
Start,
|
||||||
Stop,
|
Stop,
|
||||||
|
|
@ -48,20 +47,22 @@ pub enum Command {
|
||||||
Exec,
|
Exec,
|
||||||
Occ,
|
Occ,
|
||||||
Db,
|
Db,
|
||||||
|
Clean,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromStr for Command {
|
impl FromStr for HazeCommand {
|
||||||
type Err = Report;
|
type Err = Report;
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
match s {
|
match s {
|
||||||
"list" => Ok(Command::List),
|
"list" => Ok(HazeCommand::List),
|
||||||
"start" => Ok(Command::Start),
|
"start" => Ok(HazeCommand::Start),
|
||||||
"stop" => Ok(Command::Stop),
|
"stop" => Ok(HazeCommand::Stop),
|
||||||
"test" => Ok(Command::Test),
|
"test" => Ok(HazeCommand::Test),
|
||||||
"exec" => Ok(Command::Exec),
|
"exec" => Ok(HazeCommand::Exec),
|
||||||
"occ" => Ok(Command::Occ),
|
"occ" => Ok(HazeCommand::Occ),
|
||||||
"db" => Ok(Command::Db),
|
"db" => Ok(HazeCommand::Db),
|
||||||
|
"clean" => Ok(HazeCommand::Clean),
|
||||||
_ => Err(Report::msg(format!("Unknown command: {}", s))),
|
_ => Err(Report::msg(format!("Unknown command: {}", s))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -73,7 +74,7 @@ fn test_arg_parse() {
|
||||||
HazeArgs::parse(vec!["haze"].into_iter()).unwrap(),
|
HazeArgs::parse(vec!["haze"].into_iter()).unwrap(),
|
||||||
HazeArgs {
|
HazeArgs {
|
||||||
id: None,
|
id: None,
|
||||||
command: Command::List,
|
command: HazeCommand::List,
|
||||||
options: Vec::new(),
|
options: Vec::new(),
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
@ -81,7 +82,7 @@ fn test_arg_parse() {
|
||||||
HazeArgs::parse(vec!["haze", "test"].into_iter()).unwrap(),
|
HazeArgs::parse(vec!["haze", "test"].into_iter()).unwrap(),
|
||||||
HazeArgs {
|
HazeArgs {
|
||||||
id: None,
|
id: None,
|
||||||
command: Command::Test,
|
command: HazeCommand::Test,
|
||||||
options: Vec::new(),
|
options: Vec::new(),
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
@ -89,7 +90,7 @@ fn test_arg_parse() {
|
||||||
HazeArgs::parse(vec!["haze", "asdasd"].into_iter()).unwrap(),
|
HazeArgs::parse(vec!["haze", "asdasd"].into_iter()).unwrap(),
|
||||||
HazeArgs {
|
HazeArgs {
|
||||||
id: Some("asdasd".to_string()),
|
id: Some("asdasd".to_string()),
|
||||||
command: Command::List,
|
command: HazeCommand::List,
|
||||||
options: Vec::new(),
|
options: Vec::new(),
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
@ -97,7 +98,7 @@ fn test_arg_parse() {
|
||||||
HazeArgs::parse(vec!["haze", "asdasd", "db"].into_iter()).unwrap(),
|
HazeArgs::parse(vec!["haze", "asdasd", "db"].into_iter()).unwrap(),
|
||||||
HazeArgs {
|
HazeArgs {
|
||||||
id: Some("asdasd".to_string()),
|
id: Some("asdasd".to_string()),
|
||||||
command: Command::Db,
|
command: HazeCommand::Db,
|
||||||
options: Vec::new(),
|
options: Vec::new(),
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
@ -105,7 +106,7 @@ fn test_arg_parse() {
|
||||||
HazeArgs::parse(vec!["haze", "exec", "foo", "bar"].into_iter()).unwrap(),
|
HazeArgs::parse(vec!["haze", "exec", "foo", "bar"].into_iter()).unwrap(),
|
||||||
HazeArgs {
|
HazeArgs {
|
||||||
id: None,
|
id: None,
|
||||||
command: Command::Exec,
|
command: HazeCommand::Exec,
|
||||||
options: vec!["foo".to_string(), "bar".to_string()],
|
options: vec!["foo".to_string(), "bar".to_string()],
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
@ -113,7 +114,7 @@ fn test_arg_parse() {
|
||||||
HazeArgs::parse(vec!["haze", "asdasd", "exec", "foo", "bar"].into_iter()).unwrap(),
|
HazeArgs::parse(vec!["haze", "asdasd", "exec", "foo", "bar"].into_iter()).unwrap(),
|
||||||
HazeArgs {
|
HazeArgs {
|
||||||
id: Some("asdasd".to_string()),
|
id: Some("asdasd".to_string()),
|
||||||
command: Command::Exec,
|
command: HazeCommand::Exec,
|
||||||
options: vec!["foo".to_string(), "bar".to_string()],
|
options: vec!["foo".to_string(), "bar".to_string()],
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
||||||
140
src/cloud.rs
140
src/cloud.rs
|
|
@ -14,7 +14,7 @@ use std::time::Duration;
|
||||||
use tokio::fs::{create_dir_all, remove_dir_all, write};
|
use tokio::fs::{create_dir_all, remove_dir_all, write};
|
||||||
use tokio::time::sleep;
|
use tokio::time::sleep;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Eq, PartialEq)]
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub enum Database {
|
pub enum Database {
|
||||||
Sqlite,
|
Sqlite,
|
||||||
|
|
@ -43,15 +43,30 @@ impl Default for Database {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromStr for Database {
|
impl FromStr for Database {
|
||||||
type Err = ();
|
type Err = Report;
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
match s {
|
match s {
|
||||||
"sqlite" => Ok(Database::Sqlite),
|
"sqlite" => Ok(Database::Sqlite),
|
||||||
"mysql" => Ok(Database::Mysql),
|
"mysql" => Ok(Database::Mysql),
|
||||||
|
"mysql:8" => Ok(Database::Mysql80),
|
||||||
|
"mysql:5" => Ok(Database::Mysql57),
|
||||||
|
"mysql:5.7" => Ok(Database::Mysql57),
|
||||||
|
"mysql:5.6" => Ok(Database::Mysql56),
|
||||||
"mariadb" => Ok(Database::MariaDB),
|
"mariadb" => Ok(Database::MariaDB),
|
||||||
"postgresql" => Ok(Database::Postgres),
|
"mariadb:10.1" => Ok(Database::MariaDB101),
|
||||||
_ => Err(()),
|
"mariadb:10.2" => Ok(Database::MariaDB102),
|
||||||
|
"mariadb:10.3" => Ok(Database::MariaDB103),
|
||||||
|
"mariadb:10.4" => Ok(Database::MariaDB104),
|
||||||
|
"mariadb:10.5" => Ok(Database::MariaDB105),
|
||||||
|
"mariadb:10" => Ok(Database::MariaDB105),
|
||||||
|
"pgsql" => Ok(Database::Postgres),
|
||||||
|
"pgsql:9" => Ok(Database::Postgres9),
|
||||||
|
"pgsql:10" => Ok(Database::Postgres10),
|
||||||
|
"pgsql:11" => Ok(Database::Postgres11),
|
||||||
|
"pgsql:12" => Ok(Database::Postgres12),
|
||||||
|
"pgsql:13" => Ok(Database::Postgres13),
|
||||||
|
_ => Err(Report::msg("Unknown db type")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -163,7 +178,7 @@ impl Database {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Eq, PartialEq)]
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub enum PhpVersion {
|
pub enum PhpVersion {
|
||||||
Latest,
|
Latest,
|
||||||
|
|
@ -172,6 +187,18 @@ pub enum PhpVersion {
|
||||||
// Php73,
|
// Php73,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl FromStr for PhpVersion {
|
||||||
|
type Err = ();
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
match s {
|
||||||
|
"7" => Ok(PhpVersion::Php74),
|
||||||
|
"7.4" => Ok(PhpVersion::Php74),
|
||||||
|
_ => Err(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl PhpVersion {
|
impl PhpVersion {
|
||||||
fn image(&self) -> &'static str {
|
fn image(&self) -> &'static str {
|
||||||
// for now only 7.4
|
// for now only 7.4
|
||||||
|
|
@ -181,6 +208,13 @@ impl PhpVersion {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn name(&self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
PhpVersion::Latest => "7.4",
|
||||||
|
PhpVersion::Php74 => "7.4",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async fn spawn(
|
async fn spawn(
|
||||||
&self,
|
&self,
|
||||||
docker: &mut Docker,
|
docker: &mut Docker,
|
||||||
|
|
@ -206,6 +240,7 @@ impl PhpVersion {
|
||||||
labels: Some(hashmap! {
|
labels: Some(hashmap! {
|
||||||
"haze-type".to_string() => "cloud".to_string(),
|
"haze-type".to_string() => "cloud".to_string(),
|
||||||
"haze-db".to_string() => db.name().to_string(),
|
"haze-db".to_string() => db.name().to_string(),
|
||||||
|
"haze-php".to_string() => self.name().to_string(),
|
||||||
"haze-cloud-id".to_string() => id.to_string(),
|
"haze-cloud-id".to_string() => id.to_string(),
|
||||||
}),
|
}),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
|
|
@ -223,20 +258,97 @@ impl Default for PhpVersion {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Debug)]
|
#[derive(Default, Debug, Eq, PartialEq)]
|
||||||
pub struct CloudOptions {
|
pub struct CloudOptions {
|
||||||
db: Database,
|
db: Database,
|
||||||
php: PhpVersion,
|
php: PhpVersion,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl CloudOptions {
|
||||||
|
pub fn parse<S>(options: Vec<S>) -> Result<(CloudOptions, Vec<S>)>
|
||||||
|
where
|
||||||
|
S: AsRef<str> + Clone,
|
||||||
|
{
|
||||||
|
let mut db = Database::default();
|
||||||
|
let mut php = PhpVersion::default();
|
||||||
|
let mut used = 0;
|
||||||
|
|
||||||
|
for option in options.iter() {
|
||||||
|
if let Ok(db_option) = Database::from_str(option.as_ref()) {
|
||||||
|
db = db_option;
|
||||||
|
used += 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if let Ok(php_option) = PhpVersion::from_str(option.as_ref()) {
|
||||||
|
php = php_option;
|
||||||
|
used += 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let rest = options[used..].to_vec();
|
||||||
|
|
||||||
|
Ok((CloudOptions { db, php }, rest))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_option_parse() {
|
||||||
|
assert_eq!(
|
||||||
|
CloudOptions::parse::<&str>(vec![]).unwrap(),
|
||||||
|
(CloudOptions::default(), vec![])
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
CloudOptions::parse(vec!["mariadb"]).unwrap(),
|
||||||
|
(
|
||||||
|
CloudOptions {
|
||||||
|
db: Database::MariaDB,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
vec![]
|
||||||
|
)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
CloudOptions::parse(vec!["rest"]).unwrap(),
|
||||||
|
(
|
||||||
|
CloudOptions {
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
vec!["rest"]
|
||||||
|
)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
CloudOptions::parse(vec!["7"]).unwrap(),
|
||||||
|
(
|
||||||
|
CloudOptions {
|
||||||
|
php: PhpVersion::Php74,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
vec![]
|
||||||
|
)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
CloudOptions::parse(vec!["7", "pgsql", "rest"]).unwrap(),
|
||||||
|
(
|
||||||
|
CloudOptions {
|
||||||
|
php: PhpVersion::Php74,
|
||||||
|
db: Database::Postgres,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
vec!["rest"]
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Cloud {
|
pub struct Cloud {
|
||||||
pub id: String,
|
pub id: String,
|
||||||
network: String,
|
pub network: String,
|
||||||
containers: Vec<String>,
|
pub containers: Vec<String>,
|
||||||
db: Database,
|
pub php: PhpVersion,
|
||||||
|
pub db: Database,
|
||||||
pub ip: IpAddr,
|
pub ip: IpAddr,
|
||||||
workdir: Utf8PathBuf,
|
pub workdir: Utf8PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Cloud {
|
impl Cloud {
|
||||||
|
|
@ -360,6 +472,7 @@ impl Cloud {
|
||||||
id,
|
id,
|
||||||
network,
|
network,
|
||||||
containers,
|
containers,
|
||||||
|
php: options.php,
|
||||||
db: options.db,
|
db: options.db,
|
||||||
ip,
|
ip,
|
||||||
workdir,
|
workdir,
|
||||||
|
|
@ -411,7 +524,7 @@ async fn setup_workdir(base: &Utf8Path, id: &str) -> Result<Utf8PathBuf> {
|
||||||
Ok(workdir)
|
Ok(workdir)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn parse(docker: &mut Docker, config: &HazeConfig) -> Result<Vec<Cloud>> {
|
pub async fn list(docker: &mut Docker, config: &HazeConfig) -> Result<Vec<Cloud>> {
|
||||||
let containers = docker.list_containers::<String>(None).await?;
|
let containers = docker.list_containers::<String>(None).await?;
|
||||||
let mut containers_by_id: HashMap<String, (Option<_>, Vec<_>)> = HashMap::new();
|
let mut containers_by_id: HashMap<String, (Option<_>, Vec<_>)> = HashMap::new();
|
||||||
for container in containers {
|
for container in containers {
|
||||||
|
|
@ -434,7 +547,9 @@ pub async fn parse(docker: &mut Docker, config: &HazeConfig) -> Result<Vec<Cloud
|
||||||
let networks = cloud.network_settings?.networks?;
|
let networks = cloud.network_settings?.networks?;
|
||||||
let network_info = networks.get(&network)?;
|
let network_info = networks.get(&network)?;
|
||||||
let workdir = config.work_dir.join(&id);
|
let workdir = config.work_dir.join(&id);
|
||||||
let db = cloud.labels?.get("haze-db")?.parse().ok()?;
|
let labels = cloud.labels?;
|
||||||
|
let db = labels.get("haze-db")?.parse().ok()?;
|
||||||
|
let php = labels.get("haze-php")?.parse().ok()?;
|
||||||
let mut service_ids: Vec<String> = services
|
let mut service_ids: Vec<String> = services
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|service| service.names.as_ref()?.first().map(String::clone))
|
.filter_map(|service| service.names.as_ref()?.first().map(String::clone))
|
||||||
|
|
@ -444,6 +559,7 @@ pub async fn parse(docker: &mut Docker, config: &HazeConfig) -> Result<Vec<Cloud
|
||||||
id,
|
id,
|
||||||
network,
|
network,
|
||||||
db,
|
db,
|
||||||
|
php,
|
||||||
containers: service_ids,
|
containers: service_ids,
|
||||||
ip: network_info.ip_address.as_ref()?.parse().ok()?,
|
ip: network_info.ip_address.as_ref()?.parse().ok()?,
|
||||||
workdir,
|
workdir,
|
||||||
|
|
|
||||||
48
src/main.rs
48
src/main.rs
|
|
@ -1,7 +1,8 @@
|
||||||
use crate::cloud::{parse, Cloud, CloudOptions};
|
use crate::args::{HazeArgs, HazeCommand};
|
||||||
|
use crate::cloud::{list, Cloud, CloudOptions};
|
||||||
use crate::config::HazeConfig;
|
use crate::config::HazeConfig;
|
||||||
use bollard::Docker;
|
use bollard::Docker;
|
||||||
use color_eyre::{eyre::WrapErr, Result};
|
use color_eyre::{eyre::WrapErr, Report, Result};
|
||||||
|
|
||||||
mod args;
|
mod args;
|
||||||
mod cloud;
|
mod cloud;
|
||||||
|
|
@ -15,13 +16,46 @@ async fn main() -> Result<()> {
|
||||||
sources_root: "/srv/http/owncloud".into(),
|
sources_root: "/srv/http/owncloud".into(),
|
||||||
work_dir: "/tmp/haze".into(),
|
work_dir: "/tmp/haze".into(),
|
||||||
};
|
};
|
||||||
let options = CloudOptions::default();
|
|
||||||
|
|
||||||
// let cloud = Cloud::create(&mut docker, options, &config).await?;
|
let args = HazeArgs::parse(std::env::args())?;
|
||||||
// println!("{} running on http://{}", cloud.id, cloud.ip);
|
dbg!(&args);
|
||||||
|
|
||||||
let clouds = parse(&mut docker, &config).await?;
|
match args.command {
|
||||||
dbg!(clouds);
|
HazeCommand::Clean => {
|
||||||
|
let list = list(&mut docker, &config).await?;
|
||||||
|
for cloud in list {
|
||||||
|
if let Err(e) = cloud.destroy(&mut docker).await {
|
||||||
|
eprintln!("Error while removing cloud: {:#}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
HazeCommand::List => {
|
||||||
|
let list = list(&mut docker, &config).await?;
|
||||||
|
for cloud in list {
|
||||||
|
if let Some(filter) = &args.id {
|
||||||
|
if !cloud.id.contains(filter.as_str()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println!(
|
||||||
|
"Cloud {}, {}, {}, running on http://{}",
|
||||||
|
cloud.id,
|
||||||
|
cloud.php.name(),
|
||||||
|
cloud.db.name(),
|
||||||
|
cloud.ip
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
HazeCommand::Start => {
|
||||||
|
let (options, rest) = CloudOptions::parse(args.options)?;
|
||||||
|
if let Some(next) = rest.first() {
|
||||||
|
return Err(Report::msg(format!("Unknown option {}", next)));
|
||||||
|
}
|
||||||
|
let cloud = Cloud::create(&mut docker, options, &config).await?;
|
||||||
|
println!("http://{}", cloud.ip);
|
||||||
|
}
|
||||||
|
_ => todo!(),
|
||||||
|
};
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue