govisor

package module
v0.0.0-...-71a9569 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 20, 2015 License: Apache-2.0 Imports: 13 Imported by: 0

README

govisor

Linux Status Windows Status GitHub License Issues Gitter GoDoc

package govisor is a framework for managing services. It supports dependency graphs of services, and handles starting, stopping, and restarting services as necessary. It also deals with failures, and supports self-healing, and has some advanced logging capabilities. It also offers a REST API for managing your services, as well as a nicer client API, and a snazzy little terminal application to monitor the services.

There is a daemon (govisord) that can be used to manage a tree of process in a manner similar to init or SMF or systemd. However, it is designed to be suitable for use by unprivileged users, and it is possible to run many copies of govisord on the same system (but you will have to choose different TCP management ports.)

Govisord listens by default at http://localhost:8321/

See govisord/main.go for a list of options, etc.

Govisor is designed for embedding as well. You can embed the manager into your own application. The REST API implementation provides a http.Handler, so you can also wrap or embed the API with other web services.

The govisor client application, "govisor", is in the govisor/ directory. It has a number of options, try it with -h to see them.

Documentation

Overview

NOTE: THIS DESCRIBES INTENT, AND DOES NOT REFLECT ACTUAL IMPLEMENTATION (YET!!)

Package govisor provides a pure Go process management framework. This is similar in concept to supervisord, but the implementation and the interfaces are wholly different. Some inspiration is taken from Solaris' SMF facility.

Unlike other frameworks, the intention is that this framework is not a replacement for your system's master process management (i.e. init, upstart, or similar), but rather a tool for user's (or administrators) to manage their own groups of processes as part of application deployment.

Multiple instances of govisor may be deployed, and an instance may be deployed using Go's HTTP handler framework, so that it is possible to register the manager within an existing server instance.

Index

Constants

View Source
const (
	PropProcessFailOnExit PropertyName = "_ProcFailOnExit"
	PropProcessStopCmd                 = "_ProcStopCmd"
	PropProcessStopTime                = "_ProcStopTime"
	PropProcessCheckCmd                = "_ProcCheckCmd"
)
View Source
const (
	PropLogger      PropertyName = "_Logger"      // Where logs get sent
	PropRestart                  = "_Restart"     // Auto-restart on failure
	PropRateLimit                = "_RateLimit"   // Max starts per period
	PropRatePeriod               = "_RatePeriod"  // Period for RateLimit
	PropName                     = "_Name"        // Service name
	PropDescription              = "_Description" // Service description
	PropDepends                  = "_Depends"     // Dependencies list
	PropConflicts                = "_Conflicts"   // Conflicts list
	PropProvides                 = "_Provides"    // Provides list
	PropNotify                   = "_Notify"      // Notification callback
)
View Source
const (
	MaxLogRecords = 1000
)

Variables

View Source
var (
	ErrNoManager    = errors.New("No manager for service")
	ErrConflict     = errors.New("Conflicting service enabled")
	ErrIsEnabled    = errors.New("Service is enabled")
	ErrNotRunning   = errors.New("Service is not running")
	ErrBadPropType  = errors.New("Bad property type")
	ErrBadPropName  = errors.New("Bad property name")
	ErrBadPropValue = errors.New("Bad property value")
	ErrPropReadOnly = errors.New("Property not changeable")
	ErrRateLimited  = errors.New("Restarting too quickly")
)

Functions

This section is empty.

Types

type Log

type Log struct {
	// contains filtered or unexported fields
}

func NewLog

func NewLog() *Log

NewLog returns a Log instance.

func (*Log) Clear

func (log *Log) Clear()

func (*Log) GetRecords

func (log *Log) GetRecords(last int64) ([]LogRecord, int64)

GetRecords returns the records that are stored, as well as an ID suitable for use as an Etag. The last parameter can be the last ID that was checked, in which case this function will return nil immediately if the log has not changed since that ID was returned, without duplicating any records. These IDs are suitable for use as an Etag in REST APIs. Note that IDs are not unique across different Log instances.

func (*Log) Watch

func (log *Log) Watch(last int64, expire time.Duration) int64

func (*Log) Write

func (log *Log) Write(b []byte) (int, error)

Write implements the Writer interface consumed by Logger.

type LogRecord

type LogRecord struct {
	Id   int64     `json:"id,string"`
	Time time.Time `json:"time"`
	Text string    `json:"text"`
}

type Manager

type Manager struct {
	// contains filtered or unexported fields
}

func NewManager

func NewManager(name string) *Manager

func (*Manager) AddService

func (m *Manager) AddService(s *Service)

AddService adds a service, registering it, to the manager.

func (*Manager) DeleteService

func (m *Manager) DeleteService(s *Service) error

DeleteService deletes a service from the manager.

func (*Manager) FindServices

func (m *Manager) FindServices(match string) []*Service

FindServices finds the list of services that have either a matching Name, or Provides. That is, they find all of our services, where the service.Match() would return true for the string match.

func (*Manager) GetInfo

func (m *Manager) GetInfo() *ManagerInfo

GetInfo returns top-level information about the Manager. This is done in a manner that ensures that the info is consistent.

func (*Manager) GetLog

func (m *Manager) GetLog(lastid int64) ([]LogRecord, int64)

func (*Manager) Name

func (m *Manager) Name() string

Name returns the name the manager was allocated with. This makes it possible to distinguish between separate manager instances. This name can influence logged messages and file/directory names.

func (*Manager) Serial

func (m *Manager) Serial() int64

Serial returns the global serial number. This is incremented anytime a service has a state change.

func (*Manager) Services

func (m *Manager) Services() ([]*Service, int64, time.Time)

Services returns all of our services. Note that the order is arbitrary. (At present it happens to be done based on order of addition.)

func (*Manager) SetLogger

func (m *Manager) SetLogger(l *log.Logger)

SetLogger is used to establish a logger. It overrides the default, so it shouldn't be used unless you want to control all logging.

func (*Manager) Shutdown

func (m *Manager) Shutdown()

Shutdown stops all services, and stops monitoring too. Finally, it removes them all from the manager. Think of this as effectively tearing down the entire thing.

func (*Manager) StartMonitoring

func (m *Manager) StartMonitoring()

func (*Manager) StopMonitoring

func (m *Manager) StopMonitoring()

func (*Manager) WatchLog

func (m *Manager) WatchLog(old int64, expire time.Duration) int64

func (*Manager) WatchSerial

func (m *Manager) WatchSerial(old int64, expire time.Duration) int64

WatchSerial monitors for a change in the global serial number.

func (*Manager) WatchServices

func (m *Manager) WatchServices(old int64, expire time.Duration) int64

WatchServices monitors for a change in the list of services.

type ManagerInfo

type ManagerInfo struct {
	Name       string
	Serial     int64
	UpdateTime time.Time
	CreateTime time.Time
}

type MultiLogger

type MultiLogger struct {
	// contains filtered or unexported fields
}

MultiLogger implements a wrapper around log.Logger, that permits a single logger interface to be used to fan out multiple logs. The idea is that it implements an io.Writer, which breaks up the lines and delivers them each to the various contained loggers. The contained loggers may have their own Prefix and Flags, and those shall not interfere with the parent.

func NewMultiLogger

func NewMultiLogger() *MultiLogger

func (*MultiLogger) AddLogger

func (l *MultiLogger) AddLogger(logger *log.Logger)

AddLogger adds a logger to the MultiLogger. Once called, all new log entries will be fanned out to this logger, as well as any others that may have been registered earlier. A logger can only be added once.

func (*MultiLogger) DelLogger

func (l *MultiLogger) DelLogger(logger *log.Logger)

DeleteLogger is removes a logger from the list of destinations that logged events are fanned out to.

func (*MultiLogger) Logger

func (l *MultiLogger) Logger() *log.Logger

func (*MultiLogger) SetFlags

func (l *MultiLogger) SetFlags(flags int)

SetFlags applies the flags to every registered logger.

func (*MultiLogger) SetPrefix

func (l *MultiLogger) SetPrefix(prefix string)

SetPrefix applies the prefix to every registered logger.

func (*MultiLogger) Write

func (l *MultiLogger) Write(b []byte) (int, error)

Write implements the io.Writer, suitable for use with Logger. It is expected that the input is text, delimited by newlines, and delivered an entire line at a time. This isn't exactly io.Writer, but it is the semantic to which the log.Logger interface conforms.

type Process

type Process struct {
	// contains filtered or unexported fields
}

Process represents an actual operating system level process. This implements the Provider interface, and hence Process objects can used as such.

XXX: is there any reason for this to be public? XXX: Should we support Setsid and other SysProcAttr settings?

func (*Process) Check

func (p *Process) Check() error

func (*Process) Conflicts

func (p *Process) Conflicts() []string

func (*Process) Depends

func (p *Process) Depends() []string

func (*Process) Description

func (p *Process) Description() string

func (*Process) Name

func (p *Process) Name() string

func (*Process) Property

func (p *Process) Property(n PropertyName) (interface{}, error)

func (*Process) Provides

func (p *Process) Provides() []string

func (*Process) SetProperty

func (p *Process) SetProperty(n PropertyName, v interface{}) error

func (*Process) Start

func (p *Process) Start() error

func (*Process) Stop

func (p *Process) Stop()

type ProcessManifest

type ProcessManifest struct {
	Name        string        `json:"name"`
	Description string        `json:"description"`
	Command     []string      `json:"command"`
	Env         []string      `json:"env"`
	StopCmd     []string      `json:"stopCommand"`
	StopTime    time.Duration `json:"stopTime"`
	FailOnExit  bool          `json:"failOnExit"`
	CheckCmd    []string      `json:"check"`
	Restart     bool          `json:"restart"`
	Provides    []string      `json:"provides"`
	Depends     []string      `json:"depends"`
	Conflicts   []string      `json:"conflicts"`
}

type PropertyName

type PropertyName string

Property names. Internal names will all start with an underscore. Other, provider specific names, may be supplied. Note that there is no provision for property discovery. Consumers wishing to use a property must know the property name and type.

type Provider

type Provider interface {
	// Name returns the name of the provider.  For example, a
	// provider for SMTP could return return "smtp" here.
	// For services that have variants, an optioanl variant can be
	// returned by appending a colon.  For example, "smtp:sendmail"
	// indicates a variant using Berkeley sendmail, whereas "smtp:qmail"
	// indicates a variant using qmail.  Both of these would satisfy
	// a dependency of "smtp".  Names may include any alpha numeric,
	// or the underscore.  No punctuation (modulo the colon separating
	// primary name and variant) may be used.
	Name() string

	// Description returns what you think.  Should be only 32 characters
	// to avoid UI truncation.
	Description() string

	// Provides returns a list of service names that this provides.
	// The Name is implicitly added, so only additional values need to
	// be listed.
	Provides() []string

	// Depends returns a list of dependencies, that must be satisfied
	// in order for this service to run.  These are names, that can be
	// either fully qualified (such as "smtp:postfix" or just the
	// base name (such as "smtp").
	Depends() []string

	// Conflicts returns a list of incompatible values.  Note that
	// the service itself is excluded when checking, so that one could
	// have a service list conflicts of "smtp", even though it provides
	// "smtp:postfix".  This would ensure that it does not run with any
	// any other service.
	Conflicts() []string

	// Start attempts to start the service.  It blocks until the service
	// is either started successfuly, or has definitively failed.
	Start() error

	// Stop attempts to stop the service.  As with Start, it blocks until
	// the operation is complete.  This is never allowed to fail.
	Stop()

	// Check performs a health check on the service.  This can be just
	// a check that a process is running, or it can include verification
	// by using test protocol packets or queries, or whatever is
	// appropriate.  It runs synchronously as well.  If all is well it
	// returns nil, otherwise it returns an error.  The error message,
	// provided by Error(), should give some clue as to the reason for the
	// failed check.
	Check() error

	// Property returns the value of a property.
	Property(PropertyName) (interface{}, error)

	// SetProperty sets the value of a property.
	SetProperty(PropertyName, interface{}) error
}

Provider is what service providers must implement. Note that except for the Name and Dependencies elements, the service manager promises not to call these methods concurrently. That is, implementers need not worry about locking. Applications should not use this interface.

type Service

type Service struct {
	// contains filtered or unexported fields
}

Service describes a generic system service -- such as a process, or group of processes. Applications are expected to use the Service structure to interact with all managed services.

Implementors can provide custom services (which may be any kind of entity) by implementing the Provider interface.

Service methods are not thread safe, until the service is added to a Manager. Once the service is added to a Manager, the Manager's lock will protect concurrent accesses.

Services go through a number of possible states as illustrated in the following state diagram. Note that these states are logical, as there is no formal state machine in the code. This diagram is for illustration purposes only.

                +------------+
                |            |
      +--------->  Disabled  <-------+
      |         |            |       |
      |         +----+--A----+       |
      |              |  |            |
+-----+----+    +----V--+---+        |
|          |    |           |        |
|  Failed  +---->  DepWait  <----+   |
|          |    |           |    |   |
+-----A--A-+    +----+------+    |   |
      |  |           |           |   |
      |  |      +----v-------+   |   |
      |  |      |            |   |   |
      |  +------+  Starting  |   |   |
      |         |            |   |   |
      |         +----+-------+   |   |
      |              |           |   |
      |          +---V---+       |   |
      |          |       |       |   |
      +----------+  Run  +-------+---+
                 |       |
                 +-------+

func NewProcess

func NewProcess(name string, cmd *exec.Cmd) *Service

func NewProcessFromJson

func NewProcessFromJson(r io.Reader) (*Service, error)

func NewProcessFromManifest

func NewProcessFromManifest(m ProcessManifest) *Service

func NewService

func NewService(p Provider) *Service

NewService allocates a service instance from a Provider. The intention is that Providers use this in their own constructors to present only a Service interface to applications.

func (*Service) Check

func (s *Service) Check() error

Check checks if a service is running, and performs any appropriate health checks. It returns nil if the service is running and healthy, or false otherwise. If it returns false, it will stop the service, as well as dependent services, and put the service into failed state.

func (*Service) Clear

func (s *Service) Clear()

Clear clears any error condition in the service, without actually enabling it. It will attempt to start the service if it isn't already running, and is enabled.

func (*Service) Conflicts

func (s *Service) Conflicts() []string

Conflicts returns a list of strings or service names that cannot be enabled with this one. The system will make sure that attempts to enable the service are rejected. Note that the scope of conflict is limited to a single Manager; that is the check will not prevent two conflicting services running under the control of different Managers.

func (*Service) Depends

func (s *Service) Depends() []string

Depends returns a list of service names. See the Name description for how these are used.

func (*Service) Description

func (s *Service) Description() string

Description returns a descriptive name for the service. If possible, user interfaces should try to allocate at least 32 characters of horizontal space when displaying descriptions.

func (*Service) Disable

func (s *Service) Disable() error

Disable disables the service, stopping it. It also will stop any services which will no longer have satisfied dependencies as a result of this service being disabled. It also clears the error state.

func (*Service) Enable

func (s *Service) Enable() error

Enable enables the service. This will also start any services that may have not been running due to unsatisfied dependencies, but which now are able to (and were otherwise enabled.)

func (*Service) Enabled

func (s *Service) Enabled() bool

Enabled checks if a service is enabled.

func (*Service) Failed

func (s *Service) Failed() bool

Failed returns true if the service is in a failure state.

func (*Service) GetLog

func (s *Service) GetLog(lastid int64) ([]LogRecord, int64)

func (*Service) GetProperty

func (s *Service) GetProperty(n PropertyName) (interface{}, error)

func (*Service) Matches

func (s *Service) Matches(check string) bool

Matches returns true if the service name matches the check. This is true if either the check is a complete match, or if the first part of our name (or Provides) is identical to the check. For example, if our name is "x:y", then this would return true for a check of "x", or "x:y", but not for "x:z", nor "z:y".

func (*Service) Name

func (s *Service) Name() string

The service name. This takes either the form <base> or <base>:<variant>. Except for the colon used to separate the <base> from <variant>, no punctuation characters other than underscores are permitted. When attempting to resolve dependencies, a dependency can list either the full <base>:<variant> name or just <base>. In the former case, the full service name must match. In the latter case, any service with the same <base> component matches.

func (*Service) Provides

func (s *Service) Provides() []string

Provides is a way to indicate other service names that this service offers. This permits a service instance to support multiple real capabilities, or to provide multiple aliases. For example, a daemon might offer "http" and "ftp" both.

func (*Service) Restart

func (s *Service) Restart() error

Restart restarts a service. It also clears any failure condition that may have occurred.

func (*Service) Running

func (s *Service) Running() bool

Running checks if a service is running. This will be false if the service has failed for any reason, or is unable to run due to a missing dependency.

func (*Service) Serial

func (s *Service) Serial() int64

func (*Service) SetProperty

func (s *Service) SetProperty(n PropertyName, v interface{}) error

SetProperty sets a property on the service.

func (*Service) Status

func (s *Service) Status() (string, time.Time)

Status returns the most reason status message, and the time when the status was recorded.

func (*Service) WatchLog

func (s *Service) WatchLog(old int64, expire time.Duration) int64

func (*Service) WatchService

func (s *Service) WatchService(old int64, expire time.Duration) int64

Directories

Path Synopsis
Command govisor implements a client application that communicate to govisord.
Command govisor implements a client application that communicate to govisord.
ui
util
Package util is used for internal implementation bits in the CLI/UI.
Package util is used for internal implementation bits in the CLI/UI.
Command govisord implements a daemon that can manage proceses from manifest files using Govisor.
Command govisord implements a daemon that can manage proceses from manifest files using Govisor.
Package rest implements REST API methods for remotely managing govisor.
Package rest implements REST API methods for remotely managing govisor.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL