mirror of
https://github.com/moghtech/komodo.git
synced 2026-08-01 18:59:59 -05:00
monrun sync
This commit is contained in:
Generated
+1
@@ -2206,6 +2206,7 @@ name = "monrun"
|
||||
version = "1.0.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
"clap",
|
||||
"futures",
|
||||
"monitor_client",
|
||||
|
||||
@@ -19,4 +19,5 @@ toml.workspace = true
|
||||
clap.workspace = true
|
||||
futures.workspace = true
|
||||
tracing.workspace = true
|
||||
tracing-subscriber.workspace = true
|
||||
tracing-subscriber.workspace = true
|
||||
async-trait.workspace = true
|
||||
@@ -10,7 +10,7 @@ use serde::{de::DeserializeOwned, Deserialize};
|
||||
|
||||
mod execution;
|
||||
mod maps;
|
||||
mod resource;
|
||||
mod sync;
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
#[command(version, about, long_about = None)]
|
||||
@@ -29,9 +29,7 @@ fn cli_args() -> &'static CliArgs {
|
||||
#[derive(Debug, Clone, Subcommand)]
|
||||
enum Command {
|
||||
/// Runs syncs on resource files
|
||||
Resource {
|
||||
/// The resource action to take
|
||||
action: resource::SyncDirection,
|
||||
Sync {
|
||||
/// The path of the resource folder / file
|
||||
/// Folder paths will recursively incorporate all the resources it finds under the folder
|
||||
#[arg(default_value_t = String::from("./resources"))]
|
||||
@@ -72,9 +70,8 @@ async fn main() -> anyhow::Result<()> {
|
||||
|
||||
match &cli_args().command {
|
||||
Command::Exec { path } => execution::run_execution(path).await?,
|
||||
Command::Resource { action, path } => {
|
||||
resource::run_resource(*action, &PathBuf::from_str(path)?)
|
||||
.await?
|
||||
Command::Sync { path } => {
|
||||
sync::run_sync(&PathBuf::from_str(path)?).await?
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+48
-2
@@ -4,8 +4,10 @@ use anyhow::Context;
|
||||
use monitor_client::{
|
||||
api::read,
|
||||
entities::{
|
||||
build::BuildListItem, deployment::DeploymentListItem,
|
||||
resource::ResourceListItem, server::ServerListItem,
|
||||
alerter::AlerterListItem, build::BuildListItem,
|
||||
builder::BuilderListItem, deployment::DeploymentListItem,
|
||||
repo::RepoListItem, resource::ResourceListItem,
|
||||
server::ServerListItem,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -69,3 +71,47 @@ pub fn name_to_server() -> &'static HashMap<String, ServerListItem> {
|
||||
.collect()
|
||||
})
|
||||
}
|
||||
|
||||
pub fn name_to_builder() -> &'static HashMap<String, BuilderListItem>
|
||||
{
|
||||
static NAME_TO_BUILDER: OnceLock<HashMap<String, BuilderListItem>> =
|
||||
OnceLock::new();
|
||||
NAME_TO_BUILDER.get_or_init(|| {
|
||||
futures::executor::block_on(
|
||||
monitor_client().read(read::ListBuilders::default()),
|
||||
)
|
||||
.expect("failed to get builders from monitor")
|
||||
.into_iter()
|
||||
.map(|builder| (builder.name.clone(), builder))
|
||||
.collect()
|
||||
})
|
||||
}
|
||||
|
||||
pub fn name_to_alerter() -> &'static HashMap<String, AlerterListItem>
|
||||
{
|
||||
static NAME_TO_ALERTER: OnceLock<HashMap<String, AlerterListItem>> =
|
||||
OnceLock::new();
|
||||
NAME_TO_ALERTER.get_or_init(|| {
|
||||
futures::executor::block_on(
|
||||
monitor_client().read(read::ListAlerters::default()),
|
||||
)
|
||||
.expect("failed to get alerters from monitor")
|
||||
.into_iter()
|
||||
.map(|alerter| (alerter.name.clone(), alerter))
|
||||
.collect()
|
||||
})
|
||||
}
|
||||
|
||||
pub fn name_to_repo() -> &'static HashMap<String, RepoListItem> {
|
||||
static NAME_TO_ALERTER: OnceLock<HashMap<String, RepoListItem>> =
|
||||
OnceLock::new();
|
||||
NAME_TO_ALERTER.get_or_init(|| {
|
||||
futures::executor::block_on(
|
||||
monitor_client().read(read::ListRepos::default()),
|
||||
)
|
||||
.expect("failed to get repos from monitor")
|
||||
.into_iter()
|
||||
.map(|repo| (repo.name.clone(), repo))
|
||||
.collect()
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,173 +0,0 @@
|
||||
use std::{fs, path::Path};
|
||||
|
||||
use anyhow::{anyhow, Context};
|
||||
use clap::ValueEnum;
|
||||
use monitor_client::{
|
||||
api::write,
|
||||
entities::{
|
||||
build::PartialBuildConfig, deployment::PartialDeploymentConfig,
|
||||
resource::Resource, server::PartialServerConfig,
|
||||
},
|
||||
};
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::{maps::name_to_server, monitor_client, wait_for_enter};
|
||||
|
||||
pub async fn run_resource(
|
||||
action: SyncDirection,
|
||||
path: &Path,
|
||||
) -> anyhow::Result<()> {
|
||||
info!("action: {action:?} | path: {path:?}");
|
||||
|
||||
let resources = read_resources(path)?;
|
||||
|
||||
match action {
|
||||
SyncDirection::Up => run_resource_up(resources).await,
|
||||
SyncDirection::Down => {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn run_resource_up(
|
||||
resources: ResourceFile,
|
||||
) -> anyhow::Result<()> {
|
||||
let servers = name_to_server();
|
||||
|
||||
// (name, partial config)
|
||||
let mut to_update =
|
||||
Vec::<(String, Resource<PartialServerConfig>)>::new();
|
||||
let mut to_create = Vec::<Resource<PartialServerConfig>>::new();
|
||||
|
||||
for server in resources.servers {
|
||||
match servers.get(&server.name).map(|s| s.id.clone()) {
|
||||
Some(id) => {
|
||||
to_update.push((id, server));
|
||||
}
|
||||
None => {
|
||||
to_create.push(server);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !to_create.is_empty() {
|
||||
println!(
|
||||
"\nTO CREATE: {}",
|
||||
to_create
|
||||
.iter()
|
||||
.map(|server| server.name.as_str())
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
);
|
||||
}
|
||||
|
||||
if !to_update.is_empty() {
|
||||
println!(
|
||||
"\nTO UPDATE: {}",
|
||||
to_update
|
||||
.iter()
|
||||
.map(|(_, server)| server.name.as_str())
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
);
|
||||
}
|
||||
|
||||
wait_for_enter("CONTINUE")?;
|
||||
|
||||
for (id, server) in to_update {
|
||||
if let Err(e) = monitor_client()
|
||||
.write(write::UpdateServer {
|
||||
id,
|
||||
config: server.config,
|
||||
})
|
||||
.await
|
||||
{
|
||||
warn!("failed to update server {} | {e:#}", server.name)
|
||||
}
|
||||
}
|
||||
|
||||
for server in to_create {
|
||||
if let Err(e) = monitor_client()
|
||||
.write(write::CreateServer {
|
||||
name: server.name.clone(),
|
||||
config: server.config,
|
||||
})
|
||||
.await
|
||||
{
|
||||
warn!("failed to create server {} | {e:#}", server.name)
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Specifies resources to sync on monitor
|
||||
#[derive(Debug, Clone, Default, Deserialize)]
|
||||
struct ResourceFile {
|
||||
#[serde(default, rename = "server")]
|
||||
servers: Vec<Resource<PartialServerConfig>>,
|
||||
#[serde(default, rename = "build")]
|
||||
builds: Vec<Resource<PartialBuildConfig>>,
|
||||
#[serde(default, rename = "deployment")]
|
||||
deployments: Vec<Resource<PartialDeploymentConfig>>,
|
||||
// #[serde(rename = "builder")]
|
||||
// builders: (),
|
||||
// #[serde(rename = "repo")]
|
||||
// repos: (),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, ValueEnum)]
|
||||
pub enum SyncDirection {
|
||||
/// Brings up resources / updates
|
||||
Up,
|
||||
/// Takes down / deletes resources
|
||||
Down,
|
||||
}
|
||||
|
||||
fn read_resources(path: &Path) -> anyhow::Result<ResourceFile> {
|
||||
let mut res = ResourceFile::default();
|
||||
read_resources_recursive(path, &mut res)?;
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
fn read_resources_recursive(
|
||||
path: &Path,
|
||||
resources: &mut ResourceFile,
|
||||
) -> anyhow::Result<()> {
|
||||
let res =
|
||||
fs::metadata(path).context("failed to get path metadata")?;
|
||||
if res.is_file() {
|
||||
if !path
|
||||
.extension()
|
||||
.map(|ext| ext == "toml")
|
||||
.unwrap_or_default()
|
||||
{
|
||||
return Ok(());
|
||||
}
|
||||
let more = match crate::parse_toml_file::<ResourceFile>(path) {
|
||||
Ok(res) => res,
|
||||
Err(e) => {
|
||||
warn!("failed to parse {:?}. skipping file | {e:#}", path);
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
info!("adding resources from {path:?}");
|
||||
resources.servers.extend(more.servers);
|
||||
resources.builds.extend(more.builds);
|
||||
resources.deployments.extend(more.deployments);
|
||||
Ok(())
|
||||
} else if res.is_dir() {
|
||||
let directory = fs::read_dir(path)
|
||||
.context("failed to read directory contents")?;
|
||||
for entry in directory.into_iter().flatten() {
|
||||
if let Err(e) =
|
||||
read_resources_recursive(&entry.path(), resources)
|
||||
{
|
||||
warn!("failed to read additional resources at path | {e:#}");
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
} else {
|
||||
Err(anyhow!("resources path is neither file nor directory"))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
use std::path::Path;
|
||||
|
||||
use monitor_client::entities::{
|
||||
alerter::Alerter, build::Build, builder::Builder,
|
||||
deployment::Deployment, repo::Repo, server::Server,
|
||||
};
|
||||
|
||||
use crate::wait_for_enter;
|
||||
|
||||
mod resource_file;
|
||||
mod sync_trait;
|
||||
|
||||
use sync_trait::Sync;
|
||||
|
||||
pub async fn run_sync(path: &Path) -> anyhow::Result<()> {
|
||||
info!("path: {path:?}");
|
||||
|
||||
let resources = resource_file::read_resources(path)?;
|
||||
|
||||
let (server_updates, server_creates) =
|
||||
Server::get_updates(resources.servers)?;
|
||||
let (deployment_updates, deployment_creates) =
|
||||
Deployment::get_updates(resources.deployments)?;
|
||||
let (build_updates, build_creates) =
|
||||
Build::get_updates(resources.builds)?;
|
||||
let (builder_updates, builder_creates) =
|
||||
Builder::get_updates(resources.builders)?;
|
||||
let (alerter_updates, alerter_creates) =
|
||||
Alerter::get_updates(resources.alerters)?;
|
||||
let (repo_updates, repo_creates) =
|
||||
Repo::get_updates(resources.repos)?;
|
||||
|
||||
wait_for_enter("CONTINUE")?;
|
||||
|
||||
Build::run_updates(build_updates, build_creates).await;
|
||||
Server::run_updates(server_updates, server_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(())
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
use std::{fs, path::Path};
|
||||
|
||||
use anyhow::{anyhow, Context};
|
||||
use monitor_client::entities::{
|
||||
alerter::PartialAlerterConfig, build::PartialBuildConfig,
|
||||
builder::PartialBuilderConfig, deployment::PartialDeploymentConfig,
|
||||
repo::PartialRepoConfig, resource::Resource,
|
||||
server::PartialServerConfig,
|
||||
};
|
||||
use serde::Deserialize;
|
||||
|
||||
/// Specifies resources to sync on monitor
|
||||
#[derive(Debug, Clone, Default, Deserialize)]
|
||||
pub struct ResourceFile {
|
||||
#[serde(default, rename = "server")]
|
||||
pub servers: Vec<Resource<PartialServerConfig>>,
|
||||
#[serde(default, rename = "build")]
|
||||
pub builds: Vec<Resource<PartialBuildConfig>>,
|
||||
#[serde(default, rename = "deployment")]
|
||||
pub deployments: Vec<Resource<PartialDeploymentConfig>>,
|
||||
#[serde(rename = "builder")]
|
||||
pub builders: Vec<Resource<PartialBuilderConfig>>,
|
||||
#[serde(rename = "repo")]
|
||||
pub repos: Vec<Resource<PartialRepoConfig>>,
|
||||
#[serde(rename = "alerter")]
|
||||
pub alerters: Vec<Resource<PartialAlerterConfig>>,
|
||||
}
|
||||
|
||||
pub fn read_resources(path: &Path) -> anyhow::Result<ResourceFile> {
|
||||
let mut res = ResourceFile::default();
|
||||
read_resources_recursive(path, &mut res)?;
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
fn read_resources_recursive(
|
||||
path: &Path,
|
||||
resources: &mut ResourceFile,
|
||||
) -> anyhow::Result<()> {
|
||||
let res =
|
||||
fs::metadata(path).context("failed to get path metadata")?;
|
||||
if res.is_file() {
|
||||
if !path
|
||||
.extension()
|
||||
.map(|ext| ext == "toml")
|
||||
.unwrap_or_default()
|
||||
{
|
||||
return Ok(());
|
||||
}
|
||||
let more = match crate::parse_toml_file::<ResourceFile>(path) {
|
||||
Ok(res) => res,
|
||||
Err(e) => {
|
||||
warn!("failed to parse {:?}. skipping file | {e:#}", path);
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
info!("adding resources from {path:?}");
|
||||
resources.servers.extend(more.servers);
|
||||
resources.builds.extend(more.builds);
|
||||
resources.deployments.extend(more.deployments);
|
||||
resources.builders.extend(more.builders);
|
||||
resources.repos.extend(more.repos);
|
||||
resources.alerters.extend(more.alerters);
|
||||
Ok(())
|
||||
} else if res.is_dir() {
|
||||
let directory = fs::read_dir(path)
|
||||
.context("failed to read directory contents")?;
|
||||
for entry in directory.into_iter().flatten() {
|
||||
if let Err(e) =
|
||||
read_resources_recursive(&entry.path(), resources)
|
||||
{
|
||||
warn!("failed to read additional resources at path | {e:#}");
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
} else {
|
||||
Err(anyhow!("resources path is neither file nor directory"))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,360 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use monitor_client::{
|
||||
api::write,
|
||||
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},
|
||||
},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
maps::{
|
||||
name_to_alerter, name_to_build, name_to_builder,
|
||||
name_to_deployment, name_to_repo, name_to_server,
|
||||
},
|
||||
monitor_client,
|
||||
};
|
||||
|
||||
#[async_trait]
|
||||
impl Sync for Server {
|
||||
type ListItemInfo = ServerListItemInfo;
|
||||
type PartialConfig = PartialServerConfig;
|
||||
|
||||
fn display() -> &'static str {
|
||||
"server"
|
||||
}
|
||||
|
||||
fn name_to_resource(
|
||||
) -> &'static HashMap<String, ResourceListItem<Self::ListItemInfo>>
|
||||
{
|
||||
name_to_server()
|
||||
}
|
||||
|
||||
async fn create(
|
||||
resource: Resource<Self::PartialConfig>,
|
||||
) -> anyhow::Result<()> {
|
||||
monitor_client()
|
||||
.write(write::CreateServer {
|
||||
name: resource.name,
|
||||
config: resource.config,
|
||||
})
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
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 name_to_resource(
|
||||
) -> &'static HashMap<String, ResourceListItem<Self::ListItemInfo>>
|
||||
{
|
||||
name_to_deployment()
|
||||
}
|
||||
|
||||
async fn create(
|
||||
resource: Resource<Self::PartialConfig>,
|
||||
) -> anyhow::Result<()> {
|
||||
monitor_client()
|
||||
.write(write::CreateDeployment {
|
||||
name: resource.name,
|
||||
config: resource.config,
|
||||
})
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
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 name_to_resource(
|
||||
) -> &'static HashMap<String, ResourceListItem<Self::ListItemInfo>>
|
||||
{
|
||||
name_to_build()
|
||||
}
|
||||
|
||||
async fn create(
|
||||
resource: Resource<Self::PartialConfig>,
|
||||
) -> anyhow::Result<()> {
|
||||
monitor_client()
|
||||
.write(write::CreateBuild {
|
||||
name: resource.name,
|
||||
config: resource.config,
|
||||
})
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
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 name_to_resource(
|
||||
) -> &'static HashMap<String, ResourceListItem<Self::ListItemInfo>>
|
||||
{
|
||||
name_to_builder()
|
||||
}
|
||||
|
||||
async fn create(
|
||||
resource: Resource<Self::PartialConfig>,
|
||||
) -> anyhow::Result<()> {
|
||||
monitor_client()
|
||||
.write(write::CreateBuilder {
|
||||
name: resource.name,
|
||||
config: resource.config,
|
||||
})
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
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 name_to_resource(
|
||||
) -> &'static HashMap<String, ResourceListItem<Self::ListItemInfo>>
|
||||
{
|
||||
name_to_alerter()
|
||||
}
|
||||
|
||||
async fn create(
|
||||
resource: Resource<Self::PartialConfig>,
|
||||
) -> anyhow::Result<()> {
|
||||
monitor_client()
|
||||
.write(write::CreateAlerter {
|
||||
name: resource.name,
|
||||
config: resource.config,
|
||||
})
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
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 name_to_resource(
|
||||
) -> &'static HashMap<String, ResourceListItem<Self::ListItemInfo>>
|
||||
{
|
||||
name_to_repo()
|
||||
}
|
||||
|
||||
async fn create(
|
||||
resource: Resource<Self::PartialConfig>,
|
||||
) -> anyhow::Result<()> {
|
||||
monitor_client()
|
||||
.write(write::CreateRepo {
|
||||
name: resource.name,
|
||||
config: resource.config,
|
||||
})
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn update(
|
||||
id: String,
|
||||
resource: Resource<Self::PartialConfig>,
|
||||
) -> anyhow::Result<()> {
|
||||
monitor_client()
|
||||
.write(write::UpdateRepo {
|
||||
id,
|
||||
config: resource.config,
|
||||
})
|
||||
.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 Sync {
|
||||
type PartialConfig: Send + 'static;
|
||||
type ListItemInfo: 'static;
|
||||
|
||||
fn display() -> &'static str;
|
||||
|
||||
fn name_to_resource(
|
||||
) -> &'static HashMap<String, ResourceListItem<Self::ListItemInfo>>;
|
||||
|
||||
async fn create(
|
||||
resource: Resource<Self::PartialConfig>,
|
||||
) -> anyhow::Result<()>;
|
||||
|
||||
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>,
|
||||
) {
|
||||
for (id, resource) in to_update {
|
||||
let name = resource.name.clone();
|
||||
if let Err(e) = Self::update(id, resource).await {
|
||||
warn!("failed to update {} {name} | {e:#}", Self::display(),)
|
||||
}
|
||||
}
|
||||
|
||||
for resource in to_create {
|
||||
let name = resource.name.clone();
|
||||
if let Err(e) = Self::create(resource).await {
|
||||
warn!("failed to create {} {name} | {e:#}", Self::display(),)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -7,6 +7,6 @@ cmd = "node ./client/ts/generate_types.mjs"
|
||||
path = "frontend"
|
||||
cmd = "yarn dev"
|
||||
|
||||
[monrun-resource]
|
||||
[monrun-sync]
|
||||
path = "bin/monrun"
|
||||
cmd = "cargo run -- resource up"
|
||||
cmd = "cargo run -- sync"
|
||||
Reference in New Issue
Block a user