From 11e4ae1b8003ecd3d412944bc6f8efb22710a8d5 Mon Sep 17 00:00:00 2001 From: Berk Arslan Date: Wed, 18 Sep 2024 14:09:36 +0300 Subject: [PATCH] Add suspend and wakeup commands Suspend and wake-up commands are added into admin server with systemctl targets Signed-off-by: Berk Arslan --- api/admin/admin.pb.go | 57 ++++++++++++++++------------- api/admin/admin.proto | 2 ++ api/admin/admin_grpc.pb.go | 74 ++++++++++++++++++++++++++++++++++++++ client/src/client.rs | 10 ++++++ nixos/modules/host.nix | 2 ++ nixos/tests/admin.nix | 4 +++ src/admin/server.rs | 24 +++++++++++++ src/bin/givc-cli.rs | 4 +++ 8 files changed, 153 insertions(+), 24 deletions(-) diff --git a/api/admin/admin.pb.go b/api/admin/admin.pb.go index bc873b8..2a969fe 100644 --- a/api/admin/admin.pb.go +++ b/api/admin/admin.pb.go @@ -755,8 +755,8 @@ var file_admin_proto_rawDesc = []byte{ 0x65, 0x64, 0x12, 0x30, 0x0a, 0x07, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x74, 0x65, 0x6d, 0x48, 0x00, 0x52, 0x07, 0x52, 0x65, 0x6d, - 0x6f, 0x76, 0x65, 0x64, 0x42, 0x08, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x32, 0xbe, - 0x04, 0x0a, 0x0c, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, + 0x6f, 0x76, 0x65, 0x64, 0x42, 0x08, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x32, 0x8f, + 0x05, 0x0a, 0x0c, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x44, 0x0a, 0x0f, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x16, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x61, 0x64, 0x6d, @@ -785,15 +785,20 @@ var file_admin_proto_rawDesc = []byte{ 0x70, 0x74, 0x79, 0x1a, 0x0c, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x26, 0x0a, 0x06, 0x52, 0x65, 0x62, 0x6f, 0x6f, 0x74, 0x12, 0x0c, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x0c, 0x2e, 0x61, 0x64, - 0x6d, 0x69, 0x6e, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x35, 0x0a, 0x09, 0x51, - 0x75, 0x65, 0x72, 0x79, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x0c, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, - 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x18, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x51, - 0x75, 0x65, 0x72, 0x79, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x00, 0x12, 0x2b, 0x0a, 0x05, 0x57, 0x61, 0x74, 0x63, 0x68, 0x12, 0x0c, 0x2e, 0x61, 0x64, - 0x6d, 0x69, 0x6e, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x10, 0x2e, 0x61, 0x64, 0x6d, 0x69, - 0x6e, 0x2e, 0x57, 0x61, 0x74, 0x63, 0x68, 0x49, 0x74, 0x65, 0x6d, 0x22, 0x00, 0x30, 0x01, 0x42, - 0x09, 0x5a, 0x07, 0x2e, 0x2f, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x33, + 0x6d, 0x69, 0x6e, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x27, 0x0a, 0x07, 0x53, + 0x75, 0x73, 0x70, 0x65, 0x6e, 0x64, 0x12, 0x0c, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x45, + 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x0c, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x45, 0x6d, 0x70, + 0x74, 0x79, 0x22, 0x00, 0x12, 0x26, 0x0a, 0x06, 0x57, 0x61, 0x6b, 0x65, 0x75, 0x70, 0x12, 0x0c, + 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x0c, 0x2e, 0x61, + 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x35, 0x0a, 0x09, + 0x51, 0x75, 0x65, 0x72, 0x79, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x0c, 0x2e, 0x61, 0x64, 0x6d, 0x69, + 0x6e, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x18, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, + 0x51, 0x75, 0x65, 0x72, 0x79, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x00, 0x12, 0x2b, 0x0a, 0x05, 0x57, 0x61, 0x74, 0x63, 0x68, 0x12, 0x0c, 0x2e, 0x61, + 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x10, 0x2e, 0x61, 0x64, 0x6d, + 0x69, 0x6e, 0x2e, 0x57, 0x61, 0x74, 0x63, 0x68, 0x49, 0x74, 0x65, 0x6d, 0x22, 0x00, 0x30, 0x01, + 0x42, 0x09, 0x5a, 0x07, 0x2e, 0x2f, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x33, } var ( @@ -836,19 +841,23 @@ var file_admin_proto_depIdxs = []int32{ 4, // 11: admin.AdminService.StopApplication:input_type -> admin.ApplicationRequest 6, // 12: admin.AdminService.Poweroff:input_type -> admin.Empty 6, // 13: admin.AdminService.Reboot:input_type -> admin.Empty - 6, // 14: admin.AdminService.QueryList:input_type -> admin.Empty - 6, // 15: admin.AdminService.Watch:input_type -> admin.Empty - 3, // 16: admin.AdminService.RegisterService:output_type -> admin.RegistryResponse - 5, // 17: admin.AdminService.StartApplication:output_type -> admin.ApplicationResponse - 5, // 18: admin.AdminService.PauseApplication:output_type -> admin.ApplicationResponse - 5, // 19: admin.AdminService.ResumeApplication:output_type -> admin.ApplicationResponse - 5, // 20: admin.AdminService.StopApplication:output_type -> admin.ApplicationResponse - 6, // 21: admin.AdminService.Poweroff:output_type -> admin.Empty - 6, // 22: admin.AdminService.Reboot:output_type -> admin.Empty - 8, // 23: admin.AdminService.QueryList:output_type -> admin.QueryListResponse - 9, // 24: admin.AdminService.Watch:output_type -> admin.WatchItem - 16, // [16:25] is the sub-list for method output_type - 7, // [7:16] is the sub-list for method input_type + 6, // 14: admin.AdminService.Suspend:input_type -> admin.Empty + 6, // 15: admin.AdminService.Wakeup:input_type -> admin.Empty + 6, // 16: admin.AdminService.QueryList:input_type -> admin.Empty + 6, // 17: admin.AdminService.Watch:input_type -> admin.Empty + 3, // 18: admin.AdminService.RegisterService:output_type -> admin.RegistryResponse + 5, // 19: admin.AdminService.StartApplication:output_type -> admin.ApplicationResponse + 5, // 20: admin.AdminService.PauseApplication:output_type -> admin.ApplicationResponse + 5, // 21: admin.AdminService.ResumeApplication:output_type -> admin.ApplicationResponse + 5, // 22: admin.AdminService.StopApplication:output_type -> admin.ApplicationResponse + 6, // 23: admin.AdminService.Poweroff:output_type -> admin.Empty + 6, // 24: admin.AdminService.Reboot:output_type -> admin.Empty + 6, // 25: admin.AdminService.Suspend:output_type -> admin.Empty + 6, // 26: admin.AdminService.Wakeup:output_type -> admin.Empty + 8, // 27: admin.AdminService.QueryList:output_type -> admin.QueryListResponse + 9, // 28: admin.AdminService.Watch:output_type -> admin.WatchItem + 18, // [18:29] is the sub-list for method output_type + 7, // [7:18] is the sub-list for method input_type 7, // [7:7] is the sub-list for extension type_name 7, // [7:7] is the sub-list for extension extendee 0, // [0:7] is the sub-list for field type_name diff --git a/api/admin/admin.proto b/api/admin/admin.proto index f574456..b371dc5 100644 --- a/api/admin/admin.proto +++ b/api/admin/admin.proto @@ -73,6 +73,8 @@ service AdminService { rpc StopApplication(ApplicationRequest) returns (ApplicationResponse) {} rpc Poweroff(Empty) returns (Empty) {} rpc Reboot(Empty) returns (Empty) {} + rpc Suspend(Empty) returns (Empty) {} + rpc Wakeup(Empty) returns (Empty) {} rpc QueryList(Empty) returns (QueryListResponse) {} rpc Watch(Empty) returns (stream WatchItem) {} diff --git a/api/admin/admin_grpc.pb.go b/api/admin/admin_grpc.pb.go index 7a44397..dc85519 100644 --- a/api/admin/admin_grpc.pb.go +++ b/api/admin/admin_grpc.pb.go @@ -29,6 +29,8 @@ const ( AdminService_StopApplication_FullMethodName = "/admin.AdminService/StopApplication" AdminService_Poweroff_FullMethodName = "/admin.AdminService/Poweroff" AdminService_Reboot_FullMethodName = "/admin.AdminService/Reboot" + AdminService_Suspend_FullMethodName = "/admin.AdminService/Suspend" + AdminService_Wakeup_FullMethodName = "/admin.AdminService/Wakeup" AdminService_QueryList_FullMethodName = "/admin.AdminService/QueryList" AdminService_Watch_FullMethodName = "/admin.AdminService/Watch" ) @@ -44,6 +46,8 @@ type AdminServiceClient interface { StopApplication(ctx context.Context, in *ApplicationRequest, opts ...grpc.CallOption) (*ApplicationResponse, error) Poweroff(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*Empty, error) Reboot(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*Empty, error) + Suspend(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*Empty, error) + Wakeup(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*Empty, error) QueryList(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*QueryListResponse, error) Watch(ctx context.Context, in *Empty, opts ...grpc.CallOption) (AdminService_WatchClient, error) } @@ -119,6 +123,24 @@ func (c *adminServiceClient) Reboot(ctx context.Context, in *Empty, opts ...grpc return out, nil } +func (c *adminServiceClient) Suspend(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*Empty, error) { + out := new(Empty) + err := c.cc.Invoke(ctx, AdminService_Suspend_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminServiceClient) Wakeup(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*Empty, error) { + out := new(Empty) + err := c.cc.Invoke(ctx, AdminService_Wakeup_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *adminServiceClient) QueryList(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*QueryListResponse, error) { out := new(QueryListResponse) err := c.cc.Invoke(ctx, AdminService_QueryList_FullMethodName, in, out, opts...) @@ -171,6 +193,8 @@ type AdminServiceServer interface { StopApplication(context.Context, *ApplicationRequest) (*ApplicationResponse, error) Poweroff(context.Context, *Empty) (*Empty, error) Reboot(context.Context, *Empty) (*Empty, error) + Suspend(context.Context, *Empty) (*Empty, error) + Wakeup(context.Context, *Empty) (*Empty, error) QueryList(context.Context, *Empty) (*QueryListResponse, error) Watch(*Empty, AdminService_WatchServer) error mustEmbedUnimplementedAdminServiceServer() @@ -201,6 +225,12 @@ func (UnimplementedAdminServiceServer) Poweroff(context.Context, *Empty) (*Empty func (UnimplementedAdminServiceServer) Reboot(context.Context, *Empty) (*Empty, error) { return nil, status.Errorf(codes.Unimplemented, "method Reboot not implemented") } +func (UnimplementedAdminServiceServer) Suspend(context.Context, *Empty) (*Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method Suspend not implemented") +} +func (UnimplementedAdminServiceServer) Wakeup(context.Context, *Empty) (*Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method Wakeup not implemented") +} func (UnimplementedAdminServiceServer) QueryList(context.Context, *Empty) (*QueryListResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method QueryList not implemented") } @@ -346,6 +376,42 @@ func _AdminService_Reboot_Handler(srv interface{}, ctx context.Context, dec func return interceptor(ctx, in, info, handler) } +func _AdminService_Suspend_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(Empty) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServiceServer).Suspend(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: AdminService_Suspend_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServiceServer).Suspend(ctx, req.(*Empty)) + } + return interceptor(ctx, in, info, handler) +} + +func _AdminService_Wakeup_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(Empty) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServiceServer).Wakeup(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: AdminService_Wakeup_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServiceServer).Wakeup(ctx, req.(*Empty)) + } + return interceptor(ctx, in, info, handler) +} + func _AdminService_QueryList_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(Empty) if err := dec(in); err != nil { @@ -420,6 +486,14 @@ var AdminService_ServiceDesc = grpc.ServiceDesc{ MethodName: "Reboot", Handler: _AdminService_Reboot_Handler, }, + { + MethodName: "Suspend", + Handler: _AdminService_Suspend_Handler, + }, + { + MethodName: "Wakeup", + Handler: _AdminService_Wakeup_Handler, + }, { MethodName: "QueryList", Handler: _AdminService_QueryList_Handler, diff --git a/client/src/client.rs b/client/src/client.rs index 3a773ee..90a697b 100644 --- a/client/src/client.rs +++ b/client/src/client.rs @@ -110,6 +110,16 @@ impl AdminClient { let _response = self.connect_to().await?.poweroff(request).await?; Ok(()) } + pub async fn suspend(&self) -> anyhow::Result<()> { + let request = pb::admin::Empty {}; + let _response = self.connect_to().await?.suspend(request).await?; + Ok(()) + } + pub async fn wakeup(&self) -> anyhow::Result<()> { + let request = pb::admin::Empty {}; + let _response = self.connect_to().await?.wakeup(request).await?; + Ok(()) + } pub async fn query( &self, diff --git a/nixos/modules/host.nix b/nixos/modules/host.nix index 8207a8b..2802d30 100644 --- a/nixos/modules/host.nix +++ b/nixos/modules/host.nix @@ -59,6 +59,8 @@ in default = [ "reboot.target" "poweroff.target" + "sleep.target" + "suspend.target" ]; example = "[ 'my-service.service' ]"; }; diff --git a/nixos/tests/admin.nix b/nixos/tests/admin.nix index e6e07ee..44f1b5c 100644 --- a/nixos/tests/admin.nix +++ b/nixos/tests/admin.nix @@ -75,6 +75,8 @@ in "microvm@foot-vm.service" "poweroff.target" "reboot.target" + "sleep.target" + "suspend.target" ]; tls = mkTls "ghaf-host"; }; @@ -154,6 +156,8 @@ in services = [ "poweroff.target" "reboot.target" + "sleep.target" + "suspend.target" ]; }; diff --git a/src/admin/server.rs b/src/admin/server.rs index 9f670c0..6ebae05 100644 --- a/src/admin/server.rs +++ b/src/admin/server.rs @@ -385,6 +385,30 @@ impl pb::admin_service_server::AdminService for AdminService { }) .await } + async fn suspend( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status> { + escalate(request, |_| async { + self.inner + .send_system_command(String::from("suspend.target")) + .await?; + Ok(Empty {}) + }) + .await + } + async fn wakeup( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status> { + escalate(request, |_| async { + self.inner + .send_system_command(String::from("sleep.target")) + .await?; + Ok(Empty {}) + }) + .await + } async fn query_list( &self, diff --git a/src/bin/givc-cli.rs b/src/bin/givc-cli.rs index 2892e67..9851259 100644 --- a/src/bin/givc-cli.rs +++ b/src/bin/givc-cli.rs @@ -59,6 +59,8 @@ enum Commands { }, Reboot {}, Poweroff {}, + Suspend {}, + Wakeup {}, Query { #[arg(long, default_value_t = false)] as_json: bool, // Would it useful for scripts? @@ -140,6 +142,8 @@ async fn main() -> std::result::Result<(), Box> { Commands::Resume { app } => admin.resume(app).await?, Commands::Reboot {} => admin.reboot().await?, Commands::Poweroff {} => admin.poweroff().await?, + Commands::Suspend {} => admin.suspend().await?, + Commands::Wakeup {} => admin.wakeup().await?, Commands::Query { by_type,