From 2bdc7cd39a66d9973c749c467d04ae2fbf5ae4d0 Mon Sep 17 00:00:00 2001 From: mbecker20 Date: Tue, 25 Jul 2023 02:33:48 -0400 Subject: [PATCH 1/3] list updates for admin --- bin/core/src/helpers/mod.rs | 32 ++++++++++++++++++++++++++-- bin/core/src/requests/read/build.rs | 16 +++++++++++++- bin/core/src/requests/read/update.rs | 17 +++++++++++++-- lib/macros/src/lib.rs | 1 + lib/types/src/requests/read/build.rs | 2 +- 5 files changed, 62 insertions(+), 6 deletions(-) diff --git a/bin/core/src/helpers/mod.rs b/bin/core/src/helpers/mod.rs index ac92d5647..84f0c0168 100644 --- a/bin/core/src/helpers/mod.rs +++ b/bin/core/src/helpers/mod.rs @@ -17,14 +17,15 @@ use monitor_types::{ monitor_timestamp, permissioned::Permissioned, }; +use mungos::{mongodb::bson::doc, AggStage::*}; use periphery_client::{requests, PeripheryClient}; use rand::{thread_rng, Rng}; use crate::{auth::RequestUser, state::State}; +pub mod alert; pub mod cache; pub mod channel; -pub mod alert; pub mod db; pub fn empty_or_only_spaces(word: &str) -> bool { @@ -59,7 +60,6 @@ pub fn make_update( } impl State { - // USER pub async fn get_user(&self, user_id: &str) -> anyhow::Result { @@ -230,6 +230,34 @@ impl State { Ok(build.get_user_permissions(user_id)) } + pub async fn get_build_ids_for_non_admin(&self, user_id: &str) -> anyhow::Result> { + self.db + .builds + .aggregate_collect( + [ + Match(doc! { + format!("permissions.{}", user_id): { "$in": ["update", "execute", "read"] } + }), + Project(doc! { "_id": 1 }), + ], + None, + ) + .await + .context("failed to get build ids for non admin | aggregation")? + .into_iter() + .map(|d| { + let id = d + .get("_id") + .context("no _id field")? + .as_object_id() + .context("_id not ObjectId")? + .to_string(); + anyhow::Ok(id) + }) + .collect::>>() + .context("failed to get build ids for non admin | extract id from document") + } + // BUILDER pub async fn get_builder(&self, builder_id: &str) -> anyhow::Result { diff --git a/bin/core/src/requests/read/build.rs b/bin/core/src/requests/read/build.rs index ca56b40ea..d1adfb123 100644 --- a/bin/core/src/requests/read/build.rs +++ b/bin/core/src/requests/read/build.rs @@ -8,6 +8,7 @@ use monitor_types::{ permissioned::Permissioned, requests::read::*, }; +use mungos::mongodb::bson::doc; use resolver_api::Resolve; use crate::{auth::RequestUser, state::State}; @@ -79,6 +80,19 @@ impl Resolve for State { GetBuildsSummary {}: GetBuildsSummary, user: RequestUser, ) -> anyhow::Result { - todo!() + let query = if user.is_admin { + None + } else { + let doc = doc! { + + }; + Some(doc) + }; + let total = self.db.builds.collection.count_documents(query, None).await.context("failed to count all build documents")?; + + let res = GetBuildsSummaryResponse { + total: total as u32 + }; + Ok(res) } } diff --git a/bin/core/src/requests/read/update.rs b/bin/core/src/requests/read/update.rs index 39f99a406..abd1d2530 100644 --- a/bin/core/src/requests/read/update.rs +++ b/bin/core/src/requests/read/update.rs @@ -1,5 +1,6 @@ use async_trait::async_trait; use monitor_types::{entities::update::Update, requests::read::ListUpdates}; +use mungos::mongodb::{bson::doc, options::FindOptions}; use resolver_api::Resolve; use crate::{auth::RequestUser, state::State}; @@ -11,7 +12,19 @@ impl Resolve for State { ListUpdates { query }: ListUpdates, user: RequestUser, ) -> anyhow::Result> { - - todo!() + if user.is_admin { + let updates = self + .db + .updates + .get_some( + query, + FindOptions::builder().sort(doc! { "ts": -1 }).build(), + ) + .await?; + Ok(updates) + } else { + let build_ids = self.get_build_ids_for_non_admin(&user.id).await?; + todo!() + } } } diff --git a/lib/macros/src/lib.rs b/lib/macros/src/lib.rs index 737359aff..cfb7302d7 100644 --- a/lib/macros/src/lib.rs +++ b/lib/macros/src/lib.rs @@ -58,3 +58,4 @@ pub fn derive_crud_requests(input: proc_macro::TokenStream) -> proc_macro::Token } .into() } + diff --git a/lib/types/src/requests/read/build.rs b/lib/types/src/requests/read/build.rs index 83de192a1..55cee7700 100644 --- a/lib/types/src/requests/read/build.rs +++ b/lib/types/src/requests/read/build.rs @@ -57,5 +57,5 @@ pub struct GetBuildsSummary {} #[typeshare] #[derive(Serialize, Deserialize, Debug, Clone)] pub struct GetBuildsSummaryResponse { - pub total: I64, + pub total: u32, } From da246347745e6b280c53c680ff96beb5f6141877 Mon Sep 17 00:00:00 2001 From: mbecker20 Date: Tue, 25 Jul 2023 02:51:46 -0400 Subject: [PATCH 2/3] implement the summaries --- bin/core/src/requests/read/build.rs | 35 +++++++------ bin/core/src/requests/read/builder.rs | 19 ++++--- bin/core/src/requests/read/deployment.rs | 60 +++++++++++++++++------ bin/core/src/requests/read/repo.rs | 19 ++++--- bin/core/src/requests/read/server.rs | 57 ++++++++++++++++----- lib/types/src/requests/read/deployment.rs | 3 +- lib/types/src/requests/read/server.rs | 3 +- 7 files changed, 132 insertions(+), 64 deletions(-) diff --git a/bin/core/src/requests/read/build.rs b/bin/core/src/requests/read/build.rs index d1adfb123..debf1ef69 100644 --- a/bin/core/src/requests/read/build.rs +++ b/bin/core/src/requests/read/build.rs @@ -5,7 +5,6 @@ use monitor_types::{ build::{Build, BuildActionState}, PermissionLevel, }, - permissioned::Permissioned, requests::read::*, }; use mungos::mongodb::bson::doc; @@ -28,6 +27,14 @@ impl Resolve for State { ListBuilds { query }: ListBuilds, user: RequestUser, ) -> anyhow::Result> { + let mut query = query.unwrap_or_default(); + if !user.is_admin { + query.insert( + format!("permissions.{}", user.id), + doc! { "$in": ["read", "execute", "update"] }, + ); + } + let builds = self .db .builds @@ -35,15 +42,6 @@ impl Resolve for State { .await .context("failed to pull builds from mongo")?; - let builds = if user.is_admin { - builds - } else { - builds - .into_iter() - .filter(|build| build.get_user_permissions(&user.id) > PermissionLevel::None) - .collect() - }; - let builds = builds .into_iter() .map(|build| BuildListItem { @@ -83,15 +81,20 @@ impl Resolve for State { let query = if user.is_admin { None } else { - let doc = doc! { - + let query = doc! { + format!("permissions.{}", user.id): { "$in": ["read", "execute", "update"] } }; - Some(doc) + Some(query) }; - let total = self.db.builds.collection.count_documents(query, None).await.context("failed to count all build documents")?; - + let total = self + .db + .builds + .collection + .count_documents(query, None) + .await + .context("failed to count all build documents")?; let res = GetBuildsSummaryResponse { - total: total as u32 + total: total as u32, }; Ok(res) } diff --git a/bin/core/src/requests/read/builder.rs b/bin/core/src/requests/read/builder.rs index f8327c23a..b4d12fbd2 100644 --- a/bin/core/src/requests/read/builder.rs +++ b/bin/core/src/requests/read/builder.rs @@ -2,9 +2,9 @@ use anyhow::Context; use async_trait::async_trait; use monitor_types::{ entities::{builder::Builder, PermissionLevel}, - permissioned::Permissioned, requests::read::*, }; +use mungos::mongodb::bson::doc; use resolver_api::Resolve; use crate::{auth::RequestUser, state::State}; @@ -28,6 +28,14 @@ impl Resolve for State { ListBuilders { query }: ListBuilders, user: RequestUser, ) -> anyhow::Result> { + let mut query = query.unwrap_or_default(); + if !user.is_admin { + query.insert( + format!("permissions.{}", user.id), + doc! { "$in": ["read", "execute", "update"] }, + ); + } + let builders = self .db .builders @@ -35,15 +43,6 @@ impl Resolve for State { .await .context("failed to pull builders from mongo")?; - let builders = if user.is_admin { - builders - } else { - builders - .into_iter() - .filter(|builder| builder.get_user_permissions(&user.id) > PermissionLevel::None) - .collect() - }; - Ok(builders) } } diff --git a/bin/core/src/requests/read/deployment.rs b/bin/core/src/requests/read/deployment.rs index 0c947c1d9..2c085a841 100644 --- a/bin/core/src/requests/read/deployment.rs +++ b/bin/core/src/requests/read/deployment.rs @@ -7,12 +7,11 @@ use monitor_types::{ entities::{ deployment::{ Deployment, DeploymentActionState, DeploymentConfig, DeploymentImage, - DockerContainerStats, + DockerContainerState, DockerContainerStats, }, update::{Log, UpdateStatus}, Operation, PermissionLevel, }, - permissioned::Permissioned, requests::read::*, }; use mungos::mongodb::{bson::doc, options::FindOneOptions}; @@ -40,6 +39,13 @@ impl Resolve for State { ListDeployments { query }: ListDeployments, user: RequestUser, ) -> anyhow::Result> { + let mut query = query.unwrap_or_default(); + if !user.is_admin { + query.insert( + format!("permissions.{}", user.id), + doc! { "$in": ["read", "execute", "update"] }, + ); + } let deployments = self .db .deployments @@ -47,17 +53,6 @@ impl Resolve for State { .await .context("failed to pull deployments from mongo")?; - let deployments = if user.is_admin { - deployments - } else { - deployments - .into_iter() - .filter(|deployment| { - deployment.get_user_permissions(&user.id) > PermissionLevel::None - }) - .collect() - }; - let deployments = deployments.into_iter().map(|deployment| async { let status = self.deployment_status_cache.get(&deployment.id).await; DeploymentListItem { @@ -240,6 +235,43 @@ impl Resolve for State { GetDeploymentsSummary {}: GetDeploymentsSummary, user: RequestUser, ) -> anyhow::Result { - todo!() + let query = if user.is_admin { + None + } else { + let query = doc! { + format!("permissions.{}", user.id): { "$in": ["read", "execute", "update"] } + }; + Some(query) + }; + let deployments = self + .db + .deployments + .get_some(query, None) + .await + .context("failed to count all deployment documents")?; + let mut res = GetDeploymentsSummaryResponse::default(); + for deployment in deployments { + res.total += 1; + let status = self + .deployment_status_cache + .get(&deployment.id) + .await + .unwrap_or_default(); + match status.state { + DockerContainerState::Running => { + res.running += 1; + } + DockerContainerState::Unknown => { + res.unknown += 1; + } + DockerContainerState::NotDeployed => { + res.not_deployed += 1; + } + _ => { + res.stopped += 1; + } + } + } + Ok(res) } } diff --git a/bin/core/src/requests/read/repo.rs b/bin/core/src/requests/read/repo.rs index 21a51b61a..c4653b194 100644 --- a/bin/core/src/requests/read/repo.rs +++ b/bin/core/src/requests/read/repo.rs @@ -5,9 +5,9 @@ use monitor_types::{ repo::{Repo, RepoActionState}, PermissionLevel, }, - permissioned::Permissioned, requests::read::*, }; +use mungos::mongodb::bson::doc; use resolver_api::Resolve; use crate::{auth::RequestUser, state::State}; @@ -27,6 +27,14 @@ impl Resolve for State { ListRepos { query }: ListRepos, user: RequestUser, ) -> anyhow::Result> { + let mut query = query.unwrap_or_default(); + if !user.is_admin { + query.insert( + format!("permissions.{}", user.id), + doc! { "$in": ["read", "execute", "update"] }, + ); + } + let repos = self .db .repos @@ -34,15 +42,6 @@ impl Resolve for State { .await .context("failed to pull repos from mongo")?; - let repos = if user.is_admin { - repos - } else { - repos - .into_iter() - .filter(|repo| repo.get_user_permissions(&user.id) > PermissionLevel::None) - .collect() - }; - let repos = repos .into_iter() .map(|repo| RepoListItem { diff --git a/bin/core/src/requests/read/server.rs b/bin/core/src/requests/read/server.rs index a2aa127ce..84166a254 100644 --- a/bin/core/src/requests/read/server.rs +++ b/bin/core/src/requests/read/server.rs @@ -6,13 +6,13 @@ use monitor_types::{ deployment::ContainerSummary, server::{ docker_image::ImageSummary, docker_network::DockerNetwork, stats::SystemInformation, - Server, ServerActionState, + Server, ServerActionState, ServerStatus, }, PermissionLevel, }, - permissioned::Permissioned, requests::read::*, }; +use mungos::mongodb::bson::doc; use periphery_client::requests; use resolver_api::{Resolve, ResolveToString}; @@ -52,6 +52,14 @@ impl Resolve for State { ListServers { query }: ListServers, user: RequestUser, ) -> anyhow::Result> { + let mut query = query.unwrap_or_default(); + if !user.is_admin { + query.insert( + format!("permissions.{}", user.id), + doc! { "$in": ["read", "execute", "update"] }, + ); + } + let servers = self .db .servers @@ -59,15 +67,6 @@ impl Resolve for State { .await .context("failed to pull servers from mongo")?; - let servers = if user.is_admin { - servers - } else { - servers - .into_iter() - .filter(|server| server.get_user_permissions(&user.id) > PermissionLevel::None) - .collect() - }; - let servers = servers.into_iter().map(|server| async { let status = self.server_status_cache.get(&server.id).await; ServerListItem { @@ -351,6 +350,40 @@ impl Resolve for State { GetServersSummary {}: GetServersSummary, user: RequestUser, ) -> anyhow::Result { - todo!() + let query = if user.is_admin { + None + } else { + let query = doc! { + format!("permissions.{}", user.id): { "$in": ["read", "execute", "update"] } + }; + Some(query) + }; + let servers = self + .db + .servers + .get_some(query, None) + .await + .context("failed to get servers from db")?; + let mut res = GetServersSummaryResponse::default(); + for server in servers { + res.total += 1; + let status = self + .server_status_cache + .get(&server.id) + .await + .unwrap_or_default(); + match status.status { + ServerStatus::Ok => { + res.healthy += 1; + } + ServerStatus::NotOk => { + res.unhealthy += 1; + } + ServerStatus::Disabled => { + res.disabled += 1; + } + } + } + Ok(res) } } diff --git a/lib/types/src/requests/read/deployment.rs b/lib/types/src/requests/read/deployment.rs index 851088f00..988b88d00 100644 --- a/lib/types/src/requests/read/deployment.rs +++ b/lib/types/src/requests/read/deployment.rs @@ -114,10 +114,11 @@ pub struct GetDeploymentActionState { pub struct GetDeploymentsSummary {} #[typeshare] -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, Default)] pub struct GetDeploymentsSummaryResponse { pub total: I64, pub running: I64, pub stopped: I64, + pub not_deployed: I64, pub unknown: I64, } diff --git a/lib/types/src/requests/read/server.rs b/lib/types/src/requests/read/server.rs index 88480308b..c2dfd9790 100644 --- a/lib/types/src/requests/read/server.rs +++ b/lib/types/src/requests/read/server.rs @@ -191,9 +191,10 @@ pub struct GetDockerContainers { pub struct GetServersSummary {} #[typeshare] -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, Default)] pub struct GetServersSummaryResponse { pub total: I64, pub healthy: I64, pub unhealthy: I64, + pub disabled: I64, } From 91a6485c206dd3e9e9b1cb4454649468d083f659 Mon Sep 17 00:00:00 2001 From: mbecker20 Date: Tue, 25 Jul 2023 02:53:34 -0400 Subject: [PATCH 3/3] add other status cases for summaries --- client/ts/src/types.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/client/ts/src/types.ts b/client/ts/src/types.ts index 7ba97b698..004884a22 100644 --- a/client/ts/src/types.ts +++ b/client/ts/src/types.ts @@ -749,7 +749,7 @@ export interface GetBuildsSummary { } export interface GetBuildsSummaryResponse { - total: I64; + total: number; } export interface GetBuilder { @@ -822,6 +822,7 @@ export interface GetDeploymentsSummaryResponse { total: I64; running: I64; stopped: I64; + not_deployed: I64; unknown: I64; } @@ -974,6 +975,7 @@ export interface GetServersSummaryResponse { total: I64; healthy: I64; unhealthy: I64; + disabled: I64; } export interface GetTag {