Artem Chernyshev 7433150fd8
feat: implement events sink controller
Report Talos events to any gRPC server.
Destination address is specified by using kernel parameters.

Fixes: https://github.com/talos-systems/talos/issues/4458

Signed-off-by: Artem Chernyshev <artem.chernyshev@talos-systems.com>
2021-11-25 18:37:31 +03:00

104 lines
2.6 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 v1alpha1
import (
"context"
"fmt"
"sync"
"github.com/cosi-project/runtime/pkg/controller"
"github.com/cosi-project/runtime/pkg/resource"
"github.com/cosi-project/runtime/pkg/state"
"go.uber.org/zap"
"github.com/talos-systems/talos/internal/app/machined/pkg/runtime"
"github.com/talos-systems/talos/pkg/machinery/api/machine"
"github.com/talos-systems/talos/pkg/machinery/resources/v1alpha1"
)
// ServiceController manages v1alpha1.Service based on services subsystem state.
type ServiceController struct {
V1Alpha1Events runtime.Watcher
}
// Name implements controller.Controller interface.
func (ctrl *ServiceController) Name() string {
return "v1alpha1.ServiceController"
}
// Inputs implements controller.Controller interface.
func (ctrl *ServiceController) Inputs() []controller.Input {
return nil
}
// Outputs implements controller.Controller interface.
func (ctrl *ServiceController) Outputs() []controller.Output {
return []controller.Output{
{
Type: v1alpha1.ServiceType,
Kind: controller.OutputExclusive,
},
}
}
// Run implements controller.Controller interface.
//
//nolint:gocyclo
func (ctrl *ServiceController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {
var wg sync.WaitGroup
wg.Add(1)
if err := ctrl.V1Alpha1Events.Watch(func(eventCh <-chan runtime.EventInfo) {
defer wg.Done()
for {
var (
event runtime.EventInfo
ok bool
)
select {
case <-ctx.Done():
return
case event, ok = <-eventCh:
if !ok {
return
}
}
if msg, ok := event.Payload.(*machine.ServiceStateEvent); ok {
service := v1alpha1.NewService(msg.Service)
switch msg.Action { //nolint:exhaustive
case machine.ServiceStateEvent_RUNNING:
if err := r.Modify(ctx, service, func(r resource.Resource) error {
svc := r.(*v1alpha1.Service) //nolint:errcheck,forcetypeassert
svc.SetRunning(true)
svc.SetHealthy(msg.GetHealth().GetHealthy())
svc.SetUnknown(msg.GetHealth().GetUnknown())
return nil
}); err != nil {
logger.Info(fmt.Sprintf("failed creating service resource %s", service), zap.Error(err))
}
default:
if err := r.Destroy(ctx, service.Metadata()); err != nil && !state.IsNotFoundError(err) {
logger.Info(fmt.Sprintf("failed destroying service resource %s", service), zap.Error(err))
}
}
}
}
}, runtime.WithTailEvents(-1)); err != nil {
return err
}
wg.Wait()
return nil
}