@@ -24,6 +24,7 @@ use std::{
2424
2525use async_trait:: async_trait;
2626use base64:: Engine ;
27+ use bytes:: Bytes ;
2728use chrono:: Utc ;
2829use http:: { header:: AUTHORIZATION , HeaderMap , HeaderValue } ;
2930use humantime_serde:: re:: humantime;
@@ -35,7 +36,7 @@ use tracing::{error, trace, warn};
3536use ulid:: Ulid ;
3637use url:: Url ;
3738
38- use crate :: { alerts:: AlertError , parseable:: PARSEABLE } ;
39+ use crate :: { alerts:: AlertError , parseable:: PARSEABLE , storage :: object_storage :: target_json_path } ;
3940
4041use super :: ALERTS ;
4142
@@ -65,7 +66,12 @@ impl TargetConfigs {
6566
6667 pub async fn update ( & self , target : Target ) -> Result < ( ) , AlertError > {
6768 let id = target. id ;
68- self . target_configs . write ( ) . await . insert ( id, target) ;
69+ self . target_configs . write ( ) . await . insert ( id, target. clone ( ) ) ;
70+ let path = target_json_path ( & id) ;
71+
72+ let store = PARSEABLE . storage . get_object_store ( ) ;
73+ let target_bytes = serde_json:: to_vec ( & target) ?;
74+ store. put_object ( & path, Bytes :: from ( target_bytes) ) . await ?;
6975 Ok ( ( ) )
7076 }
7177
@@ -81,24 +87,38 @@ impl TargetConfigs {
8187 }
8288
8389 pub async fn get_target_by_id ( & self , target_id : & Ulid ) -> Result < Target , AlertError > {
84- self . target_configs
90+ let target = self
91+ . target_configs
8592 . read ( )
8693 . await
8794 . get ( target_id)
8895 . ok_or ( AlertError :: InvalidTargetID ( target_id. to_string ( ) ) )
89- . cloned ( )
96+ . cloned ( ) ?;
97+
98+ Ok ( target)
9099 }
91100
92101 pub async fn delete ( & self , target_id : & Ulid ) -> Result < Target , AlertError > {
93- self . target_configs
102+ // ensure that the target is not being used by any alert
103+ for ( _, alert) in ALERTS . alerts . read ( ) . await . iter ( ) {
104+ if alert. targets . contains ( target_id) {
105+ return Err ( AlertError :: TargetInUse ) ;
106+ }
107+ }
108+ let target = self
109+ . target_configs
94110 . write ( )
95111 . await
96112 . remove ( target_id)
97- . ok_or ( AlertError :: InvalidTargetID ( target_id. to_string ( ) ) )
113+ . ok_or ( AlertError :: InvalidTargetID ( target_id. to_string ( ) ) ) ?;
114+ let path = target_json_path ( & target. id ) ;
115+ let store = PARSEABLE . storage . get_object_store ( ) ;
116+ store. delete_object ( & path) . await ?;
117+ Ok ( target)
98118 }
99119}
100120
101- #[ derive( Debug , Clone , Copy , serde:: Serialize , serde:: Deserialize ) ]
121+ #[ derive( Debug , Clone , Copy , serde:: Serialize , serde:: Deserialize , PartialEq ) ]
102122#[ serde( rename_all = "camelCase" ) ]
103123#[ serde( untagged) ]
104124pub enum Retry {
@@ -125,9 +145,19 @@ pub struct Target {
125145}
126146
127147impl Target {
128- pub async fn validate ( & self ) {
148+ pub async fn validate ( & self ) -> Result < ( ) , AlertError > {
129149 // just check for liveness
130150 // what if the target is not live yet but is added by the user?
151+ let targets = TARGETS . list ( ) . await ?;
152+ for target in targets {
153+ if target. target == self . target
154+ && target. timeout . interval == self . timeout . interval
155+ && target. timeout . times == self . timeout . times
156+ {
157+ return Err ( AlertError :: DuplicateTargetConfig ) ;
158+ }
159+ }
160+ Ok ( ( ) )
131161 }
132162
133163 pub fn call ( & self , context : Context ) {
0 commit comments