talos/internal/app/machined/pkg/system/service_events.go
Andrey Smirnov 96aa9638f7
chore: rename talos-systems/talos to siderolabs/talos
There's a cyclic dependency on siderolink library which imports talos
machinery back. We will fix that after we get talos pushed under a new
name.

Signed-off-by: Andrey Smirnov <andrey.smirnov@talos-systems.com>
2022-11-03 16:50:32 +04:00

111 lines
2.2 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 system
import (
"context"
"fmt"
"sync"
"time"
"github.com/siderolabs/talos/pkg/conditions"
)
// StateEvent is a service event (e.g. 'up', 'down').
type StateEvent string
// Service event list.
const (
StateEventUp = StateEvent("up")
StateEventDown = StateEvent("down")
StateEventFinished = StateEvent("finished")
)
type serviceCondition struct {
mu sync.Mutex
waitingRegister bool
event StateEvent
service string
}
func (sc *serviceCondition) Wait(ctx context.Context) error {
instance.mu.Lock()
svcrunner := instance.state[sc.service]
instance.mu.Unlock()
if svcrunner == nil {
return sc.waitRegister(ctx)
}
return sc.waitEvent(ctx, svcrunner)
}
func (sc *serviceCondition) waitEvent(ctx context.Context, svcrunner *ServiceRunner) error {
notifyCh := make(chan struct{}, 1)
svcrunner.Subscribe(sc.event, notifyCh)
defer svcrunner.Unsubscribe(sc.event, notifyCh)
select {
case <-ctx.Done():
return ctx.Err()
case <-notifyCh:
return nil
}
}
func (sc *serviceCondition) waitRegister(ctx context.Context) error {
sc.mu.Lock()
sc.waitingRegister = true
sc.mu.Unlock()
ticker := time.NewTicker(100 * time.Millisecond)
defer ticker.Stop()
var svcrunner *ServiceRunner
for {
instance.mu.Lock()
svcrunner = instance.state[sc.service]
instance.mu.Unlock()
if svcrunner != nil {
break
}
select {
case <-ctx.Done():
return ctx.Err()
case <-ticker.C:
}
}
sc.mu.Lock()
sc.waitingRegister = false
sc.mu.Unlock()
return sc.waitEvent(ctx, svcrunner)
}
func (sc *serviceCondition) String() string {
sc.mu.Lock()
waitingRegister := sc.waitingRegister
sc.mu.Unlock()
if waitingRegister {
return fmt.Sprintf("service %q to be registered", sc.service)
}
return fmt.Sprintf("service %q to be %q", sc.service, string(sc.event))
}
// WaitForService waits for service to reach some state event.
func WaitForService(event StateEvent, service string) conditions.Condition {
return &serviceCondition{
event: event,
service: service,
}
}