From 08cc063bc9bdcdeb95d56fd03af1b487305aa919 Mon Sep 17 00:00:00 2001 From: Filipriec Date: Mon, 31 Aug 2026 14:24:22 +0200 Subject: [PATCH] superadmin managing backend --- client-gui2 | 2 +- common/proto/backup.proto | 35 +++ common/src/proto/descriptor.bin | Bin 210305 -> 212585 bytes common/src/proto/komp_ac.backup.rs | 355 +++++++++++++++++++++++++++++ server | 2 +- 5 files changed, 392 insertions(+), 2 deletions(-) diff --git a/client-gui2 b/client-gui2 index bdefd862..5c3181a6 160000 --- a/client-gui2 +++ b/client-gui2 @@ -1 +1 @@ -Subproject commit bdefd862ebf3a984b1621978e73e6576a3b34c86 +Subproject commit 5c3181a65d943639caab3182e723206da316eaef diff --git a/common/proto/backup.proto b/common/proto/backup.proto index 1589883a..65a189ed 100644 --- a/common/proto/backup.proto +++ b/common/proto/backup.proto @@ -9,6 +9,41 @@ service BackupService { rpc StartDump(komp_ac.common.Empty) returns (BackupOperationResponse); rpc GetBackupInfo(komp_ac.common.Empty) returns (BackupInfoResponse); rpc GetOperationStatus(GetOperationStatusRequest) returns (BackupOperationResponse); + rpc ListDatabases(komp_ac.common.Empty) returns (ListDatabasesResponse); + rpc CreateDatabase(CreateDatabaseRequest) returns (DatabaseInfo); + rpc RunDatabaseMigrations(DatabaseRequest) returns (DatabaseInfo); + rpc ActivateDatabase(DatabaseRequest) returns (ActivateDatabaseResponse); +} + +message DatabaseRequest { + string database_name = 1; +} + +message CreateDatabaseRequest { + string database_name = 1; +} + +message DatabaseInfo { + string database_name = 1; + bool active = 2; + bool connectable = 3; + int64 size_bytes = 4; + int32 applied_migrations = 5; + int32 pending_migrations = 6; + bool migration_dirty = 7; + bool application_database = 8; + string status = 9; +} + +message ListDatabasesResponse { + string mode = 1; + repeated DatabaseInfo databases = 2; +} + +message ActivateDatabaseResponse { + string database_name = 1; + bool switching = 2; + string message = 3; } enum BackupType { diff --git a/common/src/proto/descriptor.bin b/common/src/proto/descriptor.bin index 6c695577c03f7abae48473b4164b1553b86c1f3e..2bbd14515dd43b9e949a0351f191797b9b02e545 100644 GIT binary patch delta 4063 zcmbVOOLH4V5Z;~L)vngE9gi(rw&jQ9_)&4}it~Pvhx33q#7X2pOk!J>4 zAMDSU#E%D_ez9cF#7D!>r?fj;cDYZ6okq31QGd{Soby$V9kKa-kv_}0ut!C!sSL_V z$#a2n@7`rg>P|&zwkoZM&0HEz=@O&jW|)1u-fSg)%~I6d!J#54Lw9R?L$@_fmlTjE z!*mj?iRwC2Z3pwS_qMlo%9Yw|wNktHaA!7=qK1`TxECLVx%1SPm!^S(y=Iu+h-jK* zK1??s)mya>P*Lvfiw`mv`dd-6S=rRBO_vh*?58FBxhuX+J^OOm{@IS@wXprAGs~;-E++h-`j)fymNgh+ulYEDNZI_f92Oo29PYKfsNh*8eO2d!XeJ~ot7@b#n! z;e%Hg9^o`GltrPY9t{b=D{|L?5U!Z+WX%AyqU=^fZ<=fBQd0XxR)qopZ9mr(h;06z z#0J{_Zaw%YqjY8rjplPEHsMHfCY|tTKxe?iMfY&g4_HT3`W_{9!0V*+J$2FN#4v>- z0Mnf4PY`0w<<$*_4W@&7zzHa%M%u%gvf+79&oqnxhm0rj4(X1Wsebye%p!nqO@lwOMT7WAoH0L=9Qk2Me+7t;Ew06}g+*Vgr= zd(Dd9(|Yt)UJLZ<@kwuy^#Gu^$a+9 zAkeP&>Q7L=&ai=3;>8LCUI~j;hlAsi*vpyFtFgqdjj#ULETMWjOL{ey ziepT}ac+rmHqonb%h1roVdoZ>q2|%EacgXE_>HZqiFf1n)7-lKRqP9THg20Nsadyq zGr|ViZQhK&z^k!rYDurgvZ2wdv7An7Nw3B-PgWq^yVi!D1oFDelN!(@ti(e7Wpja` zx5Aqi2%al`hsquZdMjOOxxf>qRW33BXsetC5ZSoKK%lL1jRTs5HGS!zK?`~fw3x~R z2;N#+zcxVNt?9)B8$g+#5diSYCLE1InTrJ*d2+D=8ijQejwWH<9F8Vo-B;0K1fWq^ zH{sw};rkJ&KM)neql;eg^?id4v%71eLF^fs4 g3Ej6qjY7?wjz*!DPWnTmQ2Xq8)qeK8D!%{aZ@{Gspa1{> delta 1708 zcmX|ByKWOf6y3Qq>s@c0hbMlanxph5^C$X`$) zrAWSkA|-!-_yr2iow>W^(Y@!~GiUD1pMRzIe@oXt)u#*k)xG(Ap$50_UaAK}_xkqP zD|N4u=O4;R!I~g=`gQcXa&vvDYHH#3=2C5_d6G~VShE;dl_ZG{17-DMxST8`CJZRB zdWpJ8DG3>%v_#De5m38x^Wv?#NPV}qx=eMcYjl^%W(eKoY7HYORMu32rXQ!!RSB&d zr+8eIHXH>2r7E>E1c7RAT^doU2?)XzN2(8|s z*eUpn-6^_oxdy!*AFe^TyTKE0k5k%>drr<}yC-r0klPbEmvpN4L=O;pd(dMWF0*}~ z1OpsvpO&2sAPm@FsbmPW{dz-ah-@HfAZgGBRF+2eHLyMn)Ib}w(zft`4*c3+oQBPV z+$LYjL2*S?G=Fi$R+dvnXTGCbC%Cnxo*UUjz>BNcL3oBb%nQ>I?!w zZ%Ty>p>rB7We9rHvin+$=36_Khyg%578^iZlZb&pJC=wwzp|NsbI>5rW}u}UDj;~X zqWg9jfj9Ht4iLbJ|8^LFcao3e^PEUnsBx!+r3s60nvdf}IL!~oi*OpbX(=>$6HfDS z=sc6>q1_^!j#pt`%, +} +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] +pub struct ActivateDatabaseResponse { + #[prost(string, tag = "1")] + pub database_name: ::prost::alloc::string::String, + #[prost(bool, tag = "2")] + pub switching: bool, + #[prost(string, tag = "3")] + pub message: ::prost::alloc::string::String, +} #[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct StartBackupRequest { #[prost(enumeration = "BackupType", tag = "1")] @@ -362,6 +409,107 @@ pub mod backup_service_client { ); self.inner.unary(req, path, codec).await } + pub async fn list_databases( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic_prost::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/komp_ac.backup.BackupService/ListDatabases", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("komp_ac.backup.BackupService", "ListDatabases"), + ); + self.inner.unary(req, path, codec).await + } + pub async fn create_database( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic_prost::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/komp_ac.backup.BackupService/CreateDatabase", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("komp_ac.backup.BackupService", "CreateDatabase"), + ); + self.inner.unary(req, path, codec).await + } + pub async fn run_database_migrations( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic_prost::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/komp_ac.backup.BackupService/RunDatabaseMigrations", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new( + "komp_ac.backup.BackupService", + "RunDatabaseMigrations", + ), + ); + self.inner.unary(req, path, codec).await + } + pub async fn activate_database( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic_prost::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/komp_ac.backup.BackupService/ActivateDatabase", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("komp_ac.backup.BackupService", "ActivateDatabase"), + ); + self.inner.unary(req, path, codec).await + } } } /// Generated server implementations. @@ -412,6 +560,28 @@ pub mod backup_service_server { tonic::Response, tonic::Status, >; + async fn list_databases( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + async fn create_database( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + async fn run_database_migrations( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + async fn activate_database( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; } #[derive(Debug)] pub struct BackupServiceServer { @@ -715,6 +885,191 @@ pub mod backup_service_server { }; Box::pin(fut) } + "/komp_ac.backup.BackupService/ListDatabases" => { + #[allow(non_camel_case_types)] + struct ListDatabasesSvc(pub Arc); + impl< + T: BackupService, + > tonic::server::UnaryService + for ListDatabasesSvc { + type Response = super::ListDatabasesResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::list_databases(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = ListDatabasesSvc(inner); + let codec = tonic_prost::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/komp_ac.backup.BackupService/CreateDatabase" => { + #[allow(non_camel_case_types)] + struct CreateDatabaseSvc(pub Arc); + impl< + T: BackupService, + > tonic::server::UnaryService + for CreateDatabaseSvc { + type Response = super::DatabaseInfo; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::create_database(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = CreateDatabaseSvc(inner); + let codec = tonic_prost::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/komp_ac.backup.BackupService/RunDatabaseMigrations" => { + #[allow(non_camel_case_types)] + struct RunDatabaseMigrationsSvc(pub Arc); + impl< + T: BackupService, + > tonic::server::UnaryService + for RunDatabaseMigrationsSvc { + type Response = super::DatabaseInfo; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::run_database_migrations( + &inner, + request, + ) + .await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = RunDatabaseMigrationsSvc(inner); + let codec = tonic_prost::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/komp_ac.backup.BackupService/ActivateDatabase" => { + #[allow(non_camel_case_types)] + struct ActivateDatabaseSvc(pub Arc); + impl< + T: BackupService, + > tonic::server::UnaryService + for ActivateDatabaseSvc { + type Response = super::ActivateDatabaseResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::activate_database(&inner, request) + .await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = ActivateDatabaseSvc(inner); + let codec = tonic_prost::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } _ => { Box::pin(async move { let mut response = http::Response::new( diff --git a/server b/server index 13424600..ec9f1f19 160000 --- a/server +++ b/server @@ -1 +1 @@ -Subproject commit 134246004802400453349934d3f6794ddf3e8654 +Subproject commit ec9f1f19de0b25286afdfc27205f4afd3d0ef2a6