forked from github-starred/komodo
implement list resources with ListItem on Resource trait
This commit is contained in:
@@ -12,7 +12,7 @@ pub async fn send_alert(alerter: &Alerter, alert: &Alert) -> anyhow::Result<()>
|
||||
|
||||
pub async fn send_slack_alert(url: &str, alert: &Alert) -> anyhow::Result<()> {
|
||||
let (text, blocks) = match alert {
|
||||
Alert::ServerUnreachable { id, name, region } => {
|
||||
Alert::ServerUnreachable { name, region, .. } => {
|
||||
let region = fmt_region(region);
|
||||
let text = format!("CRITICAL 🚨 | *{name}*{region} is *unreachable* ❌");
|
||||
let blocks = vec![
|
||||
@@ -22,12 +22,12 @@ pub async fn send_slack_alert(url: &str, alert: &Alert) -> anyhow::Result<()> {
|
||||
(text, blocks.into())
|
||||
}
|
||||
Alert::ServerCpu {
|
||||
id,
|
||||
name,
|
||||
region,
|
||||
state,
|
||||
percentage,
|
||||
top_procs,
|
||||
..
|
||||
} => {
|
||||
let region = fmt_region(region);
|
||||
let text =
|
||||
@@ -42,13 +42,13 @@ pub async fn send_slack_alert(url: &str, alert: &Alert) -> anyhow::Result<()> {
|
||||
(text, blocks.into())
|
||||
}
|
||||
Alert::ServerMem {
|
||||
id,
|
||||
name,
|
||||
region,
|
||||
state,
|
||||
used_gb,
|
||||
total_gb,
|
||||
top_procs,
|
||||
..
|
||||
} => {
|
||||
let region = fmt_region(region);
|
||||
let percentage = 100.0 * used_gb / total_gb;
|
||||
@@ -65,13 +65,13 @@ pub async fn send_slack_alert(url: &str, alert: &Alert) -> anyhow::Result<()> {
|
||||
(text, blocks.into())
|
||||
}
|
||||
Alert::ServerDisk {
|
||||
id,
|
||||
name,
|
||||
region,
|
||||
state,
|
||||
path,
|
||||
used_gb,
|
||||
total_gb,
|
||||
..
|
||||
} => {
|
||||
let region = fmt_region(region);
|
||||
let percentage = 100.0 * used_gb / total_gb;
|
||||
|
||||
@@ -28,7 +28,7 @@ impl Resolve<ListAlerters, RequestUser> for State {
|
||||
ListAlerters { query }: ListAlerters,
|
||||
user: RequestUser,
|
||||
) -> anyhow::Result<Vec<Alerter>> {
|
||||
self.list_resources_for_user(&user, query).await
|
||||
<State as Resource<Alerter>>::list_resources_for_user(self, &user, query).await
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -31,20 +31,7 @@ impl Resolve<ListBuilds, RequestUser> for State {
|
||||
ListBuilds { query }: ListBuilds,
|
||||
user: RequestUser,
|
||||
) -> anyhow::Result<Vec<BuildListItem>> {
|
||||
let builds: Vec<Build> = self.list_resources_for_user(&user, query).await?;
|
||||
|
||||
let builds = builds
|
||||
.into_iter()
|
||||
.map(|build| BuildListItem {
|
||||
id: build.id,
|
||||
name: build.name,
|
||||
last_built_at: build.last_built_at,
|
||||
version: build.config.version,
|
||||
tags: build.tags,
|
||||
})
|
||||
.collect();
|
||||
|
||||
Ok(builds)
|
||||
<State as Resource<Build>>::list_resources_for_user(self, &user, query).await
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ impl Resolve<ListBuilders, RequestUser> for State {
|
||||
ListBuilders { query }: ListBuilders,
|
||||
user: RequestUser,
|
||||
) -> anyhow::Result<Vec<Builder>> {
|
||||
self.list_resources_for_user(&user, query).await
|
||||
<State as Resource<Builder>>::list_resources_for_user(self, &user, query).await
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@ use std::cmp;
|
||||
|
||||
use anyhow::{anyhow, Context};
|
||||
use async_trait::async_trait;
|
||||
use futures::future::join_all;
|
||||
use monitor_types::{
|
||||
entities::{
|
||||
deployment::{
|
||||
@@ -40,26 +39,7 @@ impl Resolve<ListDeployments, RequestUser> for State {
|
||||
ListDeployments { query }: ListDeployments,
|
||||
user: RequestUser,
|
||||
) -> anyhow::Result<Vec<DeploymentListItem>> {
|
||||
let deployments: Vec<Deployment> = self.list_resources_for_user(&user, query).await?;
|
||||
|
||||
let deployments = deployments.into_iter().map(|deployment| async {
|
||||
let status = self.deployment_status_cache.get(&deployment.id).await;
|
||||
DeploymentListItem {
|
||||
id: deployment.id,
|
||||
name: deployment.name,
|
||||
tags: deployment.tags,
|
||||
state: status.as_ref().map(|s| s.state).unwrap_or_default(),
|
||||
status: status
|
||||
.as_ref()
|
||||
.and_then(|s| s.container.as_ref().and_then(|c| c.status.to_owned())),
|
||||
image: String::new(),
|
||||
version: String::new(),
|
||||
}
|
||||
});
|
||||
|
||||
let deployments = join_all(deployments).await;
|
||||
|
||||
Ok(deployments)
|
||||
<State as Resource<Deployment>>::list_resources_for_user(self, &user, query).await
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -27,19 +27,7 @@ impl Resolve<ListRepos, RequestUser> for State {
|
||||
ListRepos { query }: ListRepos,
|
||||
user: RequestUser,
|
||||
) -> anyhow::Result<Vec<RepoListItem>> {
|
||||
let repos: Vec<Repo> = self.list_resources_for_user(&user, query).await?;
|
||||
|
||||
let repos = repos
|
||||
.into_iter()
|
||||
.map(|repo| RepoListItem {
|
||||
id: repo.id,
|
||||
name: repo.name,
|
||||
last_pulled_at: repo.last_pulled_at,
|
||||
tags: repo.tags,
|
||||
})
|
||||
.collect();
|
||||
|
||||
Ok(repos)
|
||||
<State as Resource<Repo>>::list_resources_for_user(self, &user, query).await
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,22 +4,63 @@ use anyhow::{anyhow, Context};
|
||||
use async_trait::async_trait;
|
||||
use monitor_types::{
|
||||
entities::{
|
||||
server,
|
||||
tag::Tag,
|
||||
update::ResourceTargetVariant::{self, *},
|
||||
PermissionLevel,
|
||||
},
|
||||
permissioned::Permissioned,
|
||||
requests::read::{
|
||||
BuildListItem, DeploymentListItem, FindResources, FindResourcesResponse, RepoListItem,
|
||||
ServerListItem,
|
||||
BuildListItem, DeploymentListItem, FindResources, FindResources2, FindResourcesResponse,
|
||||
RepoListItem, ServerListItem,
|
||||
},
|
||||
};
|
||||
use mungos::mongodb::bson::{doc, oid::ObjectId};
|
||||
use resolver_api::Resolve;
|
||||
|
||||
use crate::{auth::RequestUser, state::State};
|
||||
use crate::{auth::RequestUser, resource::Resource, state::State};
|
||||
|
||||
const ALL_RESOURCE_TYPES: [ResourceTargetVariant; 4] = [Server, Build, Deployment, Repo];
|
||||
const FIND_RESOURCE_TYPES: [ResourceTargetVariant; 4] = [Server, Build, Deployment, Repo];
|
||||
|
||||
#[async_trait]
|
||||
impl Resolve<FindResources2, RequestUser> for State {
|
||||
async fn resolve(
|
||||
&self,
|
||||
FindResources2 { query, resources }: FindResources2,
|
||||
user: RequestUser,
|
||||
) -> anyhow::Result<FindResourcesResponse> {
|
||||
let mut res = FindResourcesResponse::default();
|
||||
let resource_types = resources
|
||||
.map(|rs| {
|
||||
rs.into_iter()
|
||||
.filter(|r| !matches!(r, System | Builder | Alerter))
|
||||
.collect()
|
||||
})
|
||||
.unwrap_or(FIND_RESOURCE_TYPES.to_vec());
|
||||
for resource_type in resource_types {
|
||||
match resource_type {
|
||||
Server => {
|
||||
// let servers: Vec<server::Server> =
|
||||
// self.list_resources_for_user(&user, query.clone()).await?;
|
||||
// res.servers = servers.into_iter().
|
||||
todo!()
|
||||
}
|
||||
Deployment => {
|
||||
todo!()
|
||||
}
|
||||
Build => {
|
||||
todo!()
|
||||
}
|
||||
Repo => {
|
||||
todo!()
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Resolve<FindResources, RequestUser> for State {
|
||||
@@ -202,7 +243,7 @@ fn seperate_tags(tags: Vec<Tag>) -> SeperateTags {
|
||||
}
|
||||
|
||||
if seperated.resource_types.is_empty() {
|
||||
seperated.resource_types = ALL_RESOURCE_TYPES.to_vec();
|
||||
seperated.resource_types = FIND_RESOURCE_TYPES.to_vec();
|
||||
}
|
||||
|
||||
seperated
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
use anyhow::anyhow;
|
||||
use async_trait::async_trait;
|
||||
use futures::future::join_all;
|
||||
use monitor_types::{
|
||||
entities::{
|
||||
deployment::ContainerSummary,
|
||||
@@ -52,21 +51,7 @@ impl Resolve<ListServers, RequestUser> for State {
|
||||
ListServers { query }: ListServers,
|
||||
user: RequestUser,
|
||||
) -> anyhow::Result<Vec<ServerListItem>> {
|
||||
let servers = self.list_resources_for_user(&user, query).await?;
|
||||
|
||||
let servers = servers.into_iter().map(|server: Server| async {
|
||||
let status = self.server_status_cache.get(&server.id).await;
|
||||
ServerListItem {
|
||||
id: server.id,
|
||||
name: server.name,
|
||||
tags: server.tags,
|
||||
status: status.map(|s| s.status).unwrap_or_default(),
|
||||
}
|
||||
});
|
||||
|
||||
let servers = join_all(servers).await;
|
||||
|
||||
Ok(servers)
|
||||
<State as Resource<Server>>::list_resources_for_user(self, &user, query).await
|
||||
}
|
||||
}
|
||||
|
||||
@@ -346,16 +331,11 @@ impl Resolve<GetServersSummary, RequestUser> for State {
|
||||
GetServersSummary {}: GetServersSummary,
|
||||
user: RequestUser,
|
||||
) -> anyhow::Result<GetServersSummaryResponse> {
|
||||
let servers: Vec<Server> = self.list_resources_for_user(&user, None).await?;
|
||||
let servers = <State as Resource<Server>>::list_resources_for_user(self, &user, None).await?;
|
||||
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 {
|
||||
match server.status {
|
||||
ServerStatus::Ok => {
|
||||
res.healthy += 1;
|
||||
}
|
||||
|
||||
@@ -1,24 +1,30 @@
|
||||
use anyhow::{anyhow, Context};
|
||||
use async_trait::async_trait;
|
||||
use futures::future::join_all;
|
||||
use monitor_types::{
|
||||
entities::{
|
||||
alerter::Alerter, build::Build, builder::Builder, deployment::Deployment, repo::Repo,
|
||||
server::Server, PermissionLevel,
|
||||
},
|
||||
permissioned::Permissioned,
|
||||
requests::read::{BuildListItem, DeploymentListItem, RepoListItem, ServerListItem},
|
||||
};
|
||||
use mungos::{
|
||||
mongodb::bson::{doc, Document},
|
||||
AggStage::*,
|
||||
Collection, Indexed,
|
||||
};
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::{auth::RequestUser, state::State};
|
||||
|
||||
#[async_trait]
|
||||
pub trait Resource<T: Indexed + Send + Unpin + Permissioned> {
|
||||
type ListItem: Serialize + Send;
|
||||
|
||||
fn name() -> &'static str;
|
||||
fn coll(&self) -> &Collection<T>;
|
||||
async fn into_list_item(&self, resource: T) -> Self::ListItem;
|
||||
|
||||
async fn get_resource(&self, id: &str) -> anyhow::Result<T> {
|
||||
self.coll()
|
||||
@@ -92,7 +98,7 @@ pub trait Resource<T: Indexed + Send + Unpin + Permissioned> {
|
||||
&self,
|
||||
user: &RequestUser,
|
||||
query: Option<Document>,
|
||||
) -> anyhow::Result<Vec<T>> {
|
||||
) -> anyhow::Result<Vec<Self::ListItem>> {
|
||||
let mut query = query.unwrap_or_default();
|
||||
if !user.is_admin {
|
||||
query.insert(
|
||||
@@ -100,14 +106,24 @@ pub trait Resource<T: Indexed + Send + Unpin + Permissioned> {
|
||||
doc! { "$in": ["read", "execute", "update"] },
|
||||
);
|
||||
}
|
||||
self.coll()
|
||||
let list = self
|
||||
.coll()
|
||||
.get_some(query, None)
|
||||
.await
|
||||
.context(format!("failed to pull {}s from mongo", Self::name()))
|
||||
.context(format!("failed to pull {}s from mongo", Self::name()))?
|
||||
.into_iter()
|
||||
.map(|resource| self.into_list_item(resource));
|
||||
|
||||
let list = join_all(list).await;
|
||||
|
||||
Ok(list)
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Resource<Server> for State {
|
||||
type ListItem = ServerListItem;
|
||||
|
||||
fn name() -> &'static str {
|
||||
"server"
|
||||
}
|
||||
@@ -115,9 +131,22 @@ impl Resource<Server> for State {
|
||||
fn coll(&self) -> &Collection<Server> {
|
||||
&self.db.servers
|
||||
}
|
||||
|
||||
async fn into_list_item(&self, server: Server) -> ServerListItem {
|
||||
let status = self.server_status_cache.get(&server.id).await;
|
||||
ServerListItem {
|
||||
id: server.id,
|
||||
name: server.name,
|
||||
tags: server.tags,
|
||||
status: status.map(|s| s.status).unwrap_or_default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Resource<Deployment> for State {
|
||||
type ListItem = DeploymentListItem;
|
||||
|
||||
fn name() -> &'static str {
|
||||
"deployment"
|
||||
}
|
||||
@@ -125,9 +154,27 @@ impl Resource<Deployment> for State {
|
||||
fn coll(&self) -> &Collection<Deployment> {
|
||||
&self.db.deployments
|
||||
}
|
||||
|
||||
async fn into_list_item(&self, deployment: Deployment) -> DeploymentListItem {
|
||||
let status = self.deployment_status_cache.get(&deployment.id).await;
|
||||
DeploymentListItem {
|
||||
id: deployment.id,
|
||||
name: deployment.name,
|
||||
tags: deployment.tags,
|
||||
state: status.as_ref().map(|s| s.state).unwrap_or_default(),
|
||||
status: status
|
||||
.as_ref()
|
||||
.and_then(|s| s.container.as_ref().and_then(|c| c.status.to_owned())),
|
||||
image: String::new(),
|
||||
version: String::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Resource<Build> for State {
|
||||
type ListItem = BuildListItem;
|
||||
|
||||
fn name() -> &'static str {
|
||||
"build"
|
||||
}
|
||||
@@ -135,19 +182,22 @@ impl Resource<Build> for State {
|
||||
fn coll(&self) -> &Collection<Build> {
|
||||
&self.db.builds
|
||||
}
|
||||
}
|
||||
|
||||
impl Resource<Builder> for State {
|
||||
fn name() -> &'static str {
|
||||
"builder"
|
||||
}
|
||||
|
||||
fn coll(&self) -> &Collection<Builder> {
|
||||
&self.db.builders
|
||||
async fn into_list_item(&self, build: Build) -> BuildListItem {
|
||||
BuildListItem {
|
||||
id: build.id,
|
||||
name: build.name,
|
||||
last_built_at: build.last_built_at,
|
||||
version: build.config.version,
|
||||
tags: build.tags,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Resource<Repo> for State {
|
||||
type ListItem = RepoListItem;
|
||||
|
||||
fn name() -> &'static str {
|
||||
"repo"
|
||||
}
|
||||
@@ -155,9 +205,38 @@ impl Resource<Repo> for State {
|
||||
fn coll(&self) -> &Collection<Repo> {
|
||||
&self.db.repos
|
||||
}
|
||||
|
||||
async fn into_list_item(&self, repo: Repo) -> RepoListItem {
|
||||
RepoListItem {
|
||||
id: repo.id,
|
||||
name: repo.name,
|
||||
last_pulled_at: repo.last_pulled_at,
|
||||
tags: repo.tags,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Resource<Builder> for State {
|
||||
type ListItem = Builder;
|
||||
|
||||
fn name() -> &'static str {
|
||||
"builder"
|
||||
}
|
||||
|
||||
fn coll(&self) -> &Collection<Builder> {
|
||||
&self.db.builders
|
||||
}
|
||||
|
||||
async fn into_list_item(&self, builder: Builder) -> Builder {
|
||||
builder
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Resource<Alerter> for State {
|
||||
type ListItem = Alerter;
|
||||
|
||||
fn name() -> &'static str {
|
||||
"alerter"
|
||||
}
|
||||
@@ -165,4 +244,8 @@ impl Resource<Alerter> for State {
|
||||
fn coll(&self) -> &Collection<Alerter> {
|
||||
&self.db.alerters
|
||||
}
|
||||
|
||||
async fn into_list_item(&self, alerter: Alerter) -> Alerter {
|
||||
alerter
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user