From ac90f28589cb3dd7fca245deec3aece0949c554e Mon Sep 17 00:00:00 2001 From: Thomas Anderson <127358482+zc-devs@users.noreply.github.com> Date: Wed, 18 Oct 2023 14:29:28 +0300 Subject: [PATCH 1/2] Unregister stateless agents from server on termination --- agent/rpc/client_grpc.go | 5 ++ cmd/agent/agent.go | 20 ++++++- cmd/agent/config.go | 7 ++- cmd/agent/config_test.go | 4 +- pipeline/backend/kubernetes/kubernetes.go | 6 ++- pipeline/rpc/peer.go | 3 ++ pipeline/rpc/proto/version.go | 2 +- pipeline/rpc/proto/woodpecker.pb.go | 65 ++++++++++++----------- pipeline/rpc/proto/woodpecker.proto | 21 ++++---- pipeline/rpc/proto/woodpecker_grpc.pb.go | 59 ++++++++++++++++---- server/grpc/rpc.go | 12 +++++ server/grpc/server.go | 5 ++ shared/utils/context.go | 2 +- 13 files changed, 151 insertions(+), 60 deletions(-) diff --git a/agent/rpc/client_grpc.go b/agent/rpc/client_grpc.go index 070659b88f9..171b5e150d9 100644 --- a/agent/rpc/client_grpc.go +++ b/agent/rpc/client_grpc.go @@ -366,6 +366,11 @@ func (c *client) RegisterAgent(ctx context.Context, platform, backend, version s return res.GetAgentId(), err } +func (c *client) UnregisterAgent(ctx context.Context) error { + _, err := c.client.UnregisterAgent(ctx, &proto.Empty{}) + return err +} + func (c *client) ReportHealth(ctx context.Context) (err error) { retry := c.newBackOff() req := new(proto.ReportHealthRequest) diff --git a/cmd/agent/agent.go b/cmd/agent/agent.go index 9fde7d28f51..55103785132 100644 --- a/cmd/agent/agent.go +++ b/cmd/agent/agent.go @@ -121,9 +121,20 @@ func run(c *cli.Context) error { context.Background(), metadata.Pairs("hostname", hostname), ) + + agentConfigPersisted := abool.New() ctx = utils.WithContextSigtermCallback(ctx, func() { - println("ctrl+c received, terminating process") + log.Info().Msg("Termination signal is received, shutting down") sigterm.Set() + + // Remove stateless agents from server + if agentConfigPersisted.IsNotSet() { + log.Debug().Msg("Unregistering agent from server") + err := client.UnregisterAgent(ctx) + if err != nil { + log.Err(err).Msg("Failed to unregister agent from server") + } + } }) // check if grpc server version is compatible with agent @@ -160,7 +171,10 @@ func run(c *cli.Context) error { return err } - writeAgentConfig(agentConfig, agentConfigPath) + err = writeAgentConfig(agentConfig, agentConfigPath) + if err == nil { + agentConfigPersisted.Set() + } labels := map[string]string{ "hostname": hostname, @@ -182,6 +196,7 @@ func run(c *cli.Context) error { go func() { for { if sigterm.IsSet() { + log.Debug().Msg("Terminating health reporting") return } @@ -212,6 +227,7 @@ func run(c *cli.Context) error { for { if sigterm.IsSet() { + log.Debug().Msgf("terminating runner %d", i) return } diff --git a/cmd/agent/config.go b/cmd/agent/config.go index 1b6ef3b5eee..ea1791ba627 100644 --- a/cmd/agent/config.go +++ b/cmd/agent/config.go @@ -54,11 +54,11 @@ func readAgentConfig(agentConfigPath string) AgentConfig { return conf } -func writeAgentConfig(conf AgentConfig, agentConfigPath string) { +func writeAgentConfig(conf AgentConfig, agentConfigPath string) error { rawAgentConf, err := json.Marshal(conf) if err != nil { log.Error().Err(err).Msg("could not marshal agent config") - return + return err } // get old config @@ -68,6 +68,9 @@ func writeAgentConfig(conf AgentConfig, agentConfigPath string) { if !bytes.Equal(rawAgentConf, oldRawAgentConf) { if err := os.WriteFile(agentConfigPath, rawAgentConf, 0o644); err != nil { log.Error().Err(err).Msgf("could not persist agent config at '%s'", agentConfigPath) + return err } } + + return nil } diff --git a/cmd/agent/config_test.go b/cmd/agent/config_test.go index 6ae724e1a9c..5ec38c2c13e 100644 --- a/cmd/agent/config_test.go +++ b/cmd/agent/config_test.go @@ -44,7 +44,7 @@ func TestReadAgentIDFileExists(t *testing.T) { // update existing config and check actual.AgentID = 33 - writeAgentConfig(actual, tmpF.Name()) + _ = writeAgentConfig(actual, tmpF.Name()) actual = readAgentConfig(tmpF.Name()) assert.EqualValues(t, 33, actual.AgentID) @@ -55,7 +55,7 @@ func TestReadAgentIDFileExists(t *testing.T) { defer os.Remove(tmpF2.Name()) // write new config - writeAgentConfig(actual, tmpF2.Name()) + _ = writeAgentConfig(actual, tmpF2.Name()) actual = readAgentConfig(tmpF2.Name()) assert.EqualValues(t, 33, actual.AgentID) } diff --git a/pipeline/backend/kubernetes/kubernetes.go b/pipeline/backend/kubernetes/kubernetes.go index 458a3f08c05..ddac85c66fc 100644 --- a/pipeline/backend/kubernetes/kubernetes.go +++ b/pipeline/backend/kubernetes/kubernetes.go @@ -40,6 +40,10 @@ import ( _ "k8s.io/client-go/plugin/pkg/client/auth/gcp" ) +const ( + EngineName = "kubernetes" +) + var noContext = context.Background() type kube struct { @@ -96,7 +100,7 @@ func New(ctx context.Context) types.Engine { } func (e *kube) Name() string { - return "kubernetes" + return EngineName } func (e *kube) IsAvailable(context.Context) bool { diff --git a/pipeline/rpc/peer.go b/pipeline/rpc/peer.go index c13a557d6fd..08a19217f09 100644 --- a/pipeline/rpc/peer.go +++ b/pipeline/rpc/peer.go @@ -79,6 +79,9 @@ type Peer interface { // RegisterAgent register our agent to the server RegisterAgent(ctx context.Context, platform, backend, version string, capacity int) (int64, error) + // UnregisterAgent unregister our agent from the server + UnregisterAgent(ctx context.Context) error + // ReportHealth reports health status of the agent to the server ReportHealth(c context.Context) error } diff --git a/pipeline/rpc/proto/version.go b/pipeline/rpc/proto/version.go index 3e3449804ab..1a109d5a8a3 100644 --- a/pipeline/rpc/proto/version.go +++ b/pipeline/rpc/proto/version.go @@ -16,4 +16,4 @@ package proto // Version is the version of the woodpecker.proto file, // !IMPORTANT! increased by 1 each time it get changed !IMPORTANT! -const Version int32 = 4 +const Version int32 = 5 diff --git a/pipeline/rpc/proto/woodpecker.pb.go b/pipeline/rpc/proto/woodpecker.pb.go index 0fead4b8e0b..891e2af9c24 100644 --- a/pipeline/rpc/proto/woodpecker.pb.go +++ b/pipeline/rpc/proto/woodpecker.pb.go @@ -16,7 +16,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.31.0 -// protoc v4.23.4 +// protoc v4.24.4 // source: woodpecker.proto package proto @@ -1181,7 +1181,7 @@ var file_woodpecker_proto_rawDesc = []byte{ 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, - 0x6e, 0x32, 0x8a, 0x04, 0x0a, 0x0a, 0x57, 0x6f, 0x6f, 0x64, 0x70, 0x65, 0x63, 0x6b, 0x65, 0x72, + 0x6e, 0x32, 0xbb, 0x04, 0x0a, 0x0a, 0x57, 0x6f, 0x6f, 0x64, 0x70, 0x65, 0x63, 0x6b, 0x65, 0x72, 0x12, 0x31, 0x0a, 0x07, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x0c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, @@ -1210,19 +1210,22 @@ var file_woodpecker_proto_rawDesc = []byte{ 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x00, 0x12, 0x3a, 0x0a, 0x0c, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x48, 0x65, 0x61, 0x6c, - 0x74, 0x68, 0x12, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x72, - 0x74, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0c, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x32, 0x43, - 0x0a, 0x0e, 0x57, 0x6f, 0x6f, 0x64, 0x70, 0x65, 0x63, 0x6b, 0x65, 0x72, 0x41, 0x75, 0x74, 0x68, - 0x12, 0x31, 0x0a, 0x04, 0x41, 0x75, 0x74, 0x68, 0x12, 0x12, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x2e, 0x41, 0x75, 0x74, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x22, 0x00, 0x42, 0x38, 0x5a, 0x36, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, - 0x6d, 0x2f, 0x77, 0x6f, 0x6f, 0x64, 0x70, 0x65, 0x63, 0x6b, 0x65, 0x72, 0x2d, 0x63, 0x69, 0x2f, - 0x77, 0x6f, 0x6f, 0x64, 0x70, 0x65, 0x63, 0x6b, 0x65, 0x72, 0x2f, 0x70, 0x69, 0x70, 0x65, 0x6c, - 0x69, 0x6e, 0x65, 0x2f, 0x72, 0x70, 0x63, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x22, 0x00, 0x12, 0x2f, 0x0a, 0x0f, 0x55, 0x6e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, + 0x41, 0x67, 0x65, 0x6e, 0x74, 0x12, 0x0c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x45, 0x6d, + 0x70, 0x74, 0x79, 0x1a, 0x0c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x45, 0x6d, 0x70, 0x74, + 0x79, 0x22, 0x00, 0x12, 0x3a, 0x0a, 0x0c, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x48, 0x65, 0x61, + 0x6c, 0x74, 0x68, 0x12, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x70, 0x6f, + 0x72, 0x74, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x0c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x32, + 0x43, 0x0a, 0x0e, 0x57, 0x6f, 0x6f, 0x64, 0x70, 0x65, 0x63, 0x6b, 0x65, 0x72, 0x41, 0x75, 0x74, + 0x68, 0x12, 0x31, 0x0a, 0x04, 0x41, 0x75, 0x74, 0x68, 0x12, 0x12, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x00, 0x42, 0x38, 0x5a, 0x36, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x77, 0x6f, 0x6f, 0x64, 0x70, 0x65, 0x63, 0x6b, 0x65, 0x72, 0x2d, 0x63, 0x69, + 0x2f, 0x77, 0x6f, 0x6f, 0x64, 0x70, 0x65, 0x63, 0x6b, 0x65, 0x72, 0x2f, 0x70, 0x69, 0x70, 0x65, + 0x6c, 0x69, 0x6e, 0x65, 0x2f, 0x72, 0x70, 0x63, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -1277,21 +1280,23 @@ var file_woodpecker_proto_depIdxs = []int32{ 9, // 13: proto.Woodpecker.Update:input_type -> proto.UpdateRequest 10, // 14: proto.Woodpecker.Log:input_type -> proto.LogRequest 13, // 15: proto.Woodpecker.RegisterAgent:input_type -> proto.RegisterAgentRequest - 12, // 16: proto.Woodpecker.ReportHealth:input_type -> proto.ReportHealthRequest - 17, // 17: proto.WoodpeckerAuth.Auth:input_type -> proto.AuthRequest - 14, // 18: proto.Woodpecker.Version:output_type -> proto.VersionResponse - 15, // 19: proto.Woodpecker.Next:output_type -> proto.NextResponse - 11, // 20: proto.Woodpecker.Init:output_type -> proto.Empty - 11, // 21: proto.Woodpecker.Wait:output_type -> proto.Empty - 11, // 22: proto.Woodpecker.Done:output_type -> proto.Empty - 11, // 23: proto.Woodpecker.Extend:output_type -> proto.Empty - 11, // 24: proto.Woodpecker.Update:output_type -> proto.Empty - 11, // 25: proto.Woodpecker.Log:output_type -> proto.Empty - 16, // 26: proto.Woodpecker.RegisterAgent:output_type -> proto.RegisterAgentResponse - 11, // 27: proto.Woodpecker.ReportHealth:output_type -> proto.Empty - 18, // 28: proto.WoodpeckerAuth.Auth:output_type -> proto.AuthResponse - 18, // [18:29] is the sub-list for method output_type - 7, // [7:18] is the sub-list for method input_type + 11, // 16: proto.Woodpecker.UnregisterAgent:input_type -> proto.Empty + 12, // 17: proto.Woodpecker.ReportHealth:input_type -> proto.ReportHealthRequest + 17, // 18: proto.WoodpeckerAuth.Auth:input_type -> proto.AuthRequest + 14, // 19: proto.Woodpecker.Version:output_type -> proto.VersionResponse + 15, // 20: proto.Woodpecker.Next:output_type -> proto.NextResponse + 11, // 21: proto.Woodpecker.Init:output_type -> proto.Empty + 11, // 22: proto.Woodpecker.Wait:output_type -> proto.Empty + 11, // 23: proto.Woodpecker.Done:output_type -> proto.Empty + 11, // 24: proto.Woodpecker.Extend:output_type -> proto.Empty + 11, // 25: proto.Woodpecker.Update:output_type -> proto.Empty + 11, // 26: proto.Woodpecker.Log:output_type -> proto.Empty + 16, // 27: proto.Woodpecker.RegisterAgent:output_type -> proto.RegisterAgentResponse + 11, // 28: proto.Woodpecker.UnregisterAgent:output_type -> proto.Empty + 11, // 29: proto.Woodpecker.ReportHealth:output_type -> proto.Empty + 18, // 30: proto.WoodpeckerAuth.Auth:output_type -> proto.AuthResponse + 19, // [19:31] is the sub-list for method output_type + 7, // [7:19] 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/pipeline/rpc/proto/woodpecker.proto b/pipeline/rpc/proto/woodpecker.proto index d780f71d2b3..876a4060f42 100644 --- a/pipeline/rpc/proto/woodpecker.proto +++ b/pipeline/rpc/proto/woodpecker.proto @@ -24,16 +24,17 @@ package proto; // Woodpecker Server Service service Woodpecker { - rpc Version (Empty) returns (VersionResponse) {} - rpc Next (NextRequest) returns (NextResponse) {} - rpc Init (InitRequest) returns (Empty) {} - rpc Wait (WaitRequest) returns (Empty) {} - rpc Done (DoneRequest) returns (Empty) {} - rpc Extend (ExtendRequest) returns (Empty) {} - rpc Update (UpdateRequest) returns (Empty) {} - rpc Log (LogRequest) returns (Empty) {} - rpc RegisterAgent (RegisterAgentRequest) returns (RegisterAgentResponse) {} - rpc ReportHealth (ReportHealthRequest) returns (Empty) {} + rpc Version (Empty) returns (VersionResponse) {} + rpc Next (NextRequest) returns (NextResponse) {} + rpc Init (InitRequest) returns (Empty) {} + rpc Wait (WaitRequest) returns (Empty) {} + rpc Done (DoneRequest) returns (Empty) {} + rpc Extend (ExtendRequest) returns (Empty) {} + rpc Update (UpdateRequest) returns (Empty) {} + rpc Log (LogRequest) returns (Empty) {} + rpc RegisterAgent (RegisterAgentRequest) returns (RegisterAgentResponse) {} + rpc UnregisterAgent (Empty) returns (Empty) {} + rpc ReportHealth (ReportHealthRequest) returns (Empty) {} } // diff --git a/pipeline/rpc/proto/woodpecker_grpc.pb.go b/pipeline/rpc/proto/woodpecker_grpc.pb.go index b6f0f6ae148..787f8f6e708 100644 --- a/pipeline/rpc/proto/woodpecker_grpc.pb.go +++ b/pipeline/rpc/proto/woodpecker_grpc.pb.go @@ -16,7 +16,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.3.0 -// - protoc v4.23.4 +// - protoc v4.24.4 // source: woodpecker.proto package proto @@ -34,16 +34,17 @@ import ( const _ = grpc.SupportPackageIsVersion7 const ( - Woodpecker_Version_FullMethodName = "/proto.Woodpecker/Version" - Woodpecker_Next_FullMethodName = "/proto.Woodpecker/Next" - Woodpecker_Init_FullMethodName = "/proto.Woodpecker/Init" - Woodpecker_Wait_FullMethodName = "/proto.Woodpecker/Wait" - Woodpecker_Done_FullMethodName = "/proto.Woodpecker/Done" - Woodpecker_Extend_FullMethodName = "/proto.Woodpecker/Extend" - Woodpecker_Update_FullMethodName = "/proto.Woodpecker/Update" - Woodpecker_Log_FullMethodName = "/proto.Woodpecker/Log" - Woodpecker_RegisterAgent_FullMethodName = "/proto.Woodpecker/RegisterAgent" - Woodpecker_ReportHealth_FullMethodName = "/proto.Woodpecker/ReportHealth" + Woodpecker_Version_FullMethodName = "/proto.Woodpecker/Version" + Woodpecker_Next_FullMethodName = "/proto.Woodpecker/Next" + Woodpecker_Init_FullMethodName = "/proto.Woodpecker/Init" + Woodpecker_Wait_FullMethodName = "/proto.Woodpecker/Wait" + Woodpecker_Done_FullMethodName = "/proto.Woodpecker/Done" + Woodpecker_Extend_FullMethodName = "/proto.Woodpecker/Extend" + Woodpecker_Update_FullMethodName = "/proto.Woodpecker/Update" + Woodpecker_Log_FullMethodName = "/proto.Woodpecker/Log" + Woodpecker_RegisterAgent_FullMethodName = "/proto.Woodpecker/RegisterAgent" + Woodpecker_UnregisterAgent_FullMethodName = "/proto.Woodpecker/UnregisterAgent" + Woodpecker_ReportHealth_FullMethodName = "/proto.Woodpecker/ReportHealth" ) // WoodpeckerClient is the client API for Woodpecker service. @@ -59,6 +60,7 @@ type WoodpeckerClient interface { Update(ctx context.Context, in *UpdateRequest, opts ...grpc.CallOption) (*Empty, error) Log(ctx context.Context, in *LogRequest, opts ...grpc.CallOption) (*Empty, error) RegisterAgent(ctx context.Context, in *RegisterAgentRequest, opts ...grpc.CallOption) (*RegisterAgentResponse, error) + UnregisterAgent(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*Empty, error) ReportHealth(ctx context.Context, in *ReportHealthRequest, opts ...grpc.CallOption) (*Empty, error) } @@ -151,6 +153,15 @@ func (c *woodpeckerClient) RegisterAgent(ctx context.Context, in *RegisterAgentR return out, nil } +func (c *woodpeckerClient) UnregisterAgent(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*Empty, error) { + out := new(Empty) + err := c.cc.Invoke(ctx, Woodpecker_UnregisterAgent_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *woodpeckerClient) ReportHealth(ctx context.Context, in *ReportHealthRequest, opts ...grpc.CallOption) (*Empty, error) { out := new(Empty) err := c.cc.Invoke(ctx, Woodpecker_ReportHealth_FullMethodName, in, out, opts...) @@ -173,6 +184,7 @@ type WoodpeckerServer interface { Update(context.Context, *UpdateRequest) (*Empty, error) Log(context.Context, *LogRequest) (*Empty, error) RegisterAgent(context.Context, *RegisterAgentRequest) (*RegisterAgentResponse, error) + UnregisterAgent(context.Context, *Empty) (*Empty, error) ReportHealth(context.Context, *ReportHealthRequest) (*Empty, error) mustEmbedUnimplementedWoodpeckerServer() } @@ -208,6 +220,9 @@ func (UnimplementedWoodpeckerServer) Log(context.Context, *LogRequest) (*Empty, func (UnimplementedWoodpeckerServer) RegisterAgent(context.Context, *RegisterAgentRequest) (*RegisterAgentResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method RegisterAgent not implemented") } +func (UnimplementedWoodpeckerServer) UnregisterAgent(context.Context, *Empty) (*Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method UnregisterAgent not implemented") +} func (UnimplementedWoodpeckerServer) ReportHealth(context.Context, *ReportHealthRequest) (*Empty, error) { return nil, status.Errorf(codes.Unimplemented, "method ReportHealth not implemented") } @@ -386,6 +401,24 @@ func _Woodpecker_RegisterAgent_Handler(srv interface{}, ctx context.Context, dec return interceptor(ctx, in, info, handler) } +func _Woodpecker_UnregisterAgent_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.(WoodpeckerServer).UnregisterAgent(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Woodpecker_UnregisterAgent_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(WoodpeckerServer).UnregisterAgent(ctx, req.(*Empty)) + } + return interceptor(ctx, in, info, handler) +} + func _Woodpecker_ReportHealth_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(ReportHealthRequest) if err := dec(in); err != nil { @@ -447,6 +480,10 @@ var Woodpecker_ServiceDesc = grpc.ServiceDesc{ MethodName: "RegisterAgent", Handler: _Woodpecker_RegisterAgent_Handler, }, + { + MethodName: "UnregisterAgent", + Handler: _Woodpecker_UnregisterAgent_Handler, + }, { MethodName: "ReportHealth", Handler: _Woodpecker_ReportHealth_Handler, diff --git a/server/grpc/rpc.go b/server/grpc/rpc.go index 7cbdd9a82a7..3a4eb8f88f9 100644 --- a/server/grpc/rpc.go +++ b/server/grpc/rpc.go @@ -352,6 +352,18 @@ func (s *RPC) RegisterAgent(ctx context.Context, platform, backend, version stri return agent.ID, nil } +func (s *RPC) UnregisterAgent(ctx context.Context) error { + agent, err := s.getAgentFromContext(ctx) + log.Debug().Msgf("unregistering agent with ID %d", agent.ID) + if err != nil { + return err + } + + err = s.store.AgentDelete(agent) + + return err +} + func (s *RPC) ReportHealth(ctx context.Context, status string) error { agent, err := s.getAgentFromContext(ctx) if err != nil { diff --git a/server/grpc/server.go b/server/grpc/server.go index 44e73277c1d..ff14a907493 100644 --- a/server/grpc/server.go +++ b/server/grpc/server.go @@ -163,6 +163,11 @@ func (s *WoodpeckerServer) RegisterAgent(c context.Context, req *proto.RegisterA return res, err } +func (s *WoodpeckerServer) UnregisterAgent(ctx context.Context, _ *proto.Empty) (*proto.Empty, error) { + err := s.peer.UnregisterAgent(ctx) + return new(proto.Empty), err +} + func (s *WoodpeckerServer) ReportHealth(c context.Context, req *proto.ReportHealthRequest) (*proto.Empty, error) { res := new(proto.Empty) err := s.peer.ReportHealth(c, req.GetStatus()) diff --git a/shared/utils/context.go b/shared/utils/context.go index 0bc689e6bd6..bb72f8251f7 100644 --- a/shared/utils/context.go +++ b/shared/utils/context.go @@ -34,10 +34,10 @@ func WithContextSigtermCallback(ctx context.Context, f func()) context.Context { select { case <-ctx.Done(): case <-receivedSignal: - cancel(fmt.Errorf("received signal: %v", receivedSignal)) if f != nil { f() } + cancel(fmt.Errorf("received signal: %v", receivedSignal)) } }() From ee86bf78e5b9c7d9f6a3e9cdac4271fca6c7f42d Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Thu, 2 Nov 2023 00:20:50 +0100 Subject: [PATCH 2/2] make stateless agent an option --- cmd/agent/agent.go | 7 ++++--- cmd/agent/config.go | 4 ++++ cmd/agent/flags.go | 2 +- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/cmd/agent/agent.go b/cmd/agent/agent.go index f7674903dd9..3eba6a128a1 100644 --- a/cmd/agent/agent.go +++ b/cmd/agent/agent.go @@ -176,9 +176,10 @@ func run(c *cli.Context) error { return err } - err = writeAgentConfig(agentConfig, agentConfigPath) - if err == nil { - agentConfigPersisted.Set() + if agentConfigPath != "" { + if err := writeAgentConfig(agentConfig, agentConfigPath); err == nil { + agentConfigPersisted.Set() + } } labels := map[string]string{ diff --git a/cmd/agent/config.go b/cmd/agent/config.go index ea1791ba627..61e700e1b07 100644 --- a/cmd/agent/config.go +++ b/cmd/agent/config.go @@ -35,6 +35,10 @@ func readAgentConfig(agentConfigPath string) AgentConfig { AgentID: defaultAgentIDValue, } + if agentConfigPath == "" { + return conf + } + rawAgentConf, err := os.ReadFile(agentConfigPath) if err != nil { if os.IsNotExist(err) { diff --git a/cmd/agent/flags.go b/cmd/agent/flags.go index 481afd4864c..fa43297fed9 100644 --- a/cmd/agent/flags.go +++ b/cmd/agent/flags.go @@ -54,7 +54,7 @@ var flags = []cli.Flag{ &cli.StringFlag{ EnvVars: []string{"WOODPECKER_AGENT_CONFIG_FILE"}, Name: "agent-config", - Usage: "agent config file path", + Usage: "agent config file path, if set empty the agent will be stateless and unregister on termination", Value: "/etc/woodpecker/agent.conf", }, &cli.StringSliceFlag{