mirror of
https://github.com/moghtech/komodo.git
synced 2026-07-20 15:20:27 -05:00
resources sync ready for test
This commit is contained in:
+219
-11
@@ -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<T> = Vec<(String, Resource<T>)>;
|
||||
type ToCreate<T> = Vec<Resource<T>>;
|
||||
type UpdatesResult<T> = (ToUpdate<T>, ToCreate<T>);
|
||||
|
||||
#[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<String, ResourceListItem<Self::ListItemInfo>>;
|
||||
|
||||
async fn init_lookup_data() -> Self::ExtLookup;
|
||||
|
||||
/// Returns created id
|
||||
async fn create(
|
||||
resource: Resource<Self::PartialConfig>,
|
||||
ext_lookup: &Self::ExtLookup,
|
||||
) -> anyhow::Result<String>;
|
||||
|
||||
async fn update(
|
||||
id: String,
|
||||
resource: Resource<Self::PartialConfig>,
|
||||
ext_lookup: &Self::ExtLookup,
|
||||
) -> anyhow::Result<()>;
|
||||
|
||||
fn get_updates(
|
||||
resources: Vec<Resource<Self::PartialConfig>>,
|
||||
) -> anyhow::Result<UpdatesResult<Self::PartialConfig>> {
|
||||
let map = Self::name_to_resource();
|
||||
|
||||
// (name, partial config)
|
||||
let mut to_update =
|
||||
Vec::<(String, Resource<Self::PartialConfig>)>::new();
|
||||
let mut to_create = Vec::<Resource<Self::PartialConfig>>::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::<Vec<_>>()
|
||||
.join(", ")
|
||||
);
|
||||
}
|
||||
|
||||
if !to_update.is_empty() {
|
||||
println!(
|
||||
"\nTO UPDATE: {}",
|
||||
to_update
|
||||
.iter()
|
||||
.map(|(_, item)| item.name.as_str())
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
);
|
||||
}
|
||||
|
||||
Ok((to_update, to_create))
|
||||
}
|
||||
|
||||
async fn run_updates(
|
||||
to_update: ToUpdate<Self::PartialConfig>,
|
||||
to_create: ToCreate<Self::PartialConfig>,
|
||||
) {
|
||||
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::<HashMap<_, _>>();
|
||||
|
||||
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<String, String>,
|
||||
) {
|
||||
// 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<tag_id>
|
||||
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:#}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<String, ResourceListItem<Self::ListItemInfo>>
|
||||
{
|
||||
name_to_alerter()
|
||||
}
|
||||
|
||||
async fn init_lookup_data() -> Self::ExtLookup {
|
||||
()
|
||||
}
|
||||
|
||||
async fn create(
|
||||
resource: Resource<Self::PartialConfig>,
|
||||
_: &(),
|
||||
) -> anyhow::Result<String> {
|
||||
monitor_client()
|
||||
.write(CreateAlerter {
|
||||
name: resource.name,
|
||||
config: resource.config,
|
||||
})
|
||||
.await
|
||||
.map(|res| res.id)
|
||||
}
|
||||
|
||||
async fn update(
|
||||
id: String,
|
||||
resource: Resource<Self::PartialConfig>,
|
||||
_: &(),
|
||||
) -> anyhow::Result<()> {
|
||||
monitor_client()
|
||||
.write(UpdateAlerter {
|
||||
id,
|
||||
config: resource.config,
|
||||
})
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -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<String, String>;
|
||||
|
||||
fn display() -> &'static str {
|
||||
"build"
|
||||
}
|
||||
|
||||
fn resource_target(id: String) -> ResourceTarget {
|
||||
ResourceTarget::Build(id)
|
||||
}
|
||||
|
||||
fn name_to_resource(
|
||||
) -> &'static HashMap<String, ResourceListItem<Self::ListItemInfo>>
|
||||
{
|
||||
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::<HashMap<_, _>>()
|
||||
}
|
||||
|
||||
async fn create(
|
||||
mut resource: Resource<Self::PartialConfig>,
|
||||
builder_name_to_id: &Self::ExtLookup,
|
||||
) -> anyhow::Result<String> {
|
||||
// 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<Self::PartialConfig>,
|
||||
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(())
|
||||
}
|
||||
}
|
||||
@@ -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<String, ResourceListItem<Self::ListItemInfo>>
|
||||
{
|
||||
name_to_builder()
|
||||
}
|
||||
|
||||
async fn init_lookup_data() -> Self::ExtLookup {
|
||||
()
|
||||
}
|
||||
|
||||
async fn create(
|
||||
resource: Resource<Self::PartialConfig>,
|
||||
_: &(),
|
||||
) -> anyhow::Result<String> {
|
||||
monitor_client()
|
||||
.write(CreateBuilder {
|
||||
name: resource.name,
|
||||
config: resource.config,
|
||||
})
|
||||
.await
|
||||
.map(|res| res.id)
|
||||
}
|
||||
|
||||
async fn update(
|
||||
id: String,
|
||||
resource: Resource<Self::PartialConfig>,
|
||||
_: &(),
|
||||
) -> anyhow::Result<()> {
|
||||
monitor_client()
|
||||
.write(UpdateBuilder {
|
||||
id,
|
||||
config: resource.config,
|
||||
})
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -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<String, String>,
|
||||
pub builds: HashMap<String, String>,
|
||||
}
|
||||
|
||||
#[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<String, ResourceListItem<Self::ListItemInfo>>
|
||||
{
|
||||
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::<HashMap<_, _>>();
|
||||
|
||||
let builds = monitor_client()
|
||||
.read(ListBuilds::default())
|
||||
.await
|
||||
.expect("failed to get builds")
|
||||
.into_iter()
|
||||
.map(|b| (b.name, b.id))
|
||||
.collect::<HashMap<_, _>>();
|
||||
|
||||
DeploymentExtLookup { servers, builds }
|
||||
}
|
||||
|
||||
async fn create(
|
||||
mut resource: Resource<Self::PartialConfig>,
|
||||
lookup: &Self::ExtLookup,
|
||||
) -> anyhow::Result<String> {
|
||||
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<Self::PartialConfig>,
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
@@ -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<String, ResourceListItem<Self::ListItemInfo>>
|
||||
{
|
||||
name_to_repo()
|
||||
}
|
||||
|
||||
async fn init_lookup_data() -> Self::ExtLookup {
|
||||
()
|
||||
}
|
||||
|
||||
async fn create(
|
||||
resource: Resource<Self::PartialConfig>,
|
||||
_: &(),
|
||||
) -> anyhow::Result<String> {
|
||||
monitor_client()
|
||||
.write(CreateRepo {
|
||||
name: resource.name,
|
||||
config: resource.config,
|
||||
})
|
||||
.await
|
||||
.map(|res| res.id)
|
||||
}
|
||||
|
||||
async fn update(
|
||||
id: String,
|
||||
resource: Resource<Self::PartialConfig>,
|
||||
_: &(),
|
||||
) -> anyhow::Result<()> {
|
||||
monitor_client()
|
||||
.write(UpdateRepo {
|
||||
id,
|
||||
config: resource.config,
|
||||
})
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -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<String, ResourceListItem<Self::ListItemInfo>>
|
||||
{
|
||||
name_to_server()
|
||||
}
|
||||
|
||||
async fn init_lookup_data() -> Self::ExtLookup {
|
||||
()
|
||||
}
|
||||
|
||||
async fn create(
|
||||
resource: Resource<Self::PartialConfig>,
|
||||
_: &(),
|
||||
) -> anyhow::Result<String> {
|
||||
monitor_client()
|
||||
.write(CreateServer {
|
||||
name: resource.name,
|
||||
config: resource.config,
|
||||
})
|
||||
.await
|
||||
.map(|res| res.id)
|
||||
}
|
||||
|
||||
async fn update(
|
||||
id: String,
|
||||
resource: Resource<Self::PartialConfig>,
|
||||
_: &(),
|
||||
) -> anyhow::Result<()> {
|
||||
monitor_client()
|
||||
.write(UpdateServer {
|
||||
id,
|
||||
config: resource.config,
|
||||
})
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -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<T> = Vec<(String, Resource<T>)>;
|
||||
type ToCreate<T> = Vec<Resource<T>>;
|
||||
type UpdatesResult<T> = (ToUpdate<T>, ToCreate<T>);
|
||||
|
||||
#[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<String, ResourceListItem<Self::ListItemInfo>>;
|
||||
|
||||
/// Returns created id
|
||||
async fn create(
|
||||
resource: Resource<Self::PartialConfig>,
|
||||
) -> anyhow::Result<String>;
|
||||
|
||||
async fn update(
|
||||
id: String,
|
||||
resource: Resource<Self::PartialConfig>,
|
||||
) -> anyhow::Result<()>;
|
||||
|
||||
fn get_updates(
|
||||
resources: Vec<Resource<Self::PartialConfig>>,
|
||||
) -> anyhow::Result<UpdatesResult<Self::PartialConfig>> {
|
||||
let map = Self::name_to_resource();
|
||||
|
||||
// (name, partial config)
|
||||
let mut to_update =
|
||||
Vec::<(String, Resource<Self::PartialConfig>)>::new();
|
||||
let mut to_create = Vec::<Resource<Self::PartialConfig>>::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::<Vec<_>>()
|
||||
.join(", ")
|
||||
);
|
||||
}
|
||||
|
||||
if !to_update.is_empty() {
|
||||
println!(
|
||||
"\nTO UPDATE: {}",
|
||||
to_update
|
||||
.iter()
|
||||
.map(|(_, item)| item.name.as_str())
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
);
|
||||
}
|
||||
|
||||
Ok((to_update, to_create))
|
||||
}
|
||||
|
||||
async fn run_updates(
|
||||
to_update: ToUpdate<Self::PartialConfig>,
|
||||
to_create: ToCreate<Self::PartialConfig>,
|
||||
) {
|
||||
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::<HashMap<_, _>>();
|
||||
|
||||
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<String, String>,
|
||||
) {
|
||||
// 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<tag_id>
|
||||
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<String, ResourceListItem<Self::ListItemInfo>>
|
||||
{
|
||||
name_to_server()
|
||||
}
|
||||
|
||||
async fn create(
|
||||
resource: Resource<Self::PartialConfig>,
|
||||
) -> anyhow::Result<String> {
|
||||
monitor_client()
|
||||
.write(write::CreateServer {
|
||||
name: resource.name,
|
||||
config: resource.config,
|
||||
})
|
||||
.await
|
||||
.map(|res| res.id)
|
||||
}
|
||||
|
||||
async fn update(
|
||||
id: String,
|
||||
resource: Resource<Self::PartialConfig>,
|
||||
) -> 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<String, ResourceListItem<Self::ListItemInfo>>
|
||||
{
|
||||
name_to_deployment()
|
||||
}
|
||||
|
||||
async fn create(
|
||||
resource: Resource<Self::PartialConfig>,
|
||||
) -> anyhow::Result<String> {
|
||||
monitor_client()
|
||||
.write(write::CreateDeployment {
|
||||
name: resource.name,
|
||||
config: resource.config,
|
||||
})
|
||||
.await
|
||||
.map(|res| res.id)
|
||||
}
|
||||
|
||||
async fn update(
|
||||
id: String,
|
||||
resource: Resource<Self::PartialConfig>,
|
||||
) -> 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<String, ResourceListItem<Self::ListItemInfo>>
|
||||
{
|
||||
name_to_build()
|
||||
}
|
||||
|
||||
async fn create(
|
||||
resource: Resource<Self::PartialConfig>,
|
||||
) -> anyhow::Result<String> {
|
||||
monitor_client()
|
||||
.write(write::CreateBuild {
|
||||
name: resource.name,
|
||||
config: resource.config,
|
||||
})
|
||||
.await
|
||||
.map(|res| res.id)
|
||||
}
|
||||
|
||||
async fn update(
|
||||
id: String,
|
||||
resource: Resource<Self::PartialConfig>,
|
||||
) -> 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<String, ResourceListItem<Self::ListItemInfo>>
|
||||
{
|
||||
name_to_builder()
|
||||
}
|
||||
|
||||
async fn create(
|
||||
resource: Resource<Self::PartialConfig>,
|
||||
) -> anyhow::Result<String> {
|
||||
monitor_client()
|
||||
.write(write::CreateBuilder {
|
||||
name: resource.name,
|
||||
config: resource.config,
|
||||
})
|
||||
.await
|
||||
.map(|res| res.id)
|
||||
}
|
||||
|
||||
async fn update(
|
||||
id: String,
|
||||
resource: Resource<Self::PartialConfig>,
|
||||
) -> 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<String, ResourceListItem<Self::ListItemInfo>>
|
||||
{
|
||||
name_to_alerter()
|
||||
}
|
||||
|
||||
async fn create(
|
||||
resource: Resource<Self::PartialConfig>,
|
||||
) -> anyhow::Result<String> {
|
||||
monitor_client()
|
||||
.write(write::CreateAlerter {
|
||||
name: resource.name,
|
||||
config: resource.config,
|
||||
})
|
||||
.await
|
||||
.map(|res| res.id)
|
||||
}
|
||||
|
||||
async fn update(
|
||||
id: String,
|
||||
resource: Resource<Self::PartialConfig>,
|
||||
) -> 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<String, ResourceListItem<Self::ListItemInfo>>
|
||||
{
|
||||
name_to_repo()
|
||||
}
|
||||
|
||||
async fn create(
|
||||
resource: Resource<Self::PartialConfig>,
|
||||
) -> anyhow::Result<String> {
|
||||
monitor_client()
|
||||
.write(write::CreateRepo {
|
||||
name: resource.name,
|
||||
config: resource.config,
|
||||
})
|
||||
.await
|
||||
.map(|res| res.id)
|
||||
}
|
||||
|
||||
async fn update(
|
||||
id: String,
|
||||
resource: Resource<Self::PartialConfig>,
|
||||
) -> anyhow::Result<()> {
|
||||
monitor_client()
|
||||
.write(write::UpdateRepo {
|
||||
id,
|
||||
config: resource.config,
|
||||
})
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user