1
+ use bech32:: ToBase32 ;
1
2
use futures:: StreamExt ;
2
3
use kube:: {
3
4
api:: { Patch , PatchParams } ,
@@ -13,28 +14,14 @@ use rand::distributions::{Alphanumeric, DistString};
13
14
use schemars:: JsonSchema ;
14
15
use serde:: { Deserialize , Serialize } ;
15
16
use serde_json:: json;
17
+ use sha3:: { Digest , Sha3_256 } ;
16
18
use std:: { sync:: Arc , time:: Duration } ;
17
19
use tracing:: error;
18
20
19
- use crate :: { postgres:: Postgres , Config , Error , Metrics , Network , State } ;
21
+ use crate :: { postgres:: Postgres , Error , Network , State } ;
20
22
21
23
pub static DB_SYNC_PORT_FINALIZER : & str = "dbsyncports.demeter.run" ;
22
24
23
- struct Context {
24
- pub client : Client ,
25
- pub metrics : Metrics ,
26
- pub config : Config ,
27
- }
28
- impl Context {
29
- pub fn new ( client : Client , metrics : Metrics , config : Config ) -> Self {
30
- Self {
31
- client,
32
- metrics,
33
- config,
34
- }
35
- }
36
- }
37
-
38
25
#[ derive( CustomResource , Deserialize , Serialize , Clone , Debug , JsonSchema ) ]
39
26
#[ kube(
40
27
kind = "DbSyncPort" ,
@@ -64,22 +51,19 @@ impl DbSyncPort {
64
51
. unwrap_or ( false )
65
52
}
66
53
67
- async fn reconcile ( & self , ctx : Arc < Context > , pg : & mut Postgres ) -> Result < Action , Error > {
68
- let client = ctx . client . clone ( ) ;
54
+ async fn reconcile ( & self , state : Arc < State > , pg : & Postgres ) -> Result < Action , Error > {
55
+ let client = state . kube_client . clone ( ) ;
69
56
let ns = self . namespace ( ) . unwrap ( ) ;
70
57
let name = self . name_any ( ) ;
71
58
let crds: Api < DbSyncPort > = Api :: namespaced ( client, & ns) ;
72
59
73
- let username = format ! ( "{name}.{ns}" ) ;
60
+ let username = gen_username_hash ( & format ! ( "{name}.{ns}" ) ) . await ? ;
74
61
let password = Alphanumeric . sample_string ( & mut rand:: thread_rng ( ) , 16 ) ;
75
62
76
63
if !self . was_executed ( ) {
77
- match pg. user_already_exists ( & username) . await ? {
78
- true => pg. user_enable ( & username, & password) . await ?,
79
- false => pg. user_create ( & username, & password) . await ?,
80
- } ;
64
+ pg. create_user ( & username, & password) . await ?;
81
65
82
- let new_status = Patch :: Apply ( json ! ( {
66
+ let status = Patch :: Apply ( json ! ( {
83
67
"apiVersion" : "demeter.run/v1alpha1" ,
84
68
"kind" : "DbSyncPort" ,
85
69
"status" : DbSyncPortStatus {
@@ -89,61 +73,77 @@ impl DbSyncPort {
89
73
} ) ) ;
90
74
91
75
let ps = PatchParams :: apply ( "cntrlr" ) . force ( ) ;
92
- crds. patch_status ( & name, & ps, & new_status )
76
+ crds. patch_status ( & name, & ps, & status )
93
77
. await
94
78
. map_err ( Error :: KubeError ) ?;
95
79
96
- ctx . metrics . count_user_created ( & username ) ;
80
+ state . metrics . count_user_created ( & ns , & self . spec . network ) ;
97
81
} ;
98
82
99
- Ok ( Action :: requeue ( Duration :: from_secs ( 5 * 60 ) ) )
83
+ Ok ( Action :: await_change ( ) )
100
84
}
101
85
102
- async fn cleanup ( & self , ctx : Arc < Context > , pg : & mut Postgres ) -> Result < Action , Error > {
103
- let username = self . status . as_ref ( ) . unwrap ( ) . username . clone ( ) ;
104
- pg. user_disable ( & username) . await ?;
105
- ctx. metrics . count_user_deactivated ( & username) ;
86
+ async fn cleanup ( & self , state : Arc < State > , pg : & Postgres ) -> Result < Action , Error > {
87
+ if self . was_executed ( ) {
88
+ let ns = self . namespace ( ) . unwrap ( ) ;
89
+ let username = self . status . as_ref ( ) . unwrap ( ) . username . clone ( ) ;
90
+ pg. drop_user ( & username) . await ?;
91
+ state
92
+ . metrics
93
+ . count_user_droped ( & ns, & self . spec . network ) ;
94
+ }
95
+
106
96
Ok ( Action :: await_change ( ) )
107
97
}
108
98
}
109
99
110
- async fn reconcile ( crd : Arc < DbSyncPort > , ctx : Arc < Context > ) -> Result < Action , Error > {
111
- let url = match crd. spec . network {
112
- Network :: Mainnet => & ctx. config . db_url_mainnet ,
113
- Network :: Preprod => & ctx. config . db_url_preprod ,
114
- Network :: Preview => & ctx. config . db_url_preview ,
115
- } ;
116
-
100
+ async fn reconcile ( crd : Arc < DbSyncPort > , state : Arc < State > ) -> Result < Action , Error > {
117
101
let ns = crd. namespace ( ) . unwrap ( ) ;
118
- let crds: Api < DbSyncPort > = Api :: namespaced ( ctx . client . clone ( ) , & ns) ;
102
+ let crds: Api < DbSyncPort > = Api :: namespaced ( state . kube_client . clone ( ) , & ns) ;
119
103
120
- let mut postgres = Postgres :: new ( url ) . await ? ;
104
+ let postgres = state . get_pg_by_network ( & crd . spec . network ) ;
121
105
122
106
finalizer ( & crds, DB_SYNC_PORT_FINALIZER , crd, |event| async {
123
107
match event {
124
- Event :: Apply ( crd) => crd. reconcile ( ctx . clone ( ) , & mut postgres) . await ,
125
- Event :: Cleanup ( crd) => crd. cleanup ( ctx . clone ( ) , & mut postgres) . await ,
108
+ Event :: Apply ( crd) => crd. reconcile ( state . clone ( ) , & postgres) . await ,
109
+ Event :: Cleanup ( crd) => crd. cleanup ( state . clone ( ) , & postgres) . await ,
126
110
}
127
111
} )
128
112
. await
129
113
. map_err ( |e| Error :: FinalizerError ( Box :: new ( e) ) )
130
114
}
131
115
132
- fn error_policy ( crd : Arc < DbSyncPort > , err : & Error , ctx : Arc < Context > ) -> Action {
116
+ fn error_policy ( crd : Arc < DbSyncPort > , err : & Error , state : Arc < State > ) -> Action {
133
117
error ! ( "reconcile failed: {:?}" , err) ;
134
- ctx . metrics . reconcile_failure ( & crd, err) ;
118
+ state . metrics . reconcile_failure ( & crd, err) ;
135
119
Action :: requeue ( Duration :: from_secs ( 5 ) )
136
120
}
137
121
138
- pub async fn run ( state : Arc < State > , config : Config ) -> Result < ( ) , Error > {
122
+ async fn gen_username_hash ( username : & str ) -> Result < String , Error > {
123
+ let mut hasher = Sha3_256 :: new ( ) ;
124
+ hasher. update ( username) ;
125
+ let sha256_hash = hasher. finalize ( ) ;
126
+
127
+ let bech32_hash = bech32:: encode (
128
+ "dmtr_dbsync" ,
129
+ sha256_hash. to_base32 ( ) ,
130
+ bech32:: Variant :: Bech32 ,
131
+ ) ?;
132
+
133
+ let bech32_truncated: String = bech32_hash. chars ( ) . take ( 32 ) . collect ( ) ;
134
+
135
+ Ok ( bech32_truncated)
136
+ }
137
+
138
+ pub async fn run ( state : Arc < State > ) -> Result < ( ) , Error > {
139
139
let client = Client :: try_default ( ) . await ?;
140
140
let crds = Api :: < DbSyncPort > :: all ( client. clone ( ) ) ;
141
141
142
- let ctx = Context :: new ( client, state. metrics . clone ( ) , config ) ;
142
+ // let ctx = Context::new(client, state.clone());
143
143
144
144
Controller :: new ( crds, WatcherConfig :: default ( ) . any_semantic ( ) )
145
145
. shutdown_on_signal ( )
146
- . run ( reconcile, error_policy, Arc :: new ( ctx ) )
146
+ . run ( reconcile, error_policy, state )
147
147
. for_each ( |_| futures:: future:: ready ( ( ) ) )
148
148
. await ;
149
149
0 commit comments