talos/internal/app/init/pkg/system/system.go
2018-12-19 22:22:05 -08:00

75 lines
2.0 KiB
Go

package system
import (
"log"
"sync"
"github.com/autonomy/talos/internal/app/init/pkg/system/conditions"
"github.com/autonomy/talos/internal/pkg/userdata"
)
type singleton struct {
UserData *userdata.UserData
}
var instance *singleton
var once sync.Once
// Service is an interface describing a system service.
type Service interface {
// ID is the service id.
ID(*userdata.UserData) string
// PreFunc is invoked before a command is executed.
PreFunc(*userdata.UserData) error
// Start
Start(*userdata.UserData) error
// PostFunc is invoked after a command is executed.
PostFunc(*userdata.UserData) error
// ConditionFunc describes the conditions under which a service should
// start.
ConditionFunc(*userdata.UserData) conditions.ConditionFunc
}
// Services returns the instance of the system services API.
// TODO(andrewrynhard): This should be a gRPC based API availale on a local
// unix socket.
// nolint: golint
func Services(data *userdata.UserData) *singleton {
once.Do(func() {
instance = &singleton{UserData: data}
})
return instance
}
// Start will invoke the service's Pre, Condition, and Type funcs. If the any
// error occurs in the Pre or Condition invocations, it is up to the caller to
// to restart the service.
func (s *singleton) Start(services ...Service) {
for _, service := range services {
go func(service Service) {
id := service.ID(s.UserData)
if err := service.PreFunc(s.UserData); err != nil {
log.Printf("failed to run pre stage of service %q: %v", id, err)
return
}
_, err := service.ConditionFunc(s.UserData)()
if err != nil {
log.Printf("service %q condition failed: %v", id, err)
return
}
log.Printf("starting service %q", id)
if err := service.Start(s.UserData); err != nil {
log.Printf("failed to start service %q: %v", id, err)
return
}
if err := service.PostFunc(s.UserData); err != nil {
log.Printf("failed to run post stage of service %q: %v", id, err)
return
}
}(service)
}
}