mirror of
https://github.com/siderolabs/talos.git
synced 2025-09-15 02:41:10 +02:00
Add config load + validation errors and address + hostnames events. Signed-off-by: Artem Chernyshev <artem.chernyshev@talos-systems.com>
155 lines
3.5 KiB
Go
155 lines
3.5 KiB
Go
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
package client
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
"log"
|
|
"sync"
|
|
"time"
|
|
|
|
"google.golang.org/grpc/codes"
|
|
|
|
machineapi "github.com/talos-systems/talos/pkg/machinery/api/machine"
|
|
"github.com/talos-systems/talos/pkg/machinery/proto"
|
|
)
|
|
|
|
// EventsOptionFunc defines the options for the Events API.
|
|
type EventsOptionFunc func(opts *machineapi.EventsRequest)
|
|
|
|
// WithTailEvents sets up Events API to return specified number of past events.
|
|
//
|
|
// If number is negative, all the available past events are returned.
|
|
func WithTailEvents(number int32) EventsOptionFunc {
|
|
return func(opts *machineapi.EventsRequest) {
|
|
opts.TailEvents = number
|
|
}
|
|
}
|
|
|
|
// WithTailID sets up Events API to return events with ID > TailID.
|
|
func WithTailID(id string) EventsOptionFunc {
|
|
return func(opts *machineapi.EventsRequest) {
|
|
opts.TailId = id
|
|
}
|
|
}
|
|
|
|
// WithTailDuration sets up Watcher to return events with timestamp >= (now - tailDuration).
|
|
func WithTailDuration(dur time.Duration) EventsOptionFunc {
|
|
return func(opts *machineapi.EventsRequest) {
|
|
opts.TailSeconds = int32(dur / time.Second)
|
|
}
|
|
}
|
|
|
|
// Events implements the proto.OSClient interface.
|
|
func (c *Client) Events(ctx context.Context, opts ...EventsOptionFunc) (stream machineapi.MachineService_EventsClient, err error) {
|
|
var req machineapi.EventsRequest
|
|
|
|
for _, opt := range opts {
|
|
opt(&req)
|
|
}
|
|
|
|
return c.MachineClient.Events(ctx, &req)
|
|
}
|
|
|
|
// Event as received from the API.
|
|
type Event struct {
|
|
Node string
|
|
TypeURL string
|
|
ID string
|
|
Payload proto.Message
|
|
}
|
|
|
|
// EventsWatch wraps Events by providing more simple interface.
|
|
//
|
|
//nolint:gocyclo
|
|
func (c *Client) EventsWatch(ctx context.Context, watchFunc func(<-chan Event), opts ...EventsOptionFunc) error {
|
|
stream, err := c.Events(ctx, opts...)
|
|
if err != nil {
|
|
return fmt.Errorf("error fetching events: %s", err)
|
|
}
|
|
|
|
if err = stream.CloseSend(); err != nil {
|
|
return err
|
|
}
|
|
|
|
defaultNode := RemotePeer(stream.Context()) //nolint:contextcheck
|
|
|
|
var wg sync.WaitGroup
|
|
|
|
defer wg.Wait()
|
|
|
|
ch := make(chan Event)
|
|
defer close(ch)
|
|
|
|
wg.Add(1)
|
|
|
|
go func() {
|
|
defer wg.Done()
|
|
|
|
watchFunc(ch)
|
|
}()
|
|
|
|
for {
|
|
event, err := stream.Recv()
|
|
if err != nil {
|
|
if err == io.EOF || StatusCode(err) == codes.Canceled {
|
|
return nil
|
|
}
|
|
|
|
return fmt.Errorf("failed to watch events: %w", err)
|
|
}
|
|
|
|
typeURL := event.GetData().GetTypeUrl()
|
|
|
|
var msg proto.Message
|
|
|
|
for _, eventType := range []proto.Message{
|
|
&machineapi.SequenceEvent{},
|
|
&machineapi.PhaseEvent{},
|
|
&machineapi.TaskEvent{},
|
|
&machineapi.ServiceStateEvent{},
|
|
&machineapi.ConfigLoadErrorEvent{},
|
|
&machineapi.ConfigValidationErrorEvent{},
|
|
&machineapi.AddressEvent{},
|
|
} {
|
|
if typeURL == "talos/runtime/"+string(eventType.ProtoReflect().Descriptor().FullName()) {
|
|
msg = eventType
|
|
|
|
break
|
|
}
|
|
}
|
|
|
|
if msg == nil {
|
|
// We haven't implemented the handling of this event yet.
|
|
continue
|
|
}
|
|
|
|
if err = proto.Unmarshal(event.GetData().GetValue(), msg); err != nil {
|
|
log.Printf("failed to unmarshal message: %v", err) // TODO: this should be fixed to return errors
|
|
|
|
continue
|
|
}
|
|
|
|
ev := Event{
|
|
Node: defaultNode,
|
|
TypeURL: typeURL,
|
|
ID: event.Id,
|
|
Payload: msg,
|
|
}
|
|
|
|
if event.Metadata != nil {
|
|
ev.Node = event.Metadata.Hostname
|
|
}
|
|
|
|
select {
|
|
case ch <- ev:
|
|
case <-ctx.Done():
|
|
return nil
|
|
}
|
|
}
|
|
}
|