feat: store workload reports and route log results
This commit is contained in:
@@ -40,6 +40,9 @@ type ReportWorkloadsRequest struct {
|
||||
SystemdOk bool `json:"systemd_ok"`
|
||||
SystemdError string `json:"systemd_error,omitempty"`
|
||||
Workloads []Workload `json:"workloads,omitempty"` // empty on the offer call
|
||||
// Full marks the second call. It is not inferred from an empty Workloads
|
||||
// slice: a host running nothing sends an empty list as its full report.
|
||||
Full bool `json:"full,omitempty"`
|
||||
}
|
||||
|
||||
type ReportWorkloadsResponse struct {
|
||||
|
||||
@@ -163,6 +163,70 @@ func (s *vantageServer) ReportPackages(ctx context.Context, req *pb.ReportPackag
|
||||
return &pb.ReportPackagesResponse{NeedFull: false}, nil
|
||||
}
|
||||
|
||||
// ReportWorkloads stores what a server is running.
|
||||
//
|
||||
// It is not gated by licence: the workload registry reads as core fleet
|
||||
// management rather than a premium add-on. If that ever changes, the check
|
||||
// belongs here — gating collection, not display — for the same reason it does
|
||||
// in ReportPackages.
|
||||
func (s *vantageServer) ReportWorkloads(ctx context.Context, req *pb.ReportWorkloadsRequest) (*pb.ReportWorkloadsResponse, error) {
|
||||
srv, err := services.ValidateAgentToken(req.ServerId, req.AgentToken)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Unauthenticated, "invalid agent token")
|
||||
}
|
||||
|
||||
// The offer call: a hash and no body. Answering NeedFull=false here is what
|
||||
// keeps an unchanged 60-second report to one small message.
|
||||
//
|
||||
// The offer is identified by Full, not by an empty Workloads slice: a host
|
||||
// genuinely running nothing sends an empty list as its FULL report, and
|
||||
// inferring the offer from emptiness would leave that host answering
|
||||
// NeedFull=true forever and never storing anything.
|
||||
if !req.Full {
|
||||
known, err := services.HasWorkloadHash(srv.InstanceID, srv.ServerID, req.Hash)
|
||||
if err != nil {
|
||||
log.Printf("workload hash lookup for %s: %v", srv.ServerID, err)
|
||||
return nil, status.Errorf(codes.Internal, "workload hash lookup failed")
|
||||
}
|
||||
return &pb.ReportWorkloadsResponse{NeedFull: !known}, nil
|
||||
}
|
||||
|
||||
wls := make([]models.Workload, len(req.Workloads))
|
||||
for i, w := range req.Workloads {
|
||||
wls[i] = models.Workload{
|
||||
Kind: w.Kind,
|
||||
ID: w.Id,
|
||||
Name: w.Name,
|
||||
State: w.State,
|
||||
Health: w.Health,
|
||||
Image: w.Image,
|
||||
Stack: w.Stack,
|
||||
Ports: w.Ports,
|
||||
Restarts: int(w.Restarts),
|
||||
Protected: w.Protected,
|
||||
}
|
||||
if w.StartedAt != "" {
|
||||
if t, err := time.Parse(time.RFC3339, w.StartedAt); err == nil {
|
||||
wls[i].StartedAt = t
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err := storeWorkloadReport(srv.InstanceID, srv.ServerID, req, wls); err != nil {
|
||||
log.Printf("store workloads for %s: %v", srv.ServerID, err)
|
||||
return nil, status.Errorf(codes.Internal, "failed to store workloads")
|
||||
}
|
||||
return &pb.ReportWorkloadsResponse{NeedFull: false}, nil
|
||||
}
|
||||
|
||||
func storeWorkloadReport(instanceID, serverID string, req *pb.ReportWorkloadsRequest, wls []models.Workload) error {
|
||||
if wls == nil {
|
||||
wls = []models.Workload{}
|
||||
}
|
||||
return services.StoreWorkloads(instanceID, serverID, req.Hash, wls,
|
||||
req.DockerOk, req.DockerError, req.SystemdOk, req.SystemdError)
|
||||
}
|
||||
|
||||
func (s *vantageServer) ReportInventory(ctx context.Context, req *pb.InventoryReport) (*pb.InventoryReportResponse, error) {
|
||||
srv, err := services.ValidateAgentToken(req.ServerId, req.AgentToken)
|
||||
if err != nil {
|
||||
@@ -257,6 +321,13 @@ func (s *vantageServer) CommandStream(stream pb.Vantage_CommandStreamServer) err
|
||||
if m.Result != nil {
|
||||
r := m.Result
|
||||
log.Printf("agent %s cmd %s: success=%v %s", srv.ServerID, r.CommandId, r.Success, r.Message)
|
||||
// Republished so a control action waiting on another pod sees
|
||||
// it. Publishing with no subscriber is a no-op, so this is safe
|
||||
// for every command result rather than only the awaited ones.
|
||||
services.WorkloadResults.DeliverCommand(r)
|
||||
}
|
||||
if m.WorkloadLogsResult != nil {
|
||||
services.WorkloadResults.Deliver(m.WorkloadLogsResult)
|
||||
}
|
||||
if m.StepResult != nil {
|
||||
services.StepResults.Deliver(m.StepResult)
|
||||
|
||||
Reference in New Issue
Block a user