lldap/migration-tool/src/main.rs

208 lines
6.3 KiB
Rust

#![allow(clippy::uninlined_format_args)]
use std::collections::HashSet;
use anyhow::{anyhow, Result};
use requestty::{prompt_one, Question};
mod ldap;
mod lldap;
use ldap::LdapGroup;
use lldap::{LldapGroup, User};
fn ask_generic_confirmation(name: &str, message: &str) -> Result<bool> {
let confirm = Question::confirm(name)
.message(message)
.default(true)
.build();
let answer = prompt_one(confirm)?;
Ok(answer.as_bool().unwrap())
}
fn get_users_to_add(users: &[User], existing_users: &[String]) -> Result<Option<Vec<User>>> {
let existing_users = HashSet::<&String>::from_iter(existing_users);
let num_found_users = users.len();
let input_users: Vec<_> = users
.iter()
.filter(|u| !existing_users.contains(&u.user_input.id))
.map(User::clone)
.collect();
println!(
"Found {} users, of which {} new users: [\n {}\n]",
num_found_users,
input_users.len(),
input_users
.iter()
.map(|u| format!(
"\"{}\" ({})",
&u.user_input.id,
if u.password.is_some() {
"with password"
} else {
"no password"
}
))
.collect::<Vec<_>>()
.join(",\n ")
);
if !input_users.is_empty()
&& ask_generic_confirmation(
"proceed_users",
"Do you want to proceed to add those users to LLDAP?",
)?
{
Ok(Some(input_users))
} else {
Ok(None)
}
}
fn should_insert_groups(
input_groups: &[LdapGroup],
existing_groups: &[LldapGroup],
) -> Result<bool> {
let existing_group_names =
HashSet::<&str>::from_iter(existing_groups.iter().map(|g| g.display_name.as_str()));
let new_groups = input_groups
.iter()
.filter(|g| !existing_group_names.contains(g.name.as_str()));
let num_new_groups = new_groups.clone().count();
println!(
"Found {} groups, of which {} new groups: [\n {}\n]",
input_groups.len(),
num_new_groups,
new_groups
.map(|g| g.name.as_str())
.collect::<Vec<_>>()
.join(",\n ")
);
Ok(num_new_groups != 0
&& ask_generic_confirmation(
"proceed_groups",
"Do you want to proceed to add those groups to LLDAP?",
)?)
}
struct GroupList {
ldap_groups: Vec<LdapGroup>,
lldap_groups: Vec<LldapGroup>,
}
fn migrate_groups(
graphql_client: &lldap::GraphQLClient,
ldap_connection: &mut ldap::LdapClient,
) -> Result<Option<GroupList>> {
Ok(
if ask_generic_confirmation("should_import_groups", "Do you want to import groups?")? {
let mut existing_groups = lldap::get_lldap_groups(graphql_client)?;
let ldap_groups = ldap::get_groups(ldap_connection)?;
if should_insert_groups(&ldap_groups, &existing_groups)? {
lldap::insert_groups_into_lldap(
&ldap_groups,
&mut existing_groups,
graphql_client,
)?;
}
Some(GroupList {
ldap_groups,
lldap_groups: existing_groups,
})
} else {
None
},
)
}
struct UserList {
lldap_users: Vec<String>,
ldap_users: Vec<User>,
}
fn migrate_users(
graphql_client: &lldap::GraphQLClient,
ldap_connection: &mut ldap::LdapClient,
) -> Result<Option<UserList>> {
Ok(
if ask_generic_confirmation("should_import_users", "Do you want to import users?")? {
let mut existing_users = lldap::get_lldap_users(graphql_client)?;
let users = ldap::get_users(ldap_connection)?;
if let Some(users_to_add) = get_users_to_add(&users, &existing_users)? {
lldap::insert_users_into_lldap(users_to_add, &mut existing_users, graphql_client)?;
}
Some(UserList {
lldap_users: existing_users,
ldap_users: users,
})
} else {
None
},
)
}
fn migrate_memberships(
user_list: Option<UserList>,
group_list: Option<GroupList>,
graphql_client: lldap::GraphQLClient,
ldap_connection: &mut ldap::LdapClient,
) -> Result<()> {
let (ldap_users, existing_users) = user_list
.map(
|UserList {
ldap_users,
lldap_users,
}| (Some(ldap_users), Some(lldap_users)),
)
.unwrap_or_default();
let (ldap_groups, existing_groups) = group_list
.map(
|GroupList {
ldap_groups,
lldap_groups,
}| (Some(ldap_groups), Some(lldap_groups)),
)
.unwrap_or_default();
let ldap_users = ldap_users
.ok_or_else(|| anyhow!("Missing LDAP users"))
.or_else(|_| ldap::get_users(ldap_connection))?;
let ldap_groups = ldap_groups
.ok_or_else(|| anyhow!("Missing LDAP groups"))
.or_else(|_| ldap::get_groups(ldap_connection))?;
let existing_groups = existing_groups
.ok_or_else(|| anyhow!("Missing LLDAP groups"))
.or_else(|_| lldap::get_lldap_groups(&graphql_client))?;
let existing_users = existing_users
.ok_or_else(|| anyhow!("Missing LLDAP users"))
.or_else(|_| lldap::get_lldap_users(&graphql_client))?;
lldap::insert_group_memberships_into_lldap(
&ldap_users,
&ldap_groups,
&existing_users,
&existing_groups,
&graphql_client,
)?;
Ok(())
}
fn main() -> Result<()> {
println!(
"The migration tool requires access to both the original LDAP \
server and the HTTP API of the target LLDAP server."
);
if !ask_generic_confirmation("setup_ready", "Are you ready to start?")? {
return Ok(());
}
let mut ldap_connection = ldap::get_ldap_connection()?;
let graphql_client = lldap::get_lldap_client()?;
let user_list = migrate_users(&graphql_client, &mut ldap_connection)?;
let group_list = migrate_groups(&graphql_client, &mut ldap_connection)?;
if ask_generic_confirmation(
"should_import_memberships",
"Do you want to import group memberships?",
)? {
migrate_memberships(user_list, group_list, graphql_client, &mut ldap_connection)?;
}
Ok(())
}