abit more

This commit is contained in:
mbecker20
2024-06-06 03:02:25 -07:00
parent eda0b233ca
commit bf85e886bd
3 changed files with 267 additions and 38 deletions

View File

@@ -27,6 +27,7 @@ pub trait ResourceSync: Sized {
+ Default
+ Send
+ From<Self::PartialConfig>
+ PartialDiff<Self::PartialConfig, Self::ConfigDiff>
+ 'static;
type Info: Default + 'static;
type PartialConfig: std::fmt::Debug
@@ -35,7 +36,9 @@ pub trait ResourceSync: Sized {
+ From<Self::Config>
+ Serialize
+ MaybeNone
+ From<Self::ConfigDiff>
+ 'static;
type ConfigDiff: Diff + MaybeNone;
fn name_to_resource(
) -> &'static HashMap<String, Resource<Self::Config, Self::Info>>;
@@ -68,29 +71,24 @@ pub trait ResourceSync: Sized {
id: String,
description: String,
) -> anyhow::Result<()>;
}
pub trait ResourceSyncOuter<
Implementer: ResourceSync,
Logger: SyncLogger<Implementer, Self>,
> where
Self: Sized,
Implementer::Config:
PartialDiff<Implementer::PartialConfig, Self::ConfigDiff>,
Implementer::PartialConfig: From<Self::ConfigDiff>,
{
type ConfigDiff: Diff + MaybeNone;
fn display() -> &'static str;
fn resource_target(id: String) -> ResourceTarget;
/// Diffs the declared toml (partial) against the full existing config.
/// Removes all fields from toml (partial) that haven't changed.
fn get_diff(
original: Implementer::Config,
update: Implementer::PartialConfig,
original: Self::Config,
update: Self::PartialConfig,
) -> anyhow::Result<Self::ConfigDiff>;
}
pub trait ResourceSyncOuter<
Implementer: ResourceSync,
Logger: SyncLogger<Implementer>,
> where
Self: Sized,
{
fn display() -> &'static str;
fn resource_target(id: String) -> ResourceTarget;
#[allow(async_fn_in_trait)]
async fn run_updates(
@@ -203,14 +201,9 @@ pub trait ResourceSyncOuter<
}
}
pub trait SyncLogger<Implementer, Resource>
pub trait SyncLogger<Implementer: ResourceSync>
where
Self: Sized,
Implementer: ResourceSync,
Resource: ResourceSyncOuter<Implementer, Self>,
Implementer::Config:
PartialDiff<Implementer::PartialConfig, Resource::ConfigDiff>,
Implementer::PartialConfig: From<Resource::ConfigDiff>,
{
fn log_to_create(
resource: &ResourceToml<Implementer::PartialConfig>,
@@ -219,7 +212,7 @@ where
name: &str,
description: &str,
tags: &[String],
diff: &Resource::ConfigDiff,
diff: &Implementer::ConfigDiff,
);
fn log_to_delete(name: &str);
@@ -237,6 +230,8 @@ where
fn log_description_updated(name: &str);
fn log_failed_description_update(name: &str, e: anyhow::Error);
fn log_procedure_sync_failed_max_iter();
}
pub trait IdToTag {
@@ -251,11 +246,8 @@ pub fn get_updates<Implementer, Resource, Tags, Logger>(
where
Implementer: ResourceSync,
Resource: ResourceSyncOuter<Implementer, Logger>,
Implementer::Config:
PartialDiff<Implementer::PartialConfig, Resource::ConfigDiff>,
Implementer::PartialConfig: From<Resource::ConfigDiff>,
Tags: IdToTag,
Logger: SyncLogger<Implementer, Resource>,
Logger: SyncLogger<Implementer>,
{
let map = Implementer::name_to_resource();
@@ -279,7 +271,7 @@ where
let config: Implementer::Config = resource.config.into();
resource.config = config.into();
let diff = Resource::get_diff(
let diff = Implementer::get_diff(
original.config.clone(),
resource.config,
)?;
@@ -400,10 +392,7 @@ pub async fn run_update_tags<Implementer, Resource, Logger>(
) where
Implementer: ResourceSync,
Resource: ResourceSyncOuter<Implementer, Logger>,
Implementer::Config:
PartialDiff<Implementer::PartialConfig, Resource::ConfigDiff>,
Implementer::PartialConfig: From<Resource::ConfigDiff>,
Logger: SyncLogger<Implementer, Resource>,
Logger: SyncLogger<Implementer>,
{
// Update tags
if let Err(e) = Implementer::update_tags(id, tags).await {
@@ -430,10 +419,7 @@ pub async fn run_update_description<Implementer, Resource, Logger>(
) where
Implementer: ResourceSync,
Resource: ResourceSyncOuter<Implementer, Logger>,
Implementer::Config:
PartialDiff<Implementer::PartialConfig, Resource::ConfigDiff>,
Implementer::PartialConfig: From<Resource::ConfigDiff>,
Logger: SyncLogger<Implementer, Resource>,
Logger: SyncLogger<Implementer>,
{
if let Err(e) =
Implementer::update_description(id, description).await

243
lib/sync/src/resources.rs Normal file
View File

@@ -0,0 +1,243 @@
use monitor_client::entities::{
alerter::Alerter, build::Build, builder::Builder,
deployment::Deployment, procedure::Procedure, repo::Repo,
server::Server, server_template::ServerTemplate, sync,
update::ResourceTarget,
};
use partial_derive2::MaybeNone;
use crate::resource::{
ResourceSync, ResourceSyncOuter, SyncLogger, ToUpdateItem,
};
impl<Implementer: ResourceSync, Logger: SyncLogger<Implementer>>
ResourceSyncOuter<Implementer, Logger> for Server
{
fn display() -> &'static str {
"server"
}
fn resource_target(id: String) -> ResourceTarget {
ResourceTarget::Server(id)
}
}
impl<Implementer: ResourceSync, Logger: SyncLogger<Implementer>>
ResourceSyncOuter<Implementer, Logger> for Deployment
{
fn display() -> &'static str {
"deployment"
}
fn resource_target(id: String) -> ResourceTarget {
ResourceTarget::Deployment(id)
}
}
impl<Implementer: ResourceSync, Logger: SyncLogger<Implementer>>
ResourceSyncOuter<Implementer, Logger> for Build
{
fn display() -> &'static str {
"build"
}
fn resource_target(id: String) -> ResourceTarget {
ResourceTarget::Build(id)
}
}
impl<Implementer: ResourceSync, Logger: SyncLogger<Implementer>>
ResourceSyncOuter<Implementer, Logger> for Repo
{
fn display() -> &'static str {
"repo"
}
fn resource_target(id: String) -> ResourceTarget {
ResourceTarget::Repo(id)
}
}
impl<Implementer: ResourceSync, Logger: SyncLogger<Implementer>>
ResourceSyncOuter<Implementer, Logger> for Alerter
{
fn display() -> &'static str {
"alerter"
}
fn resource_target(id: String) -> ResourceTarget {
ResourceTarget::Alerter(id)
}
}
impl<Implementer: ResourceSync, Logger: SyncLogger<Implementer>>
ResourceSyncOuter<Implementer, Logger> for Builder
{
fn display() -> &'static str {
"builder"
}
fn resource_target(id: String) -> ResourceTarget {
ResourceTarget::Builder(id)
}
}
impl<Implementer: ResourceSync, Logger: SyncLogger<Implementer>>
ResourceSyncOuter<Implementer, Logger> for ServerTemplate
{
fn display() -> &'static str {
"server_template"
}
fn resource_target(id: String) -> ResourceTarget {
ResourceTarget::ServerTemplate(id)
}
}
impl<Implementer: ResourceSync, Logger: SyncLogger<Implementer>>
ResourceSyncOuter<Implementer, Logger> for sync::ResourceSync
{
fn display() -> &'static str {
"resource_sync"
}
fn resource_target(id: String) -> ResourceTarget {
ResourceTarget::ResourceSync(id)
}
}
impl<Implementer: ResourceSync, Logger: SyncLogger<Implementer>>
ResourceSyncOuter<Implementer, Logger> for Procedure
{
fn display() -> &'static str {
"procedure"
}
fn resource_target(id: String) -> ResourceTarget {
ResourceTarget::Procedure(id)
}
async fn run_updates(
mut to_create: crate::resource::ToCreate<
<Implementer as ResourceSync>::PartialConfig,
>,
mut to_update: crate::resource::ToUpdate<
<Implementer as ResourceSync>::PartialConfig,
>,
to_delete: crate::resource::ToDelete,
) {
for name in to_delete {
if let Err(e) = Implementer::delete(name.clone()).await {
Logger::log_failed_delete(&name, e);
// warn!("failed to delete procedure {name} | {e:#}",);
} else {
Logger::log_deleted(&name);
// info!(
// "{} procedure '{}'",
// "deleted".red().bold(),
// name.bold(),
// );
}
}
if to_update.is_empty() && to_create.is_empty() {
return;
}
for i in 0..10 {
let mut to_pull = Vec::new();
for ToUpdateItem {
id,
resource,
update_description,
update_tags,
} in &to_update
{
// Update resource
let name = resource.name.clone();
let tags = resource.tags.clone();
let description = resource.description.clone();
if *update_description {
crate::resource::run_update_description::<
Implementer,
Self,
Logger,
>(id.clone(), &name, description)
.await;
}
if *update_tags {
crate::resource::run_update_tags::<Implementer, Self, Logger>(
id.clone(),
&name,
tags,
)
.await;
}
if !resource.config.is_none() {
if let Err(e) =
Implementer::update(id.clone(), resource.clone()).await
{
if i == 9 {
Logger::log_failed_update(&name, e);
// warn!(
// "failed to update {} {name} | {e:#}",
// Self::display()
// );
}
}
}
// info!("{} {name} updated", Self::display());
Logger::log_updated(&name);
// have to clone out so to_update is mutable
to_pull.push(id.clone());
}
//
to_update.retain(|resource| !to_pull.contains(&resource.id));
let mut to_pull = Vec::new();
for resource in &to_create {
let name = resource.name.clone();
let tags = resource.tags.clone();
let description = resource.description.clone();
let id = match Implementer::create(resource.clone()).await {
Ok(id) => id,
Err(e) => {
if i == 9 {
// warn!(
// "failed to create {} {name} | {e:#}",
// Self::display(),
// );
Logger::log_failed_create(&name, e);
}
continue;
}
};
crate::resource::run_update_tags::<Implementer, Self, Logger>(
id.clone(),
&name,
tags,
)
.await;
crate::resource::run_update_description::<
Implementer,
Self,
Logger,
>(id, &name, description)
.await;
Logger::log_created(&name);
// info!("{} {name} created", Self::display());
to_pull.push(name);
}
to_create.retain(|resource| !to_pull.contains(&resource.name));
if to_update.is_empty() && to_create.is_empty() {
// info!("all procedures synced");
return;
}
}
Logger::log_procedure_sync_failed_max_iter();
// warn!("procedure sync loop exited after max iterations");
}
}