Extends the heartbeat mechanism with a second gRPC service on the same mTLS channel (AgentControl.CheckIn, agent-initiated on the existing heartbeat ticker -- still push-only, no inbound port on any agent) so an agent reports its running config and can pick up an operator-set override. A new web UI section (/agents) lists every agent that's checked in, shows its reported config, and lets an operator edit a narrow, deliberately-scoped subset remotely: batch/heartbeat tuning, and (journald sources only) the unit filter. TLS material and the ingest endpoint are never reportable or remotely editable, by proto shape rather than a validation rule -- a bad or malicious edit there could permanently strand an agent or redirect where its logs go, unlike every other editable field, which only degrades behavior. An override lives only in the agent's memory (agent.toml is never rewritten) and re-syncs on the agent's own schedule; changing the journald filter aborts and respawns the source task since there's no other way to change what's being tailed. Building the hot-reload path surfaced a real, independent, pre-existing bug: shutdown was using poll_timeout(), which only drains once flush_interval has elapsed, silently dropping anything buffered more recently on every graceful shutdown that landed between flushes -- fixed with a new unconditional Batcher::flush_all(), now used at both shutdown and hot-reload. Verified live end-to-end against a real stack: an edited heartbeat interval changed a running agent's actual send cadence within one check-in cycle (confirmed by the real timestamps landing in ClickHouse), and an edited journald filter triggered a real source restart, both reflected back in the next reported-config snapshot. See /docs/agent-management-design.md.
144 lines
5.7 KiB
Go
144 lines
5.7 KiB
Go
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
|
// versions:
|
|
// - protoc-gen-go-grpc v1.6.2
|
|
// - protoc v7.35.1
|
|
// source: sentry/agent/v1/agent_control.proto
|
|
|
|
package agentv1
|
|
|
|
import (
|
|
context "context"
|
|
grpc "google.golang.org/grpc"
|
|
codes "google.golang.org/grpc/codes"
|
|
status "google.golang.org/grpc/status"
|
|
)
|
|
|
|
// This is a compile-time assertion to ensure that this generated file
|
|
// is compatible with the grpc package it is being compiled against.
|
|
// Requires gRPC-Go v1.64.0 or later.
|
|
const _ = grpc.SupportPackageIsVersion9
|
|
|
|
const (
|
|
AgentControl_CheckIn_FullMethodName = "/sentry.agent.v1.AgentControl/CheckIn"
|
|
)
|
|
|
|
// AgentControlClient is the client API for AgentControl service.
|
|
//
|
|
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
|
//
|
|
// AgentControl is the control-plane counterpart to logs.v1.LogIngest's
|
|
// data-plane PushBatch -- the same mTLS channel/connection an agent
|
|
// already has open to ingest, a second gRPC service on the same
|
|
// listener rather than a second protocol or connection the agent would
|
|
// need to maintain (see /docs/agent-management-design.md). CheckIn is
|
|
// agent-initiated, called on the agent's own heartbeat ticker: there is
|
|
// still no path for the platform to reach into an agent uninvited. An
|
|
// agent asks "what should I be running" on its own schedule -- the same
|
|
// push-not-pull posture the heartbeat feature this builds on already
|
|
// established.
|
|
type AgentControlClient interface {
|
|
CheckIn(ctx context.Context, in *CheckInRequest, opts ...grpc.CallOption) (*CheckInResponse, error)
|
|
}
|
|
|
|
type agentControlClient struct {
|
|
cc grpc.ClientConnInterface
|
|
}
|
|
|
|
func NewAgentControlClient(cc grpc.ClientConnInterface) AgentControlClient {
|
|
return &agentControlClient{cc}
|
|
}
|
|
|
|
func (c *agentControlClient) CheckIn(ctx context.Context, in *CheckInRequest, opts ...grpc.CallOption) (*CheckInResponse, error) {
|
|
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
|
out := new(CheckInResponse)
|
|
err := c.cc.Invoke(ctx, AgentControl_CheckIn_FullMethodName, in, out, cOpts...)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return out, nil
|
|
}
|
|
|
|
// AgentControlServer is the server API for AgentControl service.
|
|
// All implementations must embed UnimplementedAgentControlServer
|
|
// for forward compatibility.
|
|
//
|
|
// AgentControl is the control-plane counterpart to logs.v1.LogIngest's
|
|
// data-plane PushBatch -- the same mTLS channel/connection an agent
|
|
// already has open to ingest, a second gRPC service on the same
|
|
// listener rather than a second protocol or connection the agent would
|
|
// need to maintain (see /docs/agent-management-design.md). CheckIn is
|
|
// agent-initiated, called on the agent's own heartbeat ticker: there is
|
|
// still no path for the platform to reach into an agent uninvited. An
|
|
// agent asks "what should I be running" on its own schedule -- the same
|
|
// push-not-pull posture the heartbeat feature this builds on already
|
|
// established.
|
|
type AgentControlServer interface {
|
|
CheckIn(context.Context, *CheckInRequest) (*CheckInResponse, error)
|
|
mustEmbedUnimplementedAgentControlServer()
|
|
}
|
|
|
|
// UnimplementedAgentControlServer must be embedded to have
|
|
// forward compatible implementations.
|
|
//
|
|
// NOTE: this should be embedded by value instead of pointer to avoid a nil
|
|
// pointer dereference when methods are called.
|
|
type UnimplementedAgentControlServer struct{}
|
|
|
|
func (UnimplementedAgentControlServer) CheckIn(context.Context, *CheckInRequest) (*CheckInResponse, error) {
|
|
return nil, status.Error(codes.Unimplemented, "method CheckIn not implemented")
|
|
}
|
|
func (UnimplementedAgentControlServer) mustEmbedUnimplementedAgentControlServer() {}
|
|
func (UnimplementedAgentControlServer) testEmbeddedByValue() {}
|
|
|
|
// UnsafeAgentControlServer may be embedded to opt out of forward compatibility for this service.
|
|
// Use of this interface is not recommended, as added methods to AgentControlServer will
|
|
// result in compilation errors.
|
|
type UnsafeAgentControlServer interface {
|
|
mustEmbedUnimplementedAgentControlServer()
|
|
}
|
|
|
|
func RegisterAgentControlServer(s grpc.ServiceRegistrar, srv AgentControlServer) {
|
|
// If the following call panics, it indicates UnimplementedAgentControlServer was
|
|
// embedded by pointer and is nil. This will cause panics if an
|
|
// unimplemented method is ever invoked, so we test this at initialization
|
|
// time to prevent it from happening at runtime later due to I/O.
|
|
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
|
|
t.testEmbeddedByValue()
|
|
}
|
|
s.RegisterService(&AgentControl_ServiceDesc, srv)
|
|
}
|
|
|
|
func _AgentControl_CheckIn_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
|
in := new(CheckInRequest)
|
|
if err := dec(in); err != nil {
|
|
return nil, err
|
|
}
|
|
if interceptor == nil {
|
|
return srv.(AgentControlServer).CheckIn(ctx, in)
|
|
}
|
|
info := &grpc.UnaryServerInfo{
|
|
Server: srv,
|
|
FullMethod: AgentControl_CheckIn_FullMethodName,
|
|
}
|
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
|
return srv.(AgentControlServer).CheckIn(ctx, req.(*CheckInRequest))
|
|
}
|
|
return interceptor(ctx, in, info, handler)
|
|
}
|
|
|
|
// AgentControl_ServiceDesc is the grpc.ServiceDesc for AgentControl service.
|
|
// It's only intended for direct use with grpc.RegisterService,
|
|
// and not to be introspected or modified (even as a copy)
|
|
var AgentControl_ServiceDesc = grpc.ServiceDesc{
|
|
ServiceName: "sentry.agent.v1.AgentControl",
|
|
HandlerType: (*AgentControlServer)(nil),
|
|
Methods: []grpc.MethodDesc{
|
|
{
|
|
MethodName: "CheckIn",
|
|
Handler: _AgentControl_CheckIn_Handler,
|
|
},
|
|
},
|
|
Streams: []grpc.StreamDesc{},
|
|
Metadata: "sentry/agent/v1/agent_control.proto",
|
|
}
|