Verified Commit 7ab61c71 authored by Levente Polyak's avatar Levente Polyak 🚀
Browse files

wip: shared state

parent 62f9e811
...@@ -21,6 +21,7 @@ use structopt::StructOpt; ...@@ -21,6 +21,7 @@ use structopt::StructOpt;
use anyhow::Result; use anyhow::Result;
use env_logger::Env; use env_logger::Env;
use log::error; use log::error;
use std::sync::{Arc, Mutex};
async fn run(args: Args) -> Result<()> { async fn run(args: Args) -> Result<()> {
/* Early exit for completions */ /* Early exit for completions */
...@@ -32,26 +33,29 @@ async fn run(args: Args) -> Result<()> { ...@@ -32,26 +33,29 @@ async fn run(args: Args) -> Result<()> {
_ => {} _ => {}
} }
let mut state = State::new(); let state = Arc::new(Mutex::new(State::new()));
//let keycloak_glue = Keycloak::new().await?;
let gitlab_glue = GitLabGlue::new().await?;
//keycloak_glue.gather(&mut state).await?; let keycloak_glue = Keycloak::new(state.clone()).await?;
gitlab_glue.gather(&mut state).await?; let gitlab_glue = GitLabGlue::new(state.clone()).await?;
keycloak_glue.gather().await?;
gitlab_glue.gather().await?;
match args.command { match args.command {
Command::Completions(_) => {} Command::Completions(_) => {}
Command::Keycloak(action) => { Command::Keycloak(action) => {
//keycloak_glue.run(&state, action).await?; keycloak_glue.run(action).await?;
} }
Command::Gitlab(action) => gitlab_glue.run(&state, action).await?, Command::Gitlab(action) => {
gitlab_glue.run(action).await?
},
Command::Plan => { Command::Plan => {
//keycloak_glue.run(&state, Action::Plan).await?; keycloak_glue.run(Action::Plan).await?;
gitlab_glue.run(&state, Action::Plan).await?; gitlab_glue.run(Action::Plan).await?;
} }
Command::Apply => { Command::Apply => {
//keycloak_glue.run(&state, Action::Apply).await?; keycloak_glue.run(Action::Apply).await?;
gitlab_glue.run(&state, Action::Apply).await?; gitlab_glue.run(Action::Apply).await?;
} }
} }
Ok(()) Ok(())
......
...@@ -23,43 +23,38 @@ use gitlab::api::common::{AccessLevel, VisibilityLevel}; ...@@ -23,43 +23,38 @@ use gitlab::api::common::{AccessLevel, VisibilityLevel};
use gitlab::api::projects::{Projects, FeatureAccessLevel}; use gitlab::api::projects::{Projects, FeatureAccessLevel};
use gitlab::api::groups::members::{GroupMembers, AddGroupMember, RemoveGroupMember}; use gitlab::api::groups::members::{GroupMembers, AddGroupMember, RemoveGroupMember};
use tokio::task; use tokio::task;
use std::sync::{Arc, Mutex};
const MAIN_BRANCH: &str = "main"; const MAIN_BRANCH: &str = "main";
const ALL_TAGS: &str = "*"; const ALL_TAGS: &str = "*";
pub struct GitLabGlue { pub struct GitLabGlue {
client: Gitlab, client: Gitlab,
state: Arc<Mutex<State>>,
} }
impl GitLabGlue { impl GitLabGlue {
pub async fn new() -> Result<GitLabGlue> { pub async fn new(state: Arc<Mutex<State>>) -> Result<GitLabGlue> {
task::spawn_blocking(move || create_client()).await? create_client(state)
} }
pub async fn gather<'a>(&'a self, state: &mut State<'a>) -> Result<()> { pub async fn gather(&self) -> Result<()> {
Ok(()) Ok(())
} }
pub async fn run<'a>(&self, state: &State<'a>, action: Action) -> Result<()> { pub async fn run<'a>(&self, action: Action) -> Result<()> {
task::spawn_blocking(move || update_gitlab_group_members(&action)).await??; self.update_gitlab_group_members(&action).await?;
/*
task::spawn_blocking(move || {
update_gitlab_group_members(guard, &action)
}).await??;
*/
//task::spawn_blocking(move || update_package_repositories(&action)).await??; //task::spawn_blocking(move || update_package_repositories(&action)).await??;
Ok(()) Ok(())
} }
}
pub fn create_client() -> Result<GitLabGlue> { async fn update_gitlab_group_members(&self, action: &Action) -> Result<()> {
let token =
&env::var("GLUEBUDDY_GITLAB_TOKEN").context("Missing env var GLUEBUDDY_GITLAB_TOKEN")?;
let client = Gitlab::new("gitlab.archlinux.org", token).unwrap();
Ok(GitLabGlue { client })
}
/*
fn protect_tags(client: &Gitlab, project_id: u64) -> std::result::Result<ProtectedTag, gitlab::api::ApiError<>> {
}
*/
fn update_gitlab_group_members(action: &Action) -> Result<()> {
let token = let token =
&env::var("GLUEBUDDY_GITLAB_TOKEN").context("Missing env var GLUEBUDDY_GITLAB_TOKEN")?; &env::var("GLUEBUDDY_GITLAB_TOKEN").context("Missing env var GLUEBUDDY_GITLAB_TOKEN")?;
let client = Gitlab::new("gitlab.archlinux.org", token).unwrap(); let client = Gitlab::new("gitlab.archlinux.org", token).unwrap();
...@@ -71,8 +66,17 @@ fn update_gitlab_group_members(action: &Action) -> Result<()> { ...@@ -71,8 +66,17 @@ fn update_gitlab_group_members(action: &Action) -> Result<()> {
.build() .build()
.unwrap(); .unwrap();
let members: Vec<GroupMember> = members_endpoint.query(&client).unwrap(); let members: Vec<GroupMember> = members_endpoint.query(&client).unwrap();
for member in members { for member in &members {
println!("{} {} {} {}", member.id, member.username, member.email.unwrap_or("-".to_string()), member.access_level); println!("{} {} {} {}", member.id, member.username, member.email.as_ref().unwrap_or(&"-".to_string()), member.access_level);
}
let state = self.state.lock().unwrap();
for staff in &state.staff {
let member_names = members.iter().map(|e| e.username.clone()).collect::<Vec<_>>();
let staff_username = &staff.username;
if !member_names.contains(&staff_username) {
println!("not in group: {}", staff_username);
}
} }
println!("project"); println!("project");
...@@ -83,7 +87,7 @@ fn update_gitlab_group_members(action: &Action) -> Result<()> { ...@@ -83,7 +87,7 @@ fn update_gitlab_group_members(action: &Action) -> Result<()> {
.unwrap(); .unwrap();
let members: Vec<GroupMember> = members_endpoint.query(&client).unwrap(); let members: Vec<GroupMember> = members_endpoint.query(&client).unwrap();
for member in members { for member in members {
println!("{} {} {} {}", member.id, member.username, member.email.unwrap_or("-".to_string()), member.access_level); println!("{} {} {} {}", member.id, member.username, member.email.as_ref().unwrap_or(&"-".to_string()), member.access_level);
} }
println!("search"); println!("search");
...@@ -129,7 +133,6 @@ fn update_gitlab_group_members(action: &Action) -> Result<()> { ...@@ -129,7 +133,6 @@ fn update_gitlab_group_members(action: &Action) -> Result<()> {
.build() .build()
.unwrap(); .unwrap();
gitlab::api::ignore(endpoint).query(&client).unwrap(); gitlab::api::ignore(endpoint).query(&client).unwrap();
*/
let endpoint = gitlab::api::projects::members::EditProjectMember::builder() let endpoint = gitlab::api::projects::members::EditProjectMember::builder()
.project("bot-test/sandbox/lib10000") .project("bot-test/sandbox/lib10000")
...@@ -138,10 +141,19 @@ fn update_gitlab_group_members(action: &Action) -> Result<()> { ...@@ -138,10 +141,19 @@ fn update_gitlab_group_members(action: &Action) -> Result<()> {
.build() .build()
.unwrap(); .unwrap();
gitlab::api::ignore(endpoint).query(&client).unwrap(); gitlab::api::ignore(endpoint).query(&client).unwrap();
*/
} }
Ok(()) Ok(())
} }
}
pub fn create_client(state: Arc<Mutex<State>>) -> Result<GitLabGlue> {
let token =
&env::var("GLUEBUDDY_GITLAB_TOKEN").context("Missing env var GLUEBUDDY_GITLAB_TOKEN")?;
let client = Gitlab::new("gitlab.archlinux.org", token).unwrap();
Ok(GitLabGlue { client, state })
}
fn update_package_repositories(action: &Action) -> Result<()> { fn update_package_repositories(action: &Action) -> Result<()> {
let token = let token =
...@@ -308,7 +320,7 @@ fn update_package_repositories(action: &Action) -> Result<()> { ...@@ -308,7 +320,7 @@ fn update_package_repositories(action: &Action) -> Result<()> {
} }
*/ */
set_project_settings(&client, &project); set_project_settings(&client, &project)?;
} }
} }
......
...@@ -18,14 +18,17 @@ use log::{debug, info}; ...@@ -18,14 +18,17 @@ use log::{debug, info};
use std::env; use std::env;
use crate::state::State; use crate::state::State;
use crate::state::User;
use std::sync::{Mutex, Arc};
pub struct Keycloak<'a> { pub struct Keycloak<'a> {
admin: KeycloakAdmin<'a>, admin: KeycloakAdmin<'a>,
realm: String, realm: String,
state: Arc<Mutex<State>>,
} }
impl Keycloak<'_> { impl<'a> Keycloak<'a> {
pub async fn new<'a>() -> Result<Keycloak<'a>> { pub async fn new(state: Arc<Mutex<State>>) -> Result<Keycloak<'a>> {
let username = &env::var("GLUEBUDDY_KEYCLOAK_USERNAME") let username = &env::var("GLUEBUDDY_KEYCLOAK_USERNAME")
.context("Missing env var GLUEBUDDY_KEYCLOAK_USERNAME")?; .context("Missing env var GLUEBUDDY_KEYCLOAK_USERNAME")?;
let password = &env::var("GLUEBUDDY_KEYCLOAK_PASSWORD") let password = &env::var("GLUEBUDDY_KEYCLOAK_PASSWORD")
...@@ -47,10 +50,11 @@ impl Keycloak<'_> { ...@@ -47,10 +50,11 @@ impl Keycloak<'_> {
Ok(Keycloak { Ok(Keycloak {
admin, admin,
realm: realm.to_string(), realm: realm.to_string(),
state,
}) })
} }
pub async fn gather<'a>(&'a self, state: &mut State<'a>) -> Result<()> { pub async fn gather(&self) -> Result<()> {
let root_groups = vec!["Arch Linux Staff", "External Contributors"]; let root_groups = vec!["Arch Linux Staff", "External Contributors"];
let all_groups = self let all_groups = self
...@@ -89,6 +93,7 @@ impl Keycloak<'_> { ...@@ -89,6 +93,7 @@ impl Keycloak<'_> {
}); });
let group_members = try_join_all(groups_members).await?; let group_members = try_join_all(groups_members).await?;
let mut state = self.state.lock().unwrap();
// TODO: avoid duplicates in staff when multiple groups match // TODO: avoid duplicates in staff when multiple groups match
for (group, users) in group_members { for (group, users) in group_members {
...@@ -99,26 +104,26 @@ impl Keycloak<'_> { ...@@ -99,26 +104,26 @@ impl Keycloak<'_> {
group_name, group_name,
user.username.as_ref().unwrap() user.username.as_ref().unwrap()
); );
match group_name.as_ref() { match group_name {
"DevOps" => { "DevOps" => {
state.staff.push(user.clone()); state.staff.push(User::new(user.username.as_ref().unwrap().to_string()));
state.devops.push(user.clone()); state.devops.push(User::new(user.username.as_ref().unwrap().to_string()));
} }
"Developers" => { "Developers" => {
state.staff.push(user.clone()); state.staff.push(User::new(user.username.as_ref().unwrap().to_string()));
state.developers.push(user.clone()); state.developers.push(User::new(user.username.as_ref().unwrap().to_string()));
} }
"Trusted Users" => { "Trusted Users" => {
state.staff.push(user.clone()); state.staff.push(User::new(user.username.as_ref().unwrap().to_string()));
state.trusted_users.push(user.clone()); state.trusted_users.push(User::new(user.username.as_ref().unwrap().to_string()));
} }
"Security Team" => { "Security Team" => {
// TODO: do not add reporters // TODO: do not add reporters
state.staff.push(user.clone()); state.staff.push(User::new(user.username.as_ref().unwrap().to_string()));
state.security_team.push(user.clone()); state.security_team.push(User::new(user.username.as_ref().unwrap().to_string()));
} }
"External Contributors" => { "External Contributors" => {
state.external_contributors.push(user.clone()); state.external_contributors.push(User::new(user.username.as_ref().unwrap().to_string()));
} }
_ => {} _ => {}
} }
...@@ -128,7 +133,7 @@ impl Keycloak<'_> { ...@@ -128,7 +133,7 @@ impl Keycloak<'_> {
Ok(()) Ok(())
} }
pub async fn run<'a>(&self, state: &State<'a>, action: Action) -> Result<()> { pub async fn run(&self, action: Action) -> Result<()> {
Ok(()) Ok(())
} }
} }
......
use keycloak::types::UserRepresentation; use keycloak::types::UserRepresentation;
pub struct State<'a> { pub struct User {
pub staff: Vec<UserRepresentation<'a>>, pub username: String,
pub developers: Vec<UserRepresentation<'a>>,
pub trusted_users: Vec<UserRepresentation<'a>>,
pub devops: Vec<UserRepresentation<'a>>,
pub security_team: Vec<UserRepresentation<'a>>,
pub external_contributors: Vec<UserRepresentation<'a>>,
} }
impl State<'_> { impl User {
pub fn new<'a>() -> State<'a> { pub fn new(username: String) -> User {
User {
username,
}
}
}
pub struct State {
pub staff: Vec<User>,
pub developers: Vec<User>,
pub trusted_users: Vec<User>,
pub devops: Vec<User>,
pub security_team: Vec<User>,
pub external_contributors: Vec<User>,
}
impl State {
pub fn new() -> State {
State { State {
staff: Vec::new(), staff: Vec::new(),
developers: Vec::new(), developers: Vec::new(),
...@@ -24,7 +36,6 @@ impl State<'_> { ...@@ -24,7 +36,6 @@ impl State<'_> {
pub fn user_may_have_gitlab_access(&self, username: &str) -> bool { pub fn user_may_have_gitlab_access(&self, username: &str) -> bool {
self.staff.iter() self.staff.iter()
.chain(self.external_contributors.iter()) .chain(self.external_contributors.iter())
.map(|e| e.username.as_ref().unwrap()) .any(|e| e.username.eq(username))
.any(|e| e.eq(username))
} }
} }
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment