immortal

package module
v0.0.0-...-d8073cd Latest Latest
Warning

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

Go to latest
Published: Feb 1, 2024 License: BSD-3-Clause Imports: 29 Imported by: 0

README

⭕ immortal

CircleCI Build Status Coverage Status codecov Go Report Card

A *nix cross-platform (OS agnostic) supervisor

https://immortal.run/

GitHub release GoDoc contributions welcome

Linux precompiled binaries

deb rpm

run on behalf other system user

If services need to run on behalf other system user www, nobody, www-data, not root, immortal should be compiled from source for the desired target/architecture, otherwise, this error may be returned:

Error looking up user: "www". user: Lookup requires cgo

See more: https://golang.org/cmd/cgo/

If using FreeBSD or macOS you can install using pkg/ports or homebrew, for other platforms work is in progress, any help for making the port/package for other systems would be appreciated.

Compile from source

Setup go environment https://golang.org/doc/install

go >= 1.12 is required

For example using $HOME/go for your workspace

$ export GOPATH=$HOME/go

Create the directory:

$ mkdir -p $HOME/go/src/github.com/immortal

Clone project into that directory:

$ git clone git@github.com:immortal/immortal.git $HOME/go/src/github.com/immortal/immortal

Build by just typing make:

$ cd $HOME/go/src/github.com/immortal/immortal
$ make

To install/uninstall:

$ make install
$ make uninstall

configuration example

Content of file /usr/local/etc/immortal/www.yml:

# pkg install go-www
cmd: www
cwd: /usr/ports
log:
    file: /var/log/www.log
    age: 10  # seconds
    num: 7   # int
    size: 1  # MegaBytes
wait: 1
require:
  - foo
  - bar

If foo and bar are not running, the service www will not be started. Skip age, num & size options to avoid log-rotation completely.

foo and bar are the names for the services defined on the same path www.yaml is located, foo.yml & bar.yml

Paths

When using immortaldir:

/usr/local/etc/immortal
|--foo.yml
|--bar.yml
`--www.yml

The name of the file.yml will be used to reference the service to be daemonized excluding the extension .yml.:

foo
bar
www

/var/run/immortal/

/var/run/immortal
|--foo
|  |-lock
|  `-immortal.sock
|--bar
|  |-lock
|  `-immortal.sock
`--www
   |-lock
   `-immortal.sock

immortal like non-root user

Any service launched like not using using immortaldir will follow this structure:

~/.immortal
|--(pid)
|  |--lock
|  `--immortal.sock
|--(pid)
|  |--lock
|  `--immortal.sock
`--(pid)
   |--lock
   `--immortal.sock

The -name argument takes a non-path (e.g., "myservice"), and the argument will be used instead of the pid in the directory structure. For example, immortal -ctl myservice sleep 1000 will be:

~/.immortal
|--myservice
|  |--lock
|  `--immortal.sock

The -ctl argument takes precedence over the -name argument.

immortalctl

Will print current status and allow to manage the services

debug

pgrep -fl "immortal -ctl"  | awk '{print $1}' | xargs watch -n .1 pstree -p

Test status using curl & jq

status:

curl --unix-socket immortal.sock http:/status -s | jq

note the single '/' https://superuser.com/a/925610/284722

down:

curl --unix-socket immortal.sock http://im/signal/d -s | jq

up:

curl --unix-socket immortal.sock http://im/signal/u -s | jq

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func AbsSince

func AbsSince(t time.Time) string

AbsSince return time since in format [days]d[hours]h[minutes]m[seconds.decisecond]s

func Fork

func Fork() (int, error)

Fork crete a new process

func GetJSON

func GetJSON(spath, path string, target interface{}) error

GetJSON unix socket web client

func GetSdir

func GetSdir() string

GetSdir return the main supervise directory, defaults to /var/run/immortal

func GetUserSdir

func GetUserSdir() (string, error)

GetUserSdir returns the $HOME/.immortal

func Green

func Green(s string) string

Green return string in green

func NewLogger

func NewLogger(cfg *Config, quit chan struct{}) *log.Logger

NewLogger return a Logger instance

func NewProcess

func NewProcess(cfg *Config) *process

NewProcess return process instance

func NewStderrLogger

func NewStderrLogger(cfg *Config) *log.Logger

NewStderrLogger return Logger instance

func Red

func Red(s string) string

Red return string in red

func Supervise

func Supervise(d *Daemon) error

Supervise keep daemon process up and running

func Yellow

func Yellow(s string) string

Yellow return string in yellow

Types

type Config

type Config struct {
	Cmd        string            `yaml:"cmd" json:"cmd"`
	Cwd        string            `yaml:",omitempty" json:",omitempty"`
	Env        map[string]string `yaml:",omitempty" json:",omitempty"`
	Log        Log               `yaml:",omitempty" json:",omitempty"`
	Stderr     Log               `yaml:",omitempty" json:",omitempty"`
	Logger     string            `yaml:",omitempty" json:",omitempty"`
	Require    []string          `yaml:",omitempty"`
	RequireCmd string            `yaml:"require_cmd,omitempty"`
	PostExit   string            `yaml:"post_exit,omitempty"`
	User       string            `yaml:",omitempty" json:",omitempty"`
	Wait       uint              `yaml:",omitempty"`
	Retries    int               `yaml:",omitempty"`
	Pid        `yaml:",omitempty" json:",omitempty"`
	// contains filtered or unexported fields
}

Config yaml/command line configuration

func ParseArgs

func ParseArgs(p Parser, fs *flag.FlagSet) (cfg *Config, err error)

ParseArgs parse command arguments

type Control

type Control interface {
	GetStatus(socket string) (*Status, error)
	SendSignal(socket, signal string) (*SignalResponse, error)
	FindServices(dir string) ([]*ServiceStatus, error)
	PurgeServices(dir string) error
	Run(command string) ([]byte, error)
}

Control interface

type Controller

type Controller struct{}

Controller implements Control

func (*Controller) FindServices

func (c *Controller) FindServices(dir string) ([]*ServiceStatus, error)

FindServices return [name, socket path] of service

func (*Controller) GetStatus

func (c *Controller) GetStatus(socket string) (*Status, error)

GetStatus returns service status in json format

func (*Controller) PurgeServices

func (c *Controller) PurgeServices(dir string) error

PurgeServices remove unused service directory

func (*Controller) Run

func (c *Controller) Run(command string) ([]byte, error)

Run executes a command and print combinedOutput

func (*Controller) SendSignal

func (c *Controller) SendSignal(socket, signal string) (*SignalResponse, error)

SendSignal send signal to process

type Daemon

type Daemon struct {
	sync.RWMutex
	// contains filtered or unexported fields
}

Daemon struct

func New

func New(cfg *Config) (*Daemon, error)

New creates a new daemon

func (*Daemon) HandleSignal

func (d *Daemon) HandleSignal(w http.ResponseWriter, r *http.Request)

HandleSignal send signals to the current process

func (*Daemon) HandleStatus

func (d *Daemon) HandleStatus(w http.ResponseWriter, r *http.Request)

HandleStatus return process status

func (*Daemon) IsRunning

func (d *Daemon) IsRunning(pid int) bool

IsRunning check if process is running

func (*Daemon) Listen

func (d *Daemon) Listen() (err error)

Listen creates a unix socket used for control the daemon

func (*Daemon) ReadPidFile

func (d *Daemon) ReadPidFile(pidfile string) (int, error)

ReadPidFile read pid from file if error returns pid 0

func (*Daemon) Run

func (d *Daemon) Run(p Process) (*process, error)

Run returns a process instance

func (*Daemon) WatchPid

func (d *Daemon) WatchPid(pid int, ch chan<- error)

WatchPid check pid changes

func (*Daemon) WritePid

func (d *Daemon) WritePid(file string, pid int) error

WritePid write pid to file

type Flags

type Flags struct {
	CheckConfig bool
	ChildPid    string
	Command     string
	Configfile  string
	Ctl         string
	Envdir      string
	FollowPid   string
	Logfile     string
	Logger      string
	Name        string
	Nodaemon    bool
	ParentPid   string
	Retries     int
	User        string
	Version     bool
	Wait        uint
	Wrkdir      string
}

Flags available command flags

type Log

type Log struct {
	File      string `yaml:",omitempty"`
	Age       int    `yaml:",omitempty"`
	Num       int    `yaml:",omitempty"`
	Size      int    `yaml:",omitempty"`
	Timestamp bool   `yaml:",omitempty"`
}

Log struct run.yml

type LogWriter

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

LogWriter implements Logger

func (*LogWriter) IsLogging

func (l *LogWriter) IsLogging() bool

IsLogging return true if an availale logger exists

func (*LogWriter) Log

func (l *LogWriter) Log(input io.ReadCloser)

Log write to the logger

type Logger

type Logger interface {
	Log(input io.ReadCloser)
	IsLogging() bool
}

Logger interface

type Parse

type Parse struct {
	Flags
	UserLookup func(username string) (*user.User, error)
}

Parse implements parser

func (*Parse) Parse

func (p *Parse) Parse(fs *flag.FlagSet) (*Flags, error)

Parse parse the command line flags

func (*Parse) Usage

func (p *Parse) Usage(fs *flag.FlagSet) func()

Usage prints to standard error a usage message

type Parser

type Parser interface {
	Parse(fs *flag.FlagSet) (*Flags, error)
	// contains filtered or unexported methods
}

Parser interface

type Pid

type Pid struct {
	Follow string `yaml:",omitempty"`
	Parent string `yaml:",omitempty"`
	Child  string `yaml:",omitempty"`
}

Pid struct run.yml

type Process

type Process interface {
	Kill() error
	Pid() int
	Signal(sig syscall.Signal) error
	Start() (*process, error)
	GetProcess() *process
}

Process interface

type ScanDir

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

ScanDir struct

func NewScanDir

func NewScanDir(path string) (*ScanDir, error)

NewScanDir returns ScanDir struct

func (*ScanDir) Scanner

func (s *ScanDir) Scanner(ctl Control)

Scanner searches for run.yml if file changes it will reload(stop-start)

func (*ScanDir) Start

func (s *ScanDir) Start(ctl Control)

Start scans directory every 5 seconds

type ServiceStatus

type ServiceStatus struct {
	Name           string
	Socket         string
	Status         *Status
	SignalResponse *SignalResponse
}

ServiceStatus struct

type SignalResponse

type SignalResponse struct {
	Err string
}

SignalResponse struct to return the error in json format

type Status

type Status struct {
	Pid    int    `json:"pid"`
	Up     string `json:"up,omitempty"`
	Down   string `json:"down,omitempty"`
	Cmd    string `json:"cmd"`
	Fpid   bool   `json:"fpid"`
	Count  int    `json:"count"`
	Status string `json:"status,omitempty"`
}

Status struct

type Supervisor

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

Supervisor for the process

func (*Supervisor) FollowPid

func (s *Supervisor) FollowPid(err error)

FollowPid check if process still up and running if it is, follow the pid, monitor the existing pid created by the process instead of creating another process

func (*Supervisor) ReStart

func (s *Supervisor) ReStart()

ReStart create a new process

func (*Supervisor) Start

func (s *Supervisor) Start() error

Start loop forever

func (*Supervisor) Terminate

func (s *Supervisor) Terminate(err error) bool

Terminate handle process termination

Directories

Path Synopsis
cmd

Jump to

Keyboard shortcuts

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