diff --git a/bin/monrun/src/sync/mod.rs b/bin/monrun/src/sync/mod.rs index ff9e1a6e6..f478d23ae 100644 --- a/bin/monrun/src/sync/mod.rs +++ b/bin/monrun/src/sync/mod.rs @@ -1,16 +1,27 @@ -use std::path::Path; +use std::{collections::HashMap, path::Path}; -use monitor_client::entities::{ - alerter::Alerter, build::Build, builder::Builder, - deployment::Deployment, repo::Repo, server::Server, +use async_trait::async_trait; +use monitor_client::{ + api::{ + read::ListTags, + write::{CreateTag, UpdateDescription, UpdateTagsOnResource}, + }, + entities::{ + alerter::Alerter, + build::Build, + builder::Builder, + deployment::Deployment, + repo::Repo, + resource::{Resource, ResourceListItem}, + server::Server, + update::ResourceTarget, + }, }; -use crate::wait_for_enter; +use crate::{monitor_client, wait_for_enter}; mod resource_file; -mod sync_trait; - -use sync_trait::Sync; +mod resources; pub async fn run_sync(path: &Path) -> anyhow::Result<()> { info!("path: {path:?}"); @@ -32,13 +43,210 @@ pub async fn run_sync(path: &Path) -> anyhow::Result<()> { wait_for_enter("CONTINUE")?; - Build::run_updates(build_updates, build_creates).await; + // Run these first, which require no name -> id replacement + Builder::run_updates(builder_updates, builder_creates).await; Server::run_updates(server_updates, server_creates).await; + Alerter::run_updates(alerter_updates, alerter_creates).await; + + Build::run_updates(build_updates, build_creates).await; Deployment::run_updates(deployment_updates, deployment_creates) .await; - Builder::run_updates(builder_updates, builder_creates).await; - Alerter::run_updates(alerter_updates, alerter_creates).await; Repo::run_updates(repo_updates, repo_creates).await; Ok(()) } + +type ToUpdate = Vec<(String, Resource)>; +type ToCreate = Vec>; +type UpdatesResult = (ToUpdate, ToCreate); + +#[async_trait] +pub trait ResourceSync { + type PartialConfig: Clone + Send + 'static; + type ListItemInfo: 'static; + type ExtLookup: Send + Sync; + + fn display() -> &'static str; + + fn resource_target(id: String) -> ResourceTarget; + + fn name_to_resource( + ) -> &'static HashMap>; + + async fn init_lookup_data() -> Self::ExtLookup; + + /// Returns created id + async fn create( + resource: Resource, + ext_lookup: &Self::ExtLookup, + ) -> anyhow::Result; + + async fn update( + id: String, + resource: Resource, + ext_lookup: &Self::ExtLookup, + ) -> anyhow::Result<()>; + + fn get_updates( + resources: Vec>, + ) -> anyhow::Result> { + let map = Self::name_to_resource(); + + // (name, partial config) + let mut to_update = + Vec::<(String, Resource)>::new(); + let mut to_create = Vec::>::new(); + + for resource in resources { + match map.get(&resource.name).map(|s| s.id.clone()) { + Some(id) => { + to_update.push((id, resource)); + } + None => { + to_create.push(resource); + } + } + } + + if !to_create.is_empty() { + println!( + "\nTO CREATE: {}", + to_create + .iter() + .map(|item| item.name.as_str()) + .collect::>() + .join(", ") + ); + } + + if !to_update.is_empty() { + println!( + "\nTO UPDATE: {}", + to_update + .iter() + .map(|(_, item)| item.name.as_str()) + .collect::>() + .join(", ") + ); + } + + Ok((to_update, to_create)) + } + + async fn run_updates( + to_update: ToUpdate, + to_create: ToCreate, + ) { + let mut tag_name_to_id = monitor_client() + .read(ListTags::default()) + .await + .expect("failed to ListTags mid run") + .into_iter() + .map(|tag| (tag.name, tag.id)) + .collect::>(); + + let ext_lookup = Self::init_lookup_data().await; + + for (id, resource) in to_update { + // Update resource + let name = resource.name.clone(); + let tags = resource.tags.clone(); + let description = resource.description.clone(); + if let Err(e) = + Self::update(id.clone(), resource, &ext_lookup).await + { + warn!("failed to update {} {name} | {e:#}", Self::display()); + } + Self::update_tags( + id.clone(), + &name, + &tags, + &mut tag_name_to_id, + ) + .await; + Self::update_description(id, description).await; + } + + for resource in to_create { + let name = resource.name.clone(); + let tags = resource.tags.clone(); + let description = resource.description.clone(); + let id = match Self::create(resource, &ext_lookup).await { + Ok(id) => id, + Err(e) => { + warn!( + "failed to create {} {name} | {e:#}", + Self::display(), + ); + continue; + } + }; + Self::update_tags( + id.clone(), + &name, + &tags, + &mut tag_name_to_id, + ) + .await; + Self::update_description(id, description).await; + } + } + + async fn update_tags( + resource_id: String, + resource_name: &str, + tags: &[String], + tag_name_to_id: &mut HashMap, + ) { + // make sure all tags are created + for tag_name in tags { + if !tag_name_to_id.contains_key(tag_name) { + let tag_id = monitor_client() + .write(CreateTag { + name: tag_name.to_string(), + }) + .await + .expect("failed to CreateTag mid run") + .id; + tag_name_to_id.insert(tag_name.to_string(), tag_id); + } + } + + // get Vec + let tags = tags + .iter() + .map(|tag_name| { + tag_name_to_id + .get(tag_name) + .expect("somehow didn't find tag at this point") + .to_string() + }) + .collect(); + + // Update tags + if let Err(e) = monitor_client() + .write(UpdateTagsOnResource { + target: Self::resource_target(resource_id), + tags, + }) + .await + { + warn!( + "failed to update tags on {} {resource_name} | {e:#}", + Self::display(), + ); + } + } + + async fn update_description(id: String, description: String) { + if let Err(e) = monitor_client() + .write(UpdateDescription { + target: Self::resource_target(id.clone()), + description, + }) + .await + { + warn!("failed to update resource {id} description | {e:#}"); + } + } +} diff --git a/bin/monrun/src/sync/resources/alerter.rs b/bin/monrun/src/sync/resources/alerter.rs new file mode 100644 index 000000000..8d10c4d70 --- /dev/null +++ b/bin/monrun/src/sync/resources/alerter.rs @@ -0,0 +1,67 @@ +use std::collections::HashMap; + +use async_trait::async_trait; +use monitor_client::{ + api::write::{CreateAlerter, UpdateAlerter}, + entities::{ + alerter::{Alerter, AlerterListItemInfo, PartialAlerterConfig}, + resource::{Resource, ResourceListItem}, + update::ResourceTarget, + }, +}; + +use crate::{ + maps::name_to_alerter, monitor_client, sync::ResourceSync, +}; + +#[async_trait] +impl ResourceSync for Alerter { + type PartialConfig = PartialAlerterConfig; + type ListItemInfo = AlerterListItemInfo; + type ExtLookup = (); + + fn display() -> &'static str { + "alerter" + } + + fn resource_target(id: String) -> ResourceTarget { + ResourceTarget::Alerter(id) + } + + fn name_to_resource( + ) -> &'static HashMap> + { + name_to_alerter() + } + + async fn init_lookup_data() -> Self::ExtLookup { + () + } + + async fn create( + resource: Resource, + _: &(), + ) -> anyhow::Result { + monitor_client() + .write(CreateAlerter { + name: resource.name, + config: resource.config, + }) + .await + .map(|res| res.id) + } + + async fn update( + id: String, + resource: Resource, + _: &(), + ) -> anyhow::Result<()> { + monitor_client() + .write(UpdateAlerter { + id, + config: resource.config, + }) + .await?; + Ok(()) + } +} diff --git a/bin/monrun/src/sync/resources/build.rs b/bin/monrun/src/sync/resources/build.rs new file mode 100644 index 000000000..99f1da56a --- /dev/null +++ b/bin/monrun/src/sync/resources/build.rs @@ -0,0 +1,88 @@ +use std::collections::HashMap; + +use async_trait::async_trait; +use monitor_client::{ + api::{ + read::ListBuilders, + write::{CreateBuild, UpdateBuild}, + }, + entities::{ + build::{Build, BuildListItemInfo, PartialBuildConfig}, + resource::{Resource, ResourceListItem}, + update::ResourceTarget, + }, +}; + +use crate::{ + maps::name_to_build, monitor_client, sync::ResourceSync, +}; + +#[async_trait] +impl ResourceSync for Build { + type PartialConfig = PartialBuildConfig; + type ListItemInfo = BuildListItemInfo; + /// Builder Name to Id + type ExtLookup = HashMap; + + fn display() -> &'static str { + "build" + } + + fn resource_target(id: String) -> ResourceTarget { + ResourceTarget::Build(id) + } + + fn name_to_resource( + ) -> &'static HashMap> + { + name_to_build() + } + + async fn init_lookup_data() -> Self::ExtLookup { + monitor_client() + .read(ListBuilders::default()) + .await + .expect("failed to get builders") + .into_iter() + .map(|b| (b.name, b.id)) + .collect::>() + } + + async fn create( + mut resource: Resource, + builder_name_to_id: &Self::ExtLookup, + ) -> anyhow::Result { + // at this point the 'builder_id' is the name + resource.config.builder_id = resource + .config + .builder_id + .and_then(|id| builder_name_to_id.get(&id).cloned()); + + monitor_client() + .write(CreateBuild { + name: resource.name, + config: resource.config, + }) + .await + .map(|res| res.id) + } + + async fn update( + id: String, + mut resource: Resource, + builder_name_to_id: &Self::ExtLookup, + ) -> anyhow::Result<()> { + // at this point the 'builder_id' is the name + resource.config.builder_id = resource + .config + .builder_id + .and_then(|id| builder_name_to_id.get(&id).cloned()); + monitor_client() + .write(UpdateBuild { + id, + config: resource.config, + }) + .await?; + Ok(()) + } +} diff --git a/bin/monrun/src/sync/resources/builder.rs b/bin/monrun/src/sync/resources/builder.rs new file mode 100644 index 000000000..7bb2ccb78 --- /dev/null +++ b/bin/monrun/src/sync/resources/builder.rs @@ -0,0 +1,67 @@ +use std::collections::HashMap; + +use async_trait::async_trait; +use monitor_client::{ + api::write::{CreateBuilder, UpdateBuilder}, + entities::{ + builder::{Builder, BuilderListItemInfo, PartialBuilderConfig}, + resource::{Resource, ResourceListItem}, + update::ResourceTarget, + }, +}; + +use crate::{ + maps::name_to_builder, monitor_client, sync::ResourceSync, +}; + +#[async_trait] +impl ResourceSync for Builder { + type PartialConfig = PartialBuilderConfig; + type ListItemInfo = BuilderListItemInfo; + type ExtLookup = (); + + fn display() -> &'static str { + "builder" + } + + fn resource_target(id: String) -> ResourceTarget { + ResourceTarget::Builder(id) + } + + fn name_to_resource( + ) -> &'static HashMap> + { + name_to_builder() + } + + async fn init_lookup_data() -> Self::ExtLookup { + () + } + + async fn create( + resource: Resource, + _: &(), + ) -> anyhow::Result { + monitor_client() + .write(CreateBuilder { + name: resource.name, + config: resource.config, + }) + .await + .map(|res| res.id) + } + + async fn update( + id: String, + resource: Resource, + _: &(), + ) -> anyhow::Result<()> { + monitor_client() + .write(UpdateBuilder { + id, + config: resource.config, + }) + .await?; + Ok(()) + } +} diff --git a/bin/monrun/src/sync/resources/deployment.rs b/bin/monrun/src/sync/resources/deployment.rs new file mode 100644 index 000000000..2846d487e --- /dev/null +++ b/bin/monrun/src/sync/resources/deployment.rs @@ -0,0 +1,127 @@ +use std::collections::HashMap; + +use async_trait::async_trait; +use monitor_client::{ + api::{ + read::{ListBuilds, ListServers}, + write, + }, + entities::{ + deployment::{ + Deployment, DeploymentImage, DeploymentListItemInfo, + PartialDeploymentConfig, + }, + resource::{Resource, ResourceListItem}, + update::ResourceTarget, + }, +}; + +use crate::{ + maps::name_to_deployment, monitor_client, sync::ResourceSync, +}; + +pub struct DeploymentExtLookup { + pub servers: HashMap, + pub builds: HashMap, +} + +#[async_trait] +impl ResourceSync for Deployment { + type PartialConfig = PartialDeploymentConfig; + type ListItemInfo = DeploymentListItemInfo; + type ExtLookup = DeploymentExtLookup; + + fn display() -> &'static str { + "deployment" + } + + fn resource_target(id: String) -> ResourceTarget { + ResourceTarget::Deployment(id) + } + + fn name_to_resource( + ) -> &'static HashMap> + { + name_to_deployment() + } + + async fn init_lookup_data() -> Self::ExtLookup { + let servers = monitor_client() + .read(ListServers::default()) + .await + .expect("failed to get servers") + .into_iter() + .map(|b| (b.name, b.id)) + .collect::>(); + + let builds = monitor_client() + .read(ListBuilds::default()) + .await + .expect("failed to get builds") + .into_iter() + .map(|b| (b.name, b.id)) + .collect::>(); + + DeploymentExtLookup { servers, builds } + } + + async fn create( + mut resource: Resource, + lookup: &Self::ExtLookup, + ) -> anyhow::Result { + handle_name_to_id_switch(&mut resource.config, lookup); + monitor_client() + .write(write::CreateDeployment { + name: resource.name, + config: resource.config, + }) + .await + .map(|res| res.id) + } + + async fn update( + id: String, + mut resource: Resource, + lookup: &Self::ExtLookup, + ) -> anyhow::Result<()> { + handle_name_to_id_switch(&mut resource.config, lookup); + monitor_client() + .write(write::UpdateDeployment { + id, + config: resource.config, + }) + .await?; + Ok(()) + } +} + +fn handle_name_to_id_switch( + config: &mut PartialDeploymentConfig, + lookup: &DeploymentExtLookup, +) { + config.server_id = config + .server_id + .as_ref() + .and_then(|name| lookup.servers.get(name).cloned()); + if let Some(DeploymentImage::Build { + build_id: name, + version, + }) = &config.image + { + match lookup.builds.get(name).cloned() { + Some(build_id) => { + config.image = DeploymentImage::Build { + build_id, + version: version.clone(), + } + .into(); + } + None => { + config.image = DeploymentImage::Image { + image: String::new(), + } + .into(); + } + } + } +} diff --git a/bin/monrun/src/sync/resources/mod.rs b/bin/monrun/src/sync/resources/mod.rs new file mode 100644 index 000000000..8981615cb --- /dev/null +++ b/bin/monrun/src/sync/resources/mod.rs @@ -0,0 +1,7 @@ +pub mod alerter; +pub mod build; +pub mod builder; +pub mod deployment; +pub mod procedure; +pub mod repo; +pub mod server; diff --git a/bin/monrun/src/sync/resources/procedure.rs b/bin/monrun/src/sync/resources/procedure.rs new file mode 100644 index 000000000..e69de29bb diff --git a/bin/monrun/src/sync/resources/repo.rs b/bin/monrun/src/sync/resources/repo.rs new file mode 100644 index 000000000..7d52d452d --- /dev/null +++ b/bin/monrun/src/sync/resources/repo.rs @@ -0,0 +1,65 @@ +use std::collections::HashMap; + +use async_trait::async_trait; +use monitor_client::{ + api::write::{CreateRepo, UpdateRepo}, + entities::{ + repo::{PartialRepoConfig, Repo, RepoInfo}, + resource::{Resource, ResourceListItem}, + update::ResourceTarget, + }, +}; + +use crate::{maps::name_to_repo, monitor_client, sync::ResourceSync}; + +#[async_trait] +impl ResourceSync for Repo { + type PartialConfig = PartialRepoConfig; + type ListItemInfo = RepoInfo; + type ExtLookup = (); + + fn display() -> &'static str { + "repo" + } + + fn resource_target(id: String) -> ResourceTarget { + ResourceTarget::Repo(id) + } + + fn name_to_resource( + ) -> &'static HashMap> + { + name_to_repo() + } + + async fn init_lookup_data() -> Self::ExtLookup { + () + } + + async fn create( + resource: Resource, + _: &(), + ) -> anyhow::Result { + monitor_client() + .write(CreateRepo { + name: resource.name, + config: resource.config, + }) + .await + .map(|res| res.id) + } + + async fn update( + id: String, + resource: Resource, + _: &(), + ) -> anyhow::Result<()> { + monitor_client() + .write(UpdateRepo { + id, + config: resource.config, + }) + .await?; + Ok(()) + } +} diff --git a/bin/monrun/src/sync/resources/server.rs b/bin/monrun/src/sync/resources/server.rs new file mode 100644 index 000000000..bde390fb9 --- /dev/null +++ b/bin/monrun/src/sync/resources/server.rs @@ -0,0 +1,67 @@ +use std::collections::HashMap; + +use async_trait::async_trait; +use monitor_client::{ + api::write::{CreateServer, UpdateServer}, + entities::{ + resource::{Resource, ResourceListItem}, + server::{PartialServerConfig, Server, ServerListItemInfo}, + update::ResourceTarget, + }, +}; + +use crate::{ + maps::name_to_server, monitor_client, sync::ResourceSync, +}; + +#[async_trait] +impl ResourceSync for Server { + type ListItemInfo = ServerListItemInfo; + type PartialConfig = PartialServerConfig; + type ExtLookup = (); + + fn display() -> &'static str { + "server" + } + + fn resource_target(id: String) -> ResourceTarget { + ResourceTarget::Server(id) + } + + fn name_to_resource( + ) -> &'static HashMap> + { + name_to_server() + } + + async fn init_lookup_data() -> Self::ExtLookup { + () + } + + async fn create( + resource: Resource, + _: &(), + ) -> anyhow::Result { + monitor_client() + .write(CreateServer { + name: resource.name, + config: resource.config, + }) + .await + .map(|res| res.id) + } + + async fn update( + id: String, + resource: Resource, + _: &(), + ) -> anyhow::Result<()> { + monitor_client() + .write(UpdateServer { + id, + config: resource.config, + }) + .await?; + Ok(()) + } +} diff --git a/bin/monrun/src/sync/sync_trait.rs b/bin/monrun/src/sync/sync_trait.rs deleted file mode 100644 index 2ab0fb4b9..000000000 --- a/bin/monrun/src/sync/sync_trait.rs +++ /dev/null @@ -1,487 +0,0 @@ -use std::collections::HashMap; - -use async_trait::async_trait; -use monitor_client::{ - api::{ - read::ListTags, - write::{ - self, CreateTag, UpdateDescription, UpdateTagsOnResource, - }, - }, - entities::{ - alerter::{Alerter, AlerterListItemInfo, PartialAlerterConfig}, - build::{Build, BuildListItemInfo, PartialBuildConfig}, - builder::{Builder, BuilderListItemInfo, PartialBuilderConfig}, - deployment::{ - Deployment, DeploymentListItemInfo, PartialDeploymentConfig, - }, - repo::{PartialRepoConfig, Repo, RepoInfo}, - resource::{Resource, ResourceListItem}, - server::{PartialServerConfig, Server, ServerListItemInfo}, - update::ResourceTarget, - }, -}; - -use crate::{ - maps::{ - name_to_alerter, name_to_build, name_to_builder, - name_to_deployment, name_to_repo, name_to_server, - }, - monitor_client, -}; - -type ToUpdate = Vec<(String, Resource)>; -type ToCreate = Vec>; -type UpdatesResult = (ToUpdate, ToCreate); - -#[async_trait] -pub trait Sync { - type PartialConfig: Clone + Send + 'static; - type ListItemInfo: 'static; - - fn display() -> &'static str; - - fn resource_target(id: String) -> ResourceTarget; - - fn name_to_resource( - ) -> &'static HashMap>; - - /// Returns created id - async fn create( - resource: Resource, - ) -> anyhow::Result; - - async fn update( - id: String, - resource: Resource, - ) -> anyhow::Result<()>; - - fn get_updates( - resources: Vec>, - ) -> anyhow::Result> { - let map = Self::name_to_resource(); - - // (name, partial config) - let mut to_update = - Vec::<(String, Resource)>::new(); - let mut to_create = Vec::>::new(); - - for resource in resources { - match map.get(&resource.name).map(|s| s.id.clone()) { - Some(id) => { - to_update.push((id, resource)); - } - None => { - to_create.push(resource); - } - } - } - - if !to_create.is_empty() { - println!( - "\nTO CREATE: {}", - to_create - .iter() - .map(|item| item.name.as_str()) - .collect::>() - .join(", ") - ); - } - - if !to_update.is_empty() { - println!( - "\nTO UPDATE: {}", - to_update - .iter() - .map(|(_, item)| item.name.as_str()) - .collect::>() - .join(", ") - ); - } - - Ok((to_update, to_create)) - } - - async fn run_updates( - to_update: ToUpdate, - to_create: ToCreate, - ) { - let mut tag_name_to_id = monitor_client() - .read(ListTags::default()) - .await - .expect("failed to ListTags mid run") - .into_iter() - .map(|tag| (tag.name, tag.id)) - .collect::>(); - - for (id, resource) in to_update { - // Update resource - let name = resource.name.clone(); - let tags = resource.tags.clone(); - let description = resource.description.clone(); - if let Err(e) = Self::update(id.clone(), resource).await { - warn!("failed to update {} {name} | {e:#}", Self::display()); - } - Self::update_tags( - id.clone(), - &name, - &tags, - &mut tag_name_to_id, - ) - .await; - Self::update_description(id, description).await; - } - - for resource in to_create { - let name = resource.name.clone(); - let tags = resource.tags.clone(); - let description = resource.description.clone(); - let id = match Self::create(resource).await { - Ok(id) => id, - Err(e) => { - warn!( - "failed to create {} {name} | {e:#}", - Self::display(), - ); - continue; - } - }; - Self::update_tags( - id.clone(), - &name, - &tags, - &mut tag_name_to_id, - ) - .await; - Self::update_description(id, description).await; - } - } - - async fn update_tags( - resource_id: String, - resource_name: &str, - tags: &[String], - tag_name_to_id: &mut HashMap, - ) { - // make sure all tags are created - for tag_name in tags { - if !tag_name_to_id.contains_key(tag_name) { - let tag_id = monitor_client() - .write(CreateTag { - name: tag_name.to_string(), - }) - .await - .expect("failed to CreateTag mid run") - .id; - tag_name_to_id.insert(tag_name.to_string(), tag_id); - } - } - - // get Vec - let tags = tags - .iter() - .map(|tag_name| { - tag_name_to_id - .get(tag_name) - .expect("somehow didn't find tag at this point") - .to_string() - }) - .collect(); - - // Update tags - if let Err(e) = monitor_client() - .write(UpdateTagsOnResource { - target: Self::resource_target(resource_id), - tags, - }) - .await - { - warn!( - "failed to update tags on {} {resource_name} | {e:#}", - Self::display(), - ); - } - } - - async fn update_description(id: String, description: String) { - if let Err(e) = monitor_client() - .write(UpdateDescription { - target: Self::resource_target(id.clone()), - description, - }) - .await - { - warn!("failed to update resource {id} description | {e:#}"); - } - } -} - -#[async_trait] -impl Sync for Server { - type ListItemInfo = ServerListItemInfo; - type PartialConfig = PartialServerConfig; - - fn display() -> &'static str { - "server" - } - - fn resource_target(id: String) -> ResourceTarget { - ResourceTarget::Server(id) - } - - fn name_to_resource( - ) -> &'static HashMap> - { - name_to_server() - } - - async fn create( - resource: Resource, - ) -> anyhow::Result { - monitor_client() - .write(write::CreateServer { - name: resource.name, - config: resource.config, - }) - .await - .map(|res| res.id) - } - - async fn update( - id: String, - resource: Resource, - ) -> anyhow::Result<()> { - monitor_client() - .write(write::UpdateServer { - id, - config: resource.config, - }) - .await?; - Ok(()) - } -} - -#[async_trait] -impl Sync for Deployment { - type PartialConfig = PartialDeploymentConfig; - type ListItemInfo = DeploymentListItemInfo; - - fn display() -> &'static str { - "deployment" - } - - fn resource_target(id: String) -> ResourceTarget { - ResourceTarget::Deployment(id) - } - - fn name_to_resource( - ) -> &'static HashMap> - { - name_to_deployment() - } - - async fn create( - resource: Resource, - ) -> anyhow::Result { - monitor_client() - .write(write::CreateDeployment { - name: resource.name, - config: resource.config, - }) - .await - .map(|res| res.id) - } - - async fn update( - id: String, - resource: Resource, - ) -> anyhow::Result<()> { - monitor_client() - .write(write::UpdateDeployment { - id, - config: resource.config, - }) - .await?; - Ok(()) - } -} - -#[async_trait] -impl Sync for Build { - type PartialConfig = PartialBuildConfig; - type ListItemInfo = BuildListItemInfo; - - fn display() -> &'static str { - "build" - } - - fn resource_target(id: String) -> ResourceTarget { - ResourceTarget::Build(id) - } - - fn name_to_resource( - ) -> &'static HashMap> - { - name_to_build() - } - - async fn create( - resource: Resource, - ) -> anyhow::Result { - monitor_client() - .write(write::CreateBuild { - name: resource.name, - config: resource.config, - }) - .await - .map(|res| res.id) - } - - async fn update( - id: String, - resource: Resource, - ) -> anyhow::Result<()> { - monitor_client() - .write(write::UpdateBuild { - id, - config: resource.config, - }) - .await?; - Ok(()) - } -} - -#[async_trait] -impl Sync for Builder { - type PartialConfig = PartialBuilderConfig; - type ListItemInfo = BuilderListItemInfo; - - fn display() -> &'static str { - "builder" - } - - fn resource_target(id: String) -> ResourceTarget { - ResourceTarget::Builder(id) - } - - fn name_to_resource( - ) -> &'static HashMap> - { - name_to_builder() - } - - async fn create( - resource: Resource, - ) -> anyhow::Result { - monitor_client() - .write(write::CreateBuilder { - name: resource.name, - config: resource.config, - }) - .await - .map(|res| res.id) - } - - async fn update( - id: String, - resource: Resource, - ) -> anyhow::Result<()> { - monitor_client() - .write(write::UpdateBuilder { - id, - config: resource.config, - }) - .await?; - Ok(()) - } -} - -#[async_trait] -impl Sync for Alerter { - type PartialConfig = PartialAlerterConfig; - type ListItemInfo = AlerterListItemInfo; - - fn display() -> &'static str { - "alerter" - } - - fn resource_target(id: String) -> ResourceTarget { - ResourceTarget::Alerter(id) - } - - fn name_to_resource( - ) -> &'static HashMap> - { - name_to_alerter() - } - - async fn create( - resource: Resource, - ) -> anyhow::Result { - monitor_client() - .write(write::CreateAlerter { - name: resource.name, - config: resource.config, - }) - .await - .map(|res| res.id) - } - - async fn update( - id: String, - resource: Resource, - ) -> anyhow::Result<()> { - monitor_client() - .write(write::UpdateAlerter { - id, - config: resource.config, - }) - .await?; - Ok(()) - } -} - -#[async_trait] -impl Sync for Repo { - type PartialConfig = PartialRepoConfig; - type ListItemInfo = RepoInfo; - - fn display() -> &'static str { - "repo" - } - - fn resource_target(id: String) -> ResourceTarget { - ResourceTarget::Repo(id) - } - - fn name_to_resource( - ) -> &'static HashMap> - { - name_to_repo() - } - - async fn create( - resource: Resource, - ) -> anyhow::Result { - monitor_client() - .write(write::CreateRepo { - name: resource.name, - config: resource.config, - }) - .await - .map(|res| res.id) - } - - async fn update( - id: String, - resource: Resource, - ) -> anyhow::Result<()> { - monitor_client() - .write(write::UpdateRepo { - id, - config: resource.config, - }) - .await?; - Ok(()) - } -}