mirror of
https://codeberg.org/icewind/haze.git
synced 2026-06-03 17:14:08 +02:00
images and linking
This commit is contained in:
parent
da1e184e42
commit
06c0330de8
16 changed files with 1045 additions and 50 deletions
|
|
@ -48,6 +48,7 @@ pub enum HazeCommand {
|
|||
Occ,
|
||||
Db,
|
||||
Clean,
|
||||
Logs,
|
||||
}
|
||||
|
||||
impl FromStr for HazeCommand {
|
||||
|
|
@ -63,6 +64,7 @@ impl FromStr for HazeCommand {
|
|||
"occ" => Ok(HazeCommand::Occ),
|
||||
"db" => Ok(HazeCommand::Db),
|
||||
"clean" => Ok(HazeCommand::Clean),
|
||||
"logs" => Ok(HazeCommand::Logs),
|
||||
_ => Err(Report::msg(format!("Unknown command: {}", s))),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
153
src/cloud.rs
153
src/cloud.rs
|
|
@ -1,14 +1,20 @@
|
|||
use crate::config::HazeConfig;
|
||||
use bollard::container::{Config, CreateContainerOptions, RemoveContainerOptions};
|
||||
use bollard::models::{ContainerState, HostConfig};
|
||||
use bollard::container::{
|
||||
Config, CreateContainerOptions, ListContainersOptions, LogsOptions, NetworkingConfig,
|
||||
RemoveContainerOptions,
|
||||
};
|
||||
use bollard::models::{ContainerState, EndpointSettings, HostConfig};
|
||||
use bollard::network::CreateNetworkOptions;
|
||||
use bollard::Docker;
|
||||
use camino::{Utf8Path, Utf8PathBuf};
|
||||
use color_eyre::{eyre::WrapErr, Report, Result};
|
||||
use futures_util::stream::StreamExt;
|
||||
use maplit::hashmap;
|
||||
use min_id::generate_id;
|
||||
use std::collections::HashMap;
|
||||
use std::fs;
|
||||
use std::net::IpAddr;
|
||||
use std::os::unix::fs::MetadataExt;
|
||||
use std::str::FromStr;
|
||||
use std::time::Duration;
|
||||
use tokio::fs::{create_dir_all, remove_dir_all, write};
|
||||
|
|
@ -85,12 +91,12 @@ impl Database {
|
|||
Database::MariaDB103 => "mariadb:10.3",
|
||||
Database::MariaDB104 => "mariadb:10.4",
|
||||
Database::MariaDB105 => "mariadb:10.5",
|
||||
Database::Postgres => "postgresql",
|
||||
Database::Postgres9 => "postgresql:9",
|
||||
Database::Postgres10 => "postgresql:10",
|
||||
Database::Postgres11 => "postgresql:11",
|
||||
Database::Postgres12 => "postgresql:12",
|
||||
Database::Postgres13 => "postgresql:13",
|
||||
Database::Postgres => "postgres",
|
||||
Database::Postgres9 => "postgres:9",
|
||||
Database::Postgres10 => "postgres:10",
|
||||
Database::Postgres11 => "postgres:11",
|
||||
Database::Postgres12 => "postgres:12",
|
||||
Database::Postgres13 => "postgres:13",
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -170,6 +176,14 @@ impl Database {
|
|||
"haze-type" => "db",
|
||||
"haze-cloud-id" => cloud_id
|
||||
}),
|
||||
networking_config: Some(NetworkingConfig {
|
||||
endpoints_config: hashmap! {
|
||||
network => EndpointSettings {
|
||||
aliases: Some(vec![self.name().to_string()]),
|
||||
..Default::default()
|
||||
}
|
||||
},
|
||||
}),
|
||||
..Default::default()
|
||||
};
|
||||
let id = docker.create_container(options, config).await?.id;
|
||||
|
|
@ -203,8 +217,8 @@ impl PhpVersion {
|
|||
fn image(&self) -> &'static str {
|
||||
// for now only 7.4
|
||||
match self {
|
||||
PhpVersion::Latest => "icewind1991/nextcloud-dev:7",
|
||||
PhpVersion::Php74 => "icewind1991/nextcloud-dev:7",
|
||||
PhpVersion::Latest => "icewind1991/haze:7.4",
|
||||
PhpVersion::Php74 => "icewind1991/haze:7.4",
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -222,7 +236,6 @@ impl PhpVersion {
|
|||
env: Vec<String>,
|
||||
db: &Database,
|
||||
network: &str,
|
||||
links: Vec<String>,
|
||||
volumes: Vec<String>,
|
||||
) -> Result<String> {
|
||||
let options = Some(CreateContainerOptions {
|
||||
|
|
@ -233,10 +246,18 @@ impl PhpVersion {
|
|||
env: Some(env),
|
||||
host_config: Some(HostConfig {
|
||||
network_mode: Some(network.to_string()),
|
||||
links: Some(links),
|
||||
// links: Some(links),
|
||||
binds: Some(volumes),
|
||||
..Default::default()
|
||||
}),
|
||||
networking_config: Some(NetworkingConfig {
|
||||
endpoints_config: hashmap! {
|
||||
network.to_string() => EndpointSettings {
|
||||
aliases: Some(vec!["cloud".to_string()]),
|
||||
..Default::default()
|
||||
}
|
||||
},
|
||||
}),
|
||||
labels: Some(hashmap! {
|
||||
"haze-type".to_string() => "cloud".to_string(),
|
||||
"haze-db".to_string() => db.name().to_string(),
|
||||
|
|
@ -347,7 +368,7 @@ pub struct Cloud {
|
|||
pub containers: Vec<String>,
|
||||
pub php: PhpVersion,
|
||||
pub db: Database,
|
||||
pub ip: IpAddr,
|
||||
pub ip: Option<IpAddr>,
|
||||
pub workdir: Utf8PathBuf,
|
||||
}
|
||||
|
||||
|
|
@ -374,8 +395,16 @@ impl Cloud {
|
|||
.wrap_err("Failed to create network")?;
|
||||
|
||||
let mut containers = Vec::new();
|
||||
let mut links = Vec::new();
|
||||
let mut env = vec!["PHP_IDE_CONFIG=serverName=haze".to_string()];
|
||||
|
||||
let sources_meta = fs::metadata(&config.sources_root)?;
|
||||
let uid = sources_meta.uid();
|
||||
let gid = sources_meta.gid();
|
||||
|
||||
let mut env = vec![
|
||||
"PHP_IDE_CONFIG=serverName=haze".to_string(),
|
||||
format!("UID={}", uid),
|
||||
format!("GID={}", gid),
|
||||
];
|
||||
let volumes = vec![
|
||||
format!("{}:/var/www/html", config.sources_root),
|
||||
format!("{}/{}/data:/var/www/html/data", config.work_dir, id),
|
||||
|
|
@ -425,13 +454,12 @@ impl Cloud {
|
|||
.wrap_err("Failed to start database")?
|
||||
{
|
||||
containers.push(db_name);
|
||||
links.push(format!("{}-db:{}", id, options.db.name()));
|
||||
env.push(format!("SQL={}", options.db.name()));
|
||||
}
|
||||
|
||||
let container = options
|
||||
.php
|
||||
.spawn(docker, &id, env, &options.db, &network, links, volumes)
|
||||
.spawn(docker, &id, env, &options.db, &network, volumes)
|
||||
.await
|
||||
.wrap_err("Failed to start php container")?;
|
||||
|
||||
|
|
@ -474,17 +502,16 @@ impl Cloud {
|
|||
containers,
|
||||
php: options.php,
|
||||
db: options.db,
|
||||
ip,
|
||||
ip: Some(ip),
|
||||
workdir,
|
||||
})
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub async fn destroy(self, docker: &mut Docker) -> Result<()> {
|
||||
for container in self.containers {
|
||||
docker
|
||||
.remove_container(
|
||||
&container,
|
||||
container.trim_start_matches('/'),
|
||||
Some(RemoveContainerOptions {
|
||||
force: true,
|
||||
..Default::default()
|
||||
|
|
@ -503,6 +530,22 @@ impl Cloud {
|
|||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn logs(&self, docker: &mut Docker) -> Result<Vec<String>> {
|
||||
let mut logs = Vec::new();
|
||||
let mut stream = docker.logs::<String>(
|
||||
&self.id,
|
||||
Some(LogsOptions {
|
||||
stdout: true,
|
||||
stderr: true,
|
||||
..Default::default()
|
||||
}),
|
||||
);
|
||||
while let Some(line) = stream.next().await {
|
||||
logs.push(line?.to_string());
|
||||
}
|
||||
Ok(logs)
|
||||
}
|
||||
}
|
||||
|
||||
async fn setup_workdir(base: &Utf8Path, id: &str) -> Result<Utf8PathBuf> {
|
||||
|
|
@ -524,22 +567,36 @@ async fn setup_workdir(base: &Utf8Path, id: &str) -> Result<Utf8PathBuf> {
|
|||
Ok(workdir)
|
||||
}
|
||||
|
||||
pub async fn list(docker: &mut Docker, config: &HazeConfig) -> Result<Vec<Cloud>> {
|
||||
let containers = docker.list_containers::<String>(None).await?;
|
||||
pub async fn list(
|
||||
docker: &mut Docker,
|
||||
filter: Option<String>,
|
||||
config: &HazeConfig,
|
||||
) -> Result<Vec<Cloud>> {
|
||||
let containers = docker
|
||||
.list_containers::<String>(Some(ListContainersOptions {
|
||||
all: true,
|
||||
..Default::default()
|
||||
}))
|
||||
.await?;
|
||||
let mut containers_by_id: HashMap<String, (Option<_>, Vec<_>)> = HashMap::new();
|
||||
for container in containers {
|
||||
let labels = container.labels.clone().unwrap_or_default();
|
||||
if let Some(cloud_id) = labels.get("haze-cloud-id") {
|
||||
let mut entry = containers_by_id.entry(cloud_id.to_string()).or_default();
|
||||
if labels.get("haze-type").map(String::as_str) == Some("cloud") {
|
||||
entry.0 = Some(container);
|
||||
} else {
|
||||
entry.1.push(container)
|
||||
if match filter.as_ref() {
|
||||
Some(filter) => cloud_id.contains(filter),
|
||||
None => true,
|
||||
} {
|
||||
let mut entry = containers_by_id.entry(cloud_id.to_string()).or_default();
|
||||
if labels.get("haze-type").map(String::as_str) == Some("cloud") {
|
||||
entry.0 = Some(container);
|
||||
} else {
|
||||
entry.1.push(container)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(containers_by_id
|
||||
let mut sortable_containers: Vec<_> = containers_by_id
|
||||
.into_iter()
|
||||
.filter_map(|(id, (cloud, services))| {
|
||||
let cloud = cloud?;
|
||||
|
|
@ -555,15 +612,37 @@ pub async fn list(docker: &mut Docker, config: &HazeConfig) -> Result<Vec<Cloud>
|
|||
.filter_map(|service| service.names.as_ref()?.first().map(String::clone))
|
||||
.collect();
|
||||
service_ids.push(id.clone());
|
||||
Some(Cloud {
|
||||
id,
|
||||
network,
|
||||
db,
|
||||
php,
|
||||
containers: service_ids,
|
||||
ip: network_info.ip_address.as_ref()?.parse().ok()?,
|
||||
workdir,
|
||||
})
|
||||
Some((
|
||||
cloud.created.unwrap_or_default(),
|
||||
Cloud {
|
||||
id,
|
||||
network,
|
||||
db,
|
||||
php,
|
||||
containers: service_ids,
|
||||
ip: network_info.ip_address.as_ref()?.parse().ok(),
|
||||
workdir,
|
||||
},
|
||||
))
|
||||
})
|
||||
.collect();
|
||||
|
||||
sortable_containers.sort_by(|a, b| a.0.cmp(&b.0).reverse());
|
||||
|
||||
Ok(sortable_containers
|
||||
.into_iter()
|
||||
.map(|(_created, cloud)| cloud)
|
||||
.collect())
|
||||
}
|
||||
|
||||
pub async fn get_by_filter(
|
||||
docker: &mut Docker,
|
||||
filter: Option<String>,
|
||||
config: &HazeConfig,
|
||||
) -> Result<Cloud> {
|
||||
list(docker, filter, config)
|
||||
.await?
|
||||
.into_iter()
|
||||
.next()
|
||||
.ok_or(Report::msg("No clouds running matching filter"))
|
||||
}
|
||||
|
|
|
|||
38
src/main.rs
38
src/main.rs
|
|
@ -1,5 +1,5 @@
|
|||
use crate::args::{HazeArgs, HazeCommand};
|
||||
use crate::cloud::{list, Cloud, CloudOptions};
|
||||
use crate::cloud::{get_by_filter, list, Cloud, CloudOptions};
|
||||
use crate::config::HazeConfig;
|
||||
use bollard::Docker;
|
||||
use color_eyre::{eyre::WrapErr, Report, Result};
|
||||
|
|
@ -18,11 +18,10 @@ async fn main() -> Result<()> {
|
|||
};
|
||||
|
||||
let args = HazeArgs::parse(std::env::args())?;
|
||||
dbg!(&args);
|
||||
|
||||
match args.command {
|
||||
HazeCommand::Clean => {
|
||||
let list = list(&mut docker, &config).await?;
|
||||
let list = list(&mut docker, None, &config).await?;
|
||||
for cloud in list {
|
||||
if let Err(e) = cloud.destroy(&mut docker).await {
|
||||
eprintln!("Error while removing cloud: {:#}", e);
|
||||
|
|
@ -30,20 +29,28 @@ async fn main() -> Result<()> {
|
|||
}
|
||||
}
|
||||
HazeCommand::List => {
|
||||
let list = list(&mut docker, &config).await?;
|
||||
let list = list(&mut docker, args.options.first().cloned(), &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
|
||||
)
|
||||
match cloud.ip {
|
||||
Some(ip) => println!(
|
||||
"Cloud {}, {}, {}, running on http://{}",
|
||||
cloud.id,
|
||||
cloud.php.name(),
|
||||
cloud.db.name(),
|
||||
ip
|
||||
),
|
||||
None => println!(
|
||||
"Cloud {}, {}, {}, not running",
|
||||
cloud.id,
|
||||
cloud.php.name(),
|
||||
cloud.db.name()
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
HazeCommand::Start => {
|
||||
|
|
@ -52,7 +59,14 @@ async fn main() -> Result<()> {
|
|||
return Err(Report::msg(format!("Unknown option {}", next)));
|
||||
}
|
||||
let cloud = Cloud::create(&mut docker, options, &config).await?;
|
||||
println!("http://{}", cloud.ip);
|
||||
println!("http://{}", cloud.ip.unwrap());
|
||||
}
|
||||
HazeCommand::Logs => {
|
||||
let cloud = get_by_filter(&mut docker, args.options.first().cloned(), &config).await?;
|
||||
let logs = cloud.logs(&mut docker).await?;
|
||||
for log in logs {
|
||||
print!("{}", log);
|
||||
}
|
||||
}
|
||||
_ => todo!(),
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue