use tokio_postgres::Client; use crate::ergo_admin; use crate::types::DefaultNetworkSpec; pub async fn sync_default_networks( kube: &kube::Client, namespace: &str, tenant_uri: &str, default_network: &DefaultNetworkSpec, ) -> Result<(), String> { let (client, connection) = tokio_postgres::connect(tenant_uri, tokio_postgres::NoTls) .await .map_err(|e| format!("soju db connect failed: {e}"))?; tokio::spawn(async move { if let Err(e) = connection.await { tracing::warn!("soju db connection error: {e}"); } }); sync_max_networks(&client).await; sync_users_networks(kube, namespace, &client, default_network).await; Ok(()) } async fn sync_max_networks(client: &Client) { match client .execute( r#"UPDATE "User" SET max_networks = 1 WHERE max_networks != 1 OR max_networks IS NULL"#, &[], ) .await { Ok(n) => { if n > 0 { tracing::info!("synced max_networks=1 for {n} users"); } } Err(e) => tracing::warn!("max_networks sync failed: {e}"), } } async fn sync_users_networks( kube: &kube::Client, namespace: &str, client: &Client, spec: &DefaultNetworkSpec, ) { let rows = match client .query( r#"SELECT u.id, u.username FROM "User" u LEFT JOIN "Network" n ON n."user" = u.id AND n.name = $1 WHERE n.id IS NULL"#, &[&spec.name], ) .await { Ok(r) => r, Err(e) => { tracing::warn!("failed to query users without default network: {e}"); return; } }; let ergo_port = spec.ergo_port.unwrap_or(6667); for row in &rows { let user_id: i32 = row.get("id"); let username: String = row.get("username"); let nick = match ergo_admin::nick_from_username(&username) { Some(n) => n, None => { tracing::warn!("cannot derive IRC nick from '{username}', skipping"); continue; } }; let password = ergo_admin::generate_password(); if let Err(e) = ergo_admin::ensure_ergo_account( kube, namespace, &spec.ergo_service, ergo_port, &spec.oper_secret, &nick, &password, ) .await { tracing::warn!("ergo account setup for '{nick}' failed: {e}"); continue; } match client .execute( r#"INSERT INTO "Network" ("user", name, addr, nick, enabled, sasl_mechanism, sasl_plain_username, sasl_plain_password) VALUES ($1, $2, $3, $4, true, 'PLAIN', $4, $5) ON CONFLICT (name, "user") DO NOTHING"#, &[&user_id, &spec.name, &spec.addr, &nick, &password], ) .await { Ok(_) => tracing::info!( "created default '{}' network for user '{username}' (nick: {nick})", spec.name ), Err(e) => tracing::warn!("network insert for '{username}' failed: {e}"), } } }