patrol: sabey.co/patrol Index | Files | Directories

package patrol

import "sabey.co/patrol"

Index

Package Files

api.go api_status.go app.go app_api.go config.go config_api.go config_app.go config_service.go file.go funcs.go history.go patrol.go patrol_api.go patrol_apps.go patrol_http_api.go patrol_http_status.go patrol_services.go patrol_tick.go patrol_udp.go service.go service_api.go timestamp.go uuid.go

Constants

const (
    API_TOGGLE_STATE_ENABLE = iota + 1
    API_TOGGLE_STATE_DISABLE
    API_TOGGLE_STATE_RESTART
    API_TOGGLE_STATE_RUNONCE_ENABLE         // enable runonce
    API_TOGGLE_STATE_RUNONCE_DISABLE        // disable runonce
    API_TOGGLE_STATE_ENABLE_RUNONCE_ENABLE  // enable AND enable runonce
    API_TOGGLE_STATE_ENABLE_RUNONCE_DISABLE // enable AND disable runonce
)
const (
    LISTEN_HTTP_PORT_DEFAULT = 8421
    LISTEN_UDP_PORT_DEFAULT  = 1248
)
const (
    // app name maximum length in bytes
    APP_NAME_MAXLENGTH = 255
    // ping is used by APP_KEEPALIVE_HTTP and APP_KEEPALIVE_UDP
    APP_PING_TIMEOUT_MIN     = 5
    APP_PING_TIMEOUT_DEFAULT = 30
    APP_PING_TIMEOUT_MAX     = 180
    // environment keys
    APP_ENV_APP_ID      = `PATROL_ID`
    APP_ENV_KEEPALIVE   = `PATROL_KEEPALIVE`
    APP_ENV_PID         = `PATROL_PID`
    APP_ENV_LISTEN_HTTP = `PATROL_HTTP`
    APP_ENV_LISTEN_UDP  = `PATROL_UDP`
)
const (
    // KeepAlive is controlled by Patrol:
    // after executing App, Patrol will write the PID to file
    // the upside to this is that we can know exactly when our App exits - we won't have to constantly send "kill -0 PID" to our App to check if it's still alive
    // the downside to this is that if App were to fork and the parent process were to exit we would not be able to track the forked processes, we would then have to respawn our App
    // we're trading fast respawns and external PID access for no child forking
    APP_KEEPALIVE_PID_PATROL = iota + 1
    // KeepAlive is controlled by App:
    // once an App spawns the App is required to write its own PID to file
    // the upside to this is that if the parent process were to fork, the child process would write its new PID to file and Patrol would read and monitor that latest PID instead
    // the downside to this is that we constantly have to load the PID from file and send "kill -0 PID" to check if the process is still alive
    // the other downside is that we may want to optionally check that the PID belongs to Binary, and if it were not we would have to respawn our App
    // this will allow easy child forking and the ability for the parent process to exit after forking
    // the other trade off is that we won't be able to see the exact time when our monitored PID process exits, leaving a possible delay between respawn
    // see further notes at App.PIDVerify
    APP_KEEPALIVE_PID_APP
    // KeepAlive is controlled by HTTP:
    // once an App spawns the App is required intermittently send a HTTP POST to the Patrol JSON API as the keepalive method
    // the upside to this is that we don't have to monitor a PID file and it supports child forking
    // while we won't monitor the PID file here the HTTP POST is required to POST a PID, this way we can send a signal to the PID from the gui admin page for example
    // the downside is that the App must support HTTP clients and have a way to easily do intermittent HTTP POSTs, this might be a burden for most Apps
    APP_KEEPALIVE_HTTP
    // KeepAlive is controlled by UDP:
    // this is similar to HTTP except that it requires less overhead with the added downside that your App does not get a returned confirmation that Patrol is receiving your pings
    // this could be a steep price to pay should the Patrol UDP listener become unresponsive or your UDP packets never arrive, this would result in the App respawning
    APP_KEEPALIVE_UDP
)

there are multiple methods of process management, none of them are perfect! they all have their tradeoffs!!!

const (
    TICKEVERY_MIN     = 5
    TICKEVERY_MAX     = 120
    TICKEVERY_DEFAULT = 15
    HISTORY_MIN       = 5
    HISTORY_MAX       = 1000
    HISTORY_DEFAULT   = 100
)
const (
    PATROL_ENV_UNITTEST_KEY   = `PATROL_UNITTEST`
    PATROL_ENV_UNITTEST_VALUE = `I KNOW WHAT I AM DOING`
)
const (
    // service name maximum length in bytes
    SERVICE_NAME_MAXLENGTH = 255
    // service maximum length in bytes
    SERVICE_MAXLENGTH = 63
)
const (
    // this is an alias for "service * status"
    // ie: "service ssh status"
    SERVICE_MANAGEMENT_SERVICE = iota + 1
    // this is an alias for "/etc/init.d/* status"
    // ie: "/etc/init.d/ssh status"
    SERVICE_MANAGEMENT_INITD
)
const (
    SECRET_MAX_LENGTH = 128
)

Variables

var (
    ERR_APP_PING_EXPIRED                = fmt.Errorf("App Ping Expired")
    ERR_APP_KEEPALIVE_PATROL_NOTRUNNING = fmt.Errorf("App KeepAlive Patrol Method not running")
    ERR_APP_PIDFILE_NOTFOUND            = fmt.Errorf("App PID File not found")
    ERR_APP_PIDFILE_INVALID             = fmt.Errorf("App PID File was invalid")
)
var (
    ERR_CONFIG_NIL              = fmt.Errorf("Config was NIL")
    ERR_PATROL_EMPTY            = fmt.Errorf("Patrol Apps and Servers were both empty")
    ERR_APPS_KEY_EMPTY          = fmt.Errorf("App Key was empty")
    ERR_APPS_KEY_INVALID        = fmt.Errorf("App Key was invalid")
    ERR_APPS_APP_NIL            = fmt.Errorf("App was nil")
    ERR_SERVICES_KEY_EMPTY      = fmt.Errorf("Service Key was empty")
    ERR_SERVICES_KEY_INVALID    = fmt.Errorf("Service Key was invalid")
    ERR_SERVICES_SERVICE_NIL    = fmt.Errorf("Service was nil")
    ERR_APP_LABEL_DUPLICATE     = fmt.Errorf("Duplicate App Label")
    ERR_SERVICE_LABEL_DUPLICATE = fmt.Errorf("Duplicate Service Label")
    ERR_LISTEN_HTTP_EMPTY       = fmt.Errorf("HTTP Listeners were empty, we required one to exist!")
    ERR_LISTEN_UDP_EMPTY        = fmt.Errorf("UDP Listeners were empty, we required one to exist!")
    ERR_SECRET_TOOLONG          = fmt.Errorf("Secret Longer than %d bytes", SECRET_MAX_LENGTH)
)
var (
    ERR_APP_NAME_EMPTY                = fmt.Errorf("App Name was empty")
    ERR_APP_NAME_MAXLENGTH            = fmt.Errorf("App Name was longer than 255 bytes")
    ERR_APP_WORKINGDIRECTORY_EMPTY    = fmt.Errorf("App WorkingDirectory was empty")
    ERR_APP_WORKINGDIRECTORY_RELATIVE = fmt.Errorf("App WorkingDirectory was relative")
    ERR_APP_WORKINGDIRECTORY_UNCLEAN  = fmt.Errorf("App WorkingDirectory was unclean")
    ERR_APP_BINARY_EMPTY              = fmt.Errorf("App Binary was empty")
    ERR_APP_BINARY_UNCLEAN            = fmt.Errorf("App Binary was unclean")
    ERR_APP_LOGDIRECTORY_EMPTY        = fmt.Errorf("App Log Directory was empty")
    ERR_APP_LOGDIRECTORY_UNCLEAN      = fmt.Errorf("App Log Directory was unclean")
    ERR_APP_KEEPALIVE_INVALID         = fmt.Errorf("App KeepAlive was invalid, please select a keep alive method!")
    ERR_APP_PIDPATH_EMPTY             = fmt.Errorf("App PIDPATH was empty")
    ERR_APP_PIDPATH_UNCLEAN           = fmt.Errorf("App PIDPath was unclean")
    ERR_APP_EXECUTETIMEOUT_INVALID    = fmt.Errorf("App Excute Timeout < 0")
)
var (
    ERR_SERVICE_EMPTY                      = fmt.Errorf("Service was empty")
    ERR_SERVICE_MAXLENGTH                  = fmt.Errorf("Service was longer than 63 bytes")
    ERR_SERVICE_NAME_EMPTY                 = fmt.Errorf("Service Name was empty")
    ERR_SERVICE_NAME_MAXLENGTH             = fmt.Errorf("Service Name was longer than 255 bytes")
    ERR_SERVICE_MANAGEMENT_INVALID         = fmt.Errorf("Service Management was invalid, please select a method!")
    ERR_SERVICE_MANAGEMENT_START_INVALID   = fmt.Errorf("Service Management Start was invalid, please select a method!")
    ERR_SERVICE_MANAGEMENT_STATUS_INVALID  = fmt.Errorf("Service Management Status was invalid, please select a method!")
    ERR_SERVICE_MANAGEMENT_STOP_INVALID    = fmt.Errorf("Service Management Stop was invalid, please select a method!")
    ERR_SERVICE_MANAGEMENT_RESTART_INVALID = fmt.Errorf("Service Management Restart was invalid, please select a method!")
    ERR_SERVICE_INVALID_EXITCODE           = fmt.Errorf("Service contained an Invalid Exit Code")
    ERR_SERVICE_DUPLICATE_EXITCODE         = fmt.Errorf("Service contained a Duplicate Exit Code")
)
var (
    ERR_PATH_INVALID = fmt.Errorf("Path can NOT be current or parent Directory!")
    ERR_DIRECTORY    = fmt.Errorf("Path was a Directory")
)
var (
    ERR_PATROL_ALREADYRUNNING = fmt.Errorf("Patrol is already running!")
    ERR_PATROL_NOTRUNNING     = fmt.Errorf("Patrol is NOT running!")
    ERR_PATROL_SHUTDOWN       = fmt.Errorf("Patrol is Shutdown")
)

func IsAppServiceID Uses

func IsAppServiceID(
    key string,
) bool

func IsPathClean Uses

func IsPathClean(path string) bool

func OpenFile Uses

func OpenFile(
    path string,
) (
    *os.File,
    error,
)

type API_Request Uses

type API_Request struct {
    // Unique Identifier
    ID  string `json:"id,omitempty"`
    // Group: `app` or `service`
    Group string `json:"group,omitempty"`
    // Ping?
    // Only supported by either APP_KEEPALIVE_HTTP or APP_KEEPALIVE_UDP
    // If APP_KEEPALIVE_HTTP is used, the HTTP endpoint MUST be used
    // If APP_KEEPALIVE_UDP is used, the UDP endpoint MUST be used
    Ping bool `json:"ping,omitempty"`
    // App Process ID
    // Ping MUST be true if we wish to send a PID
    PID uint32 `json:"pid,omitempty"`
    // Toggle State
    //
    // API_TOGGLE_STATE_ENABLE = 1
    // API_TOGGLE_STATE_DISABLE = 2
    // API_TOGGLE_STATE_RESTART = 3
    // API_TOGGLE_STATE_RUNONCE_ENABLE = 4
    // API_TOGGLE_STATE_RUNONCE_DISABLE = 5
    // API_TOGGLE_STATE_ENABLE_RUNONCE_ENABLE = 6
    // API_TOGGLE_STATE_ENABLE_RUNONCE_DISABLE = 7
    //
    // API_TOGGLE_STATE_ENABLE: Enable App or Service
    // API_TOGGLE_STATE_DISABLE: Disable App or Service
    // API_TOGGLE_STATE_RESTART: Restart App or Service, Enable App or Service if Disabled
    // API_TOGGLE_STATE_RUNONCE_ENABLE: Enable RunOnce for App or Service
    // API_TOGGLE_STATE_RUNONCE_DISABLE: Disable RunOnce for App or Service
    // API_TOGGLE_STATE_ENABLE_RUNONCE_ENABLE: Enable App or Service and Enable RunOnce
    // API_TOGGLE_STATE_ENABLE_RUNONCE_DISABLE: Enable App or Service and Disable RunOnce
    Toggle uint8 `json:"toggle,omitempty"`
    // Return History?
    History bool `json:"history,omitempty"`
    // KeyValue
    KeyValue map[string]interface{} `json:"keyvalue,omitempty"`
    // If KeyValueReplace is true, previous KeyValue will be replaced with KeyValue
    KeyValueReplace bool `json:"keyvalue-replace,omitempty"`
    // Secret is required to access the /api GET and POST endpoints
    Secret string `json:"secret,omitempty"`
    // CAS IS OPTIONAL
    // if CAS is NOT set: we will ignore it and we will override all of our values and state!!!
    // if CAS IS SET: we will only override values if our CAS is correct!
    // HOWEVER, we will ALWAYS update our PING/LastSeen value REGARDLESS OF CAS!!!
    // updating `Ping, LastSeen, or PID` will cause our CAS to be incremented!!!
    CAS uint64 `json:"cas,omitempty"`
}

Requests by Default are STATELESS - If no values are set then nothing is modified! The reason we're stateless by default is so that our UDP endpoint can make requests as if it were a HTTP GET Request UDP has the downside that if an error occurs a response will not be sent in return

func (*API_Request) IsValid Uses

func (self *API_Request) IsValid() bool

type API_Response Uses

type API_Response struct {
    // Unique Identifier
    ID  string `json:"id,omitempty"`
    // Instance ID - UUIDv4 - Only exists IF we're running!
    InstanceID string `json:"instance-id,omitempty"`
    // Group: `app` or `service`
    Group string `json:"group,omitempty"`
    // Display Name
    Name string `json:"name,omitempty"`
    // App Process ID
    PID uint32 `json:"pid,omitempty"`
    // Timestamp App or Service started at
    Started *Timestamp `json:"started,omitempty"`
    // Timestamp App or Service was last seen
    LastSeen *Timestamp `json:"lastseen,omitempty"`
    // Is our App or Service Disabled?
    Disabled bool `json:"disabled,omitempty"`
    // Is our App or Service in a Restart state?
    Restart bool `json:"restart,omitempty"`
    // Is our App or Service set to RunOnce?
    RunOnce bool `json:"run-once,omitempty"`
    // Is Patrol in a Shutdown state?
    Shutdown bool `json:"shutdown,omitempty"`
    // History of previous App or Service states at the time of close()
    History []*History `json:"history,omitempty"`
    // Current state's KeyValue
    KeyValue map[string]interface{} `json:"keyvalue,omitempty"`
    // Does this App or Service require a Secret to modify?
    Secret bool `json:"secret,omitempty"`
    // Did any Errors occur?
    Errors []string `json:"errors,omitempty"`
    // like all of our other values, CAS is a snapshot of our PREVIOUS state
    // we are NEVER going to return our current CAS after modifying our current state or values
    // the reason for this is that if a modification request is successful, we know our CAS is CAS + 1
    // if we were to take a snapshot, update our object, then get our CAS ---
    // we could never actually verify what our current state or values are!!!
    // the reason for this has to do with triggers, we NEVER KNOW when we're going to unlock and/or execute triggers!!!
    // there are going to be very many scenarios where an API request is made and our CAS is updated more than once!!!
    // we're never in a scenario where we take a snapshot, update, and get our CAS WITHOUT UNLOCKING!!!
    // if we want to make a clean CAS, we should do a REQUEST without modifying anything(no ping), then do a secondary request without incrementing CAS!
    CAS uint64 `json:"cas,omitempty"`
    // CASInvalid is the only exception to data that references our previous snapshot
    // We need to know if our CAS was successful or not!
    // I prefer to have this as invalid and not valid as most requests without a CAS will be valid!
    CASInvalid bool `json:"cas-invalid,omitempty"`
    // contains filtered or unexported fields
}

An API Response references our STATE at the time of Request If any values change or CAS is incremented, they will STILL reference the premodification state!

When using UDP, we won't be able to respond with all of our data, we're going to have to limit our response size We're going to limit our response to: `id, group, pid, started, lastseen, disabled, restart, run-once, shutdown` We'll have to ignore `history, keyvalue, and errors`, if they're needed the HTTP endpoint should be used instead

func (*API_Response) IsValid Uses

func (self *API_Response) IsValid() bool

func (*API_Response) NewAPIHistory Uses

func (self *API_Response) NewAPIHistory() *History

func (*API_Response) NewAPITimestamp Uses

func (self *API_Response) NewAPITimestamp() *Timestamp

func (*API_Response) UnmarshalJSON Uses

func (self *API_Response) UnmarshalJSON(
    data []byte,
) error

type API_Status Uses

type API_Status struct {
    // Instance ID - UUIDv4
    InstanceID string                   `json:"instance-id,omitempty"`
    Apps       map[string]*API_Response `json:"apps,omitempty"`
    Services   map[string]*API_Response `json:"service,omitempty"`
    // Timestamp Patrol started at
    Started *Timestamp `json:"started,omitempty"`
    // Is Patrol in a Shutdown state?
    Shutdown bool `json:"shutdown,omitempty"`
}

type App Uses

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

func (*App) Disable Uses

func (self *App) Disable()

func (*App) DisableRunOnce Uses

func (self *App) DisableRunOnce()

func (*App) Enable Uses

func (self *App) Enable()

func (*App) EnableRunOnce Uses

func (self *App) EnableRunOnce()

func (*App) GetCAS Uses

func (self *App) GetCAS() uint64

func (*App) GetConfig Uses

func (self *App) GetConfig() *ConfigApp

func (*App) GetHistory Uses

func (self *App) GetHistory() []*History

func (*App) GetID Uses

func (self *App) GetID() string

func (*App) GetInstanceID Uses

func (self *App) GetInstanceID() string

func (*App) GetKeyValue Uses

func (self *App) GetKeyValue() map[string]interface{}

func (*App) GetLastSeen Uses

func (self *App) GetLastSeen() time.Time

func (*App) GetPID Uses

func (self *App) GetPID() uint32

func (*App) GetPatrol Uses

func (self *App) GetPatrol() *Patrol

func (*App) GetStarted Uses

func (self *App) GetStarted() time.Time

func (*App) GetStartedLog Uses

func (self *App) GetStartedLog() time.Time

func (*App) GetStderrLog Uses

func (self *App) GetStderrLog() string

func (*App) GetStdoutLog Uses

func (self *App) GetStdoutLog() string

func (*App) IsDisabled Uses

func (self *App) IsDisabled() bool

func (*App) IsRestart Uses

func (self *App) IsRestart() bool

func (*App) IsRunOnce Uses

func (self *App) IsRunOnce() bool

func (*App) IsRunOnceConsumed Uses

func (self *App) IsRunOnceConsumed() bool

func (*App) IsRunning Uses

func (self *App) IsRunning() bool

func (*App) IsSTDMerged Uses

func (self *App) IsSTDMerged() bool

func (*App) IsValid Uses

func (self *App) IsValid() bool

func (*App) ReplaceKeyValue Uses

func (self *App) ReplaceKeyValue(
    kv map[string]interface{},
)

func (*App) Restart Uses

func (self *App) Restart()

func (*App) SetKeyValue Uses

func (self *App) SetKeyValue(
    kv map[string]interface{},
)

func (*App) Snapshot Uses

func (self *App) Snapshot() *API_Response

func (*App) Toggle Uses

func (self *App) Toggle(
    toggle uint8,
)

type Config Uses

type Config struct {
    // Apps/Services must contain a unique non empty key: ( 0-9 A-Z a-z - )
    // ID MUST be usable as a valid hostname label, ie: len <= 63 AND no starting/ending -
    // Keys are NOT our binary name
    // Keys are only used as unique identifiers for our API and Keep Alive
    Apps     map[string]*ConfigApp     `json:"apps,omitempty"`
    Services map[string]*ConfigService `json:"services,omitempty"`
    // TickEvery is an integer value in seconds of how often we will check the state of our Apps and Services
    // Value of 0 Defaults to 15 seconds
    TickEvery int `json:"tick-every,omitempty"`
    // History is the maximum amount of instance history we should hold
    // Value of 0 Defaults to 100
    History int `json:"history,omitempty"`
    // Timestamp Layout is used by the JSON API and HTTP GUI templates
    //
    // Timestamp Layout can be found here:
    // https://golang.org/pkg/time/#pkg-constants
    // https://golang.org/pkg/time/#example_Time_Format
    //
    // The recommended value is RFC1123Z: "Mon, 02 Jan 2006 15:04:05 -0700"
    //
    // An empty value will default to time.String()
    // https://golang.org/pkg/time/#Time.String
    // This default is: "2006-01-02 15:04:05.999999999 -0700 MST"
    // This default will also include our monotonic clock as a suffix: "m=±<value>"
    Timestamp string `json:"json-timestamp,omitempty"`
    // PingTimeout is an integer value in seconds of how often we require a Ping to be sent
    // This only applies to App KeepAlives: APP_KEEPALIVE_HTTP and APP_KEEPALIVE_UDP
    PingTimeout int `json:"ping-timeout,omitempty"`
    // ListenHTTP/ListenUDP is our list of listeners
    // These values are passed as Environment Variables to our executed Apps as JSON Arrays
    //
    // Example Environment Variables:
    // PATROL_HTTP=["127.0.0.1:8421"]
    // PATROL_UDP=["127.0.0.1:1248"]
    //
    // When using APP_KEEPALIVE_HTTP and APP_KEEPALIVE_UDP, these are the addresses we MUST ping
    ListenHTTP []string `json:"listen-http,omitempty"`
    ListenUDP  []string `json:"listen-udp,omitempty"`
    // HTTP/UDP currently only support the attribute `listen`
    // This will allow us to overwrite our default listeners for HTTP and UDP
    // In the future this will include additional options.
    HTTP *ConfigHTTP `json:"http,omitempty"`
    UDP  *ConfigUDP  `json:"udp,omitempty"`
    // Triggers are only available when you extend Patrol as a library
    // These values will NOT be able to be set from `config.json` - They must be set manually
    //
    // TriggerStart is called on CreatePatrol
    // This will only be called ONCE
    // If an error is returned a Patrol object will NOT be returned!
    TriggerStart func(
        patrol *Patrol,
    ) error `json:"-"`
    // TriggerShutdown is called when we call Patrol.Shutdown()
    // This will only be called ONCE
    // Once Patrol.Shutdown() is called our Patrol object will no longer be usable
    TriggerShutdown func(
        patrol *Patrol,
    )   `json:"-"`
    // TriggerStarted is called every time we call Patrol.Start()
    TriggerStarted func(
        patrol *Patrol,
    )   `json:"-"`
    // TriggerTick is called every time we Patrol.tick() and BEFORE we check our App and Service States
    TriggerTick func(
        patrol *Patrol,
    )   `json:"-"`
    // TriggerStopped is called every time we call Patrol.Stop()
    TriggerStopped func(
        patrol *Patrol,
    )   `json:"-"`
    // Extra Unstructured Data
    X   json.RawMessage `json:"x,omitempty"`
    // contains filtered or unexported fields
}

func LoadConfig Uses

func LoadConfig(
    path string,
) (
    *Config,
    error,
)

func (*Config) Clone Uses

func (self *Config) Clone() *Config

func (*Config) IsValid Uses

func (self *Config) IsValid() bool

func (*Config) Validate Uses

func (self *Config) Validate() error

type ConfigApp Uses

type ConfigApp struct {
    // KeepAlive Method
    //
    // APP_KEEPALIVE_PID_PATROL = 1
    // APP_KEEPALIVE_PID_APP = 2
    // APP_KEEPALIVE_HTTP = 3
    // APP_KEEPALIVE_UDP = 4
    //
    // PID_PATROL: Patrol will watch the execution of the Application. Apps will not be able to fork.
    // PID_APP: The Application is required to write its CURRENT PID to our `pid-path`. Patrol will `kill -0 PID` to verify that the App is running. This option should be used for forking processes.
    // HTTP: The Application must send a Ping request to our HTTP API.
    // UDP: The Application must send a Ping request to our UDP API.
    KeepAlive int `json:"keepalive,omitempty"`
    // Name is used as our Display Name in our HTTP GUI.
    // Name can contain any characters but must be less than 255 bytes in length.
    Name string `json:"name,omitempty"`
    // Binary is the relative path to the executable
    Binary string `json:"binary,omitempty"`
    // Working Directory is the ABSOLUTE Path to our Application Directory.
    // Binary, LogDirectory, and PidPath are RELATIVE to this Path!
    //
    // The only time WorkingDirectory is allowed to be relative is if we're prefixed with ~/
    // If prefixed with ~/, we will then replace it with our current users home directory.
    WorkingDirectory string `json:"working-directory,omitempty"`
    // Log Directory is the relative path to our log directory.
    // STDErr and STDOut Logs are held in a `YEAR/MONTH/DAY` sub folder.
    LogDirectory string `json:"log-directory,omitempty"`
    // Path is the relative path to our PID file.
    // PID is optional, it is only required when using the KeepAlive method: APP_KEEPALIVE_PID_APP
    // Our PID file must ONLY contain the integer of our current PID
    PIDPath string `json:"pid-path,omitempty"`
    // PIDVerify - Should we verify that our PID belongs to Binary?
    // PIDVerify is optional, it is only supported when using the KeepAlive method: APP_KEEPALIVE_PID_APP
    // This currently is NOT supported.
    // By default when we execute an App - `ps aux` will report our FULL PATH and BINARY as our first Arg.
    // If our process should fork, we're unsure of how this will change. We may have to compare that PID contains at the very least Binary in the first Arg.
    PIDVerify bool `json:"pid-verify,omitempty"`
    // If Disabled is true our App won't be executed until enabled.
    // The only way to enable an App once Patrol is started is to use the API or restart Patrol
    // If we are Disabled and we discover an App that is running, we will signal it to stop.
    Disabled bool `json:"disabled,omitempty"`
    // KeyValue - prexisting values to populate objects with on init
    KeyValue map[string]interface{} `json:"keyvalue,omitempty"`
    // KeyValueClear if true will cause our App KeyValue to be cleared once a new instance of our App is started.
    KeyValueClear bool `json:"keyvalue-clear,omitempty"`
    // If Secret is set, we will require a secret to be passed when pinging and modifying the state of our App from our HTTP and UDP API.
    // We are not going to throttle comparing our secret. Choose a secret with enough bits of uniqueness and don't make your Patrol instance public!
    // If you are worried about your secret being public, use TLS and HTTP, DO NOT USE UDP!!!
    Secret string `json:"secret,omitempty"`
    ////////////
    // os.Cmd //
    ////////////
    // ExecuteTimeout is an optional value in seconds of how long we will run our App for.
    // A Value of 0 will disable this.
    ExecuteTimeout int `json:"execute-timeout,omitempty"`
    // Args holds command line arguments, including the command as Args[0].
    // If the Args field is empty or nil, Run uses {Path}.
    //
    // In typical use, both Path and Args are set by calling Command.
    Args []string `json:"args,omitempty"`
    // os.Cmd.Env specifies the environment of the process.
    // Each entry is of the form "key=value".
    // If os.Cmd.Env is nil, the new process uses the current process's environment.
    // If os.Cmd.Env contains duplicate environment keys, only the last value in the slice for each duplicate key is used.
    //
    // We're going to include our own Patrol related environment variables, so EnvParent is required if we wish to include parent values.
    Env []string `json:"env,omitempty"`
    // If EnvParent is true, we will prepend all of our Patrol environment variables to the execution of our process.
    EnvParent bool `json:"env-parent,omitempty"`
    // These options are only available when you extend Patrol as a library
    // These values will NOT be able to be set from `config.json` - They must be set manually
    //
    // ExtraArgs is an optional set of values that will be appended to Args.
    ExtraArgs func(
        id string,
    ) []string `json:"-"`
    // ExtraEnv is an optional set of values that will be appended to Env.
    ExtraEnv func(
        id string,
    ) []string `json:"-"`
    // Stdin specifies the process's standard input.
    //
    // If Stdin is nil, the process reads from the null device (os.DevNull).
    //
    // If Stdin is an *os.File, the process's standard input is connected
    // directly to that file.
    //
    // Otherwise, during the execution of the command a separate
    // goroutine reads from Stdin and delivers that data to the command
    // over a pipe. In this case, Wait does not complete until the goroutine
    // stops copying, either because it has reached the end of Stdin
    // (EOF or a read error) or because writing to the pipe returned an error.
    Stdin io.Reader `json:"-"`
    // Stdout and Stderr specify the process's standard output and error.
    //
    // If either is nil, Run connects the corresponding file descriptor
    // to the null device (os.DevNull).
    //
    // If either is an *os.File, the corresponding output from the process
    // is connected directly to that file.
    //
    // Otherwise, during the execution of the command a separate goroutine
    // reads from the process over a pipe and delivers that data to the
    // corresponding Writer. In this case, Wait does not complete until the
    // goroutine reaches EOF or encounters an error.
    //
    // If Stdout and Stderr are the same writer, and have a type that can
    // be compared with ==, at most one goroutine at a time will call Write.
    //
    // If this value is nil, Patrol will create its own file located in our Log Directory.
    // If this value is nil, this file will also be able to be read from the HTTP GUI.
    Stdout io.Writer `json:"-"`
    Stderr io.Writer `json:"-"`
    // Merge Stdout and Stderr into a single file?
    StdMerge bool `json:"std-merge,omitempty"`
    // ExtraFiles specifies additional open files to be inherited by the
    // new process. It does not include standard input, standard output, or
    // standard error. If non-nil, entry i becomes file descriptor 3+i.
    ExtraFiles func(
        id string,
    ) []*os.File `json:"-"`
    // TriggerStart is called from tick in runApps() before we attempt to execute an App.
    TriggerStart func(
        app *App,
    )   `json:"-"`
    // TriggerStarted is called from tick in runApps() and isAppRunning()
    // This is called after we either execute a new App or we discover a newly running App.
    TriggerStarted func(
        app *App,
    )   `json:"-"`
    // TriggerStartedPinged is called from App.apiRequest() when we discover a newly running App from a Ping request.
    TriggerStartedPinged func(
        app *App,
    )   `json:"-"`
    // TriggerStartFailed is called from tick in runApps() when we fail to execute a new App.
    TriggerStartFailed func(
        app *App,
    )   `json:"-"`
    // TriggerRunning is called from tick() when we discover an App is running.
    TriggerRunning func(
        app *App,
    )   `json:"-"`
    // TriggerDisabled is called from tick() when we discover an App that is disabled.
    TriggerDisabled func(
        app *App,
    )   `json:"-"`
    // TriggerClosed is called from App.close() when we discover a previous instance of an App is closed.
    TriggerClosed func(
        app *App,
        history *History,
    )   `json:"-"`
    // TriggerPinged is from App.apiRequest() when we discover an App is running from a Ping request.
    TriggerPinged func(
        app *App,
    )   `json:"-"`
    // TriggerShutdown is called when we call Patrol.Shutdown()
    // This will only be called ONCE
    // This is called regardless if our App is running or disabled!
    TriggerShutdown func(
        app *App,
    )   `json:"-"`
    // Extra Unstructured Data
    X   json.RawMessage `json:"x,omitempty"`
}

func (*ConfigApp) Clone Uses

func (self *ConfigApp) Clone() *ConfigApp

func (*ConfigApp) IsValid Uses

func (self *ConfigApp) IsValid() bool

func (*ConfigApp) Validate Uses

func (self *ConfigApp) Validate() error

type ConfigHTTP Uses

type ConfigHTTP struct {
    Listen string `json:"listen,omitempty"`
    // Extra Unstructured Data
    X   json.RawMessage `json:"x,omitempty"`
}

func (*ConfigHTTP) Clone Uses

func (self *ConfigHTTP) Clone() *ConfigHTTP

func (*ConfigHTTP) IsValid Uses

func (self *ConfigHTTP) IsValid() bool

type ConfigService Uses

type ConfigService struct {
    // Management Method
    //
    // SERVICE_MANAGEMENT_SERVICE = 1
    // SERVICE_MANAGEMENT_INITD = 2
    //
    // SERVICE_MANAGEMENT_SERVICE: Patrol will use the command `service *`
    // SERVICE_MANAGEMENT_INITD: Patrol will use the command `/etc/init.d/*`
    //
    // If Management is set it will ignore all of the Management Start/Status/Stop/Restart values
    // If Management is 0, Start/Status/Stop/Restart must each be individually set!
    // If for whatever reason is necessary, we could choose to user `service` for `status` and `/etc/init.d/` for start or stop!
    Management        int `json:"management,omitempty"`
    ManagementStart   int `json:"management-start,omitempty"`
    ManagementStatus  int `json:"management-status,omitempty"`
    ManagementStop    int `json:"management-stop,omitempty"`
    ManagementRestart int `json:"management-restart,omitempty"`
    // Optionally we may override our service parameters.
    // For example, instead of `restart` we may choose to use `force-reload`
    ManagementStartParameter   string `json:"management-start-parameter,omitempty"`
    ManagementStatusParameter  string `json:"management-status-parameter,omitempty"`
    ManagementStopParameter    string `json:"management-stop-parameter,omitempty"`
    ManagementRestartParameter string `json:"management-restart-parameter,omitempty"`
    // Name is used as our Display Name in our HTTP GUI.
    // Name can contain any characters but must be less than 255 bytes in length.
    Name string `json:"name,omitempty"`
    // Service is the parameter of our service.
    // This is the equivalent of Binary
    Service string `json:"service,omitempty"`
    // These are a list of valid exit codes to ignore when returned from Start/Status/Stop/Restart
    // By Default 0 is always ignored, it is assumed to mean that the command was successful!
    IgnoreExitCodesStart   []uint8 `json:"ignore-exit-codes-start,omitempty"`
    IgnoreExitCodesStatus  []uint8 `json:"ignore-exit-codes-status,omitempty"`
    IgnoreExitCodesStop    []uint8 `json:"ignore-exit-codes-stop,omitempty"`
    IgnoreExitCodesRestart []uint8 `json:"ignore-exit-codes-restart,omitempty"`
    // If Disabled is true our Service won't be executed until enabled.
    // The only way to enable an Service once Patrol is started is to use the API or restart Patrol
    // If we are Disabled and we discover an Service that is running, we will signal it to stop.
    Disabled bool `json:"disabled,omitempty"`
    // KeyValue - prexisting values to populate objects with on init
    KeyValue map[string]interface{} `json:"keyvalue,omitempty"`
    // KeyValueClear if true will cause our Service KeyValue to be cleared once a new instance of our Service is started.
    KeyValueClear bool `json:"keyvalue-clear,omitempty"`
    // If Secret is set, we will require a secret to be passed when pinging and modifying the state of our Service from our HTTP and UDP API.
    // We are not going to throttle comparing our secret. Choose a secret with enough bits of uniqueness and don't make your Patrol instance public!
    // If you are worried about your secret being public, use TLS and HTTP, DO NOT USE UDP!!!
    Secret string `json:"secret,omitempty"`
    // Triggers are only available when you extend Patrol as a library
    // These values will NOT be able to be set from `config.json` - They must be set manually
    //
    // TriggerStart is called from tick in runServices() before we attempt to execute an Service.
    TriggerStart func(
        service *Service,
    )   `json:"-"`
    // TriggerStarted is called from tick in runServices() and isServiceRunning()
    // This is called after we either execute a new Service or we discover a newly running Service.
    TriggerStarted func(
        service *Service,
    )   `json:"-"`
    // TriggerStartFailed is called from tick in runServices() when we fail to execute a new Service.
    TriggerStartFailed func(
        service *Service,
    )   `json:"-"`
    // TriggerRunning is called from tick() when we discover an Service is running.
    TriggerRunning func(
        service *Service,
    )   `json:"-"`
    // TriggerDisabled is called from tick() when we discover an Service that is disabled.
    TriggerDisabled func(
        service *Service,
    )   `json:"-"`
    // TriggerPinged is from Service.apiRequest() when we discover an Service is running from a Ping request.
    TriggerClosed func(
        service *Service,
        history *History,
    )   `json:"-"`
    // TriggerShutdown is called when we call Patrol.Shutdown()
    // This will only be called ONCE
    // This is called regardless if our Service is running or disabled!
    TriggerShutdown func(
        service *Service,
    )   `json:"-"`
    // Extra Unstructured Data
    X   json.RawMessage `json:"x,omitempty"`
}

func (*ConfigService) Clone Uses

func (self *ConfigService) Clone() *ConfigService

func (*ConfigService) GetManagementRestart Uses

func (self *ConfigService) GetManagementRestart() int

func (*ConfigService) GetManagementRestartParameter Uses

func (self *ConfigService) GetManagementRestartParameter() string

func (*ConfigService) GetManagementStart Uses

func (self *ConfigService) GetManagementStart() int

func (*ConfigService) GetManagementStartParameter Uses

func (self *ConfigService) GetManagementStartParameter() string

func (*ConfigService) GetManagementStatus Uses

func (self *ConfigService) GetManagementStatus() int

func (*ConfigService) GetManagementStatusParameter Uses

func (self *ConfigService) GetManagementStatusParameter() string

func (*ConfigService) GetManagementStop Uses

func (self *ConfigService) GetManagementStop() int

func (*ConfigService) GetManagementStopParameter Uses

func (self *ConfigService) GetManagementStopParameter() string

func (*ConfigService) IsValid Uses

func (self *ConfigService) IsValid() bool

func (*ConfigService) Validate Uses

func (self *ConfigService) Validate() error

type ConfigUDP Uses

type ConfigUDP struct {
    Listen string `json:"listen,omitempty"`
    // Extra Unstructured Data
    X   json.RawMessage `json:"x,omitempty"`
}

func (*ConfigUDP) Clone Uses

func (self *ConfigUDP) Clone() *ConfigUDP

func (*ConfigUDP) IsValid Uses

func (self *ConfigUDP) IsValid() bool

type History Uses

type History struct {
    InstanceID string                 `json:"instance-id,omitempty"`
    PID        uint32                 `json:"pid,omitempty"`
    Started    *Timestamp             `json:"started,omitempty"`
    LastSeen   *Timestamp             `json:"lastseen,omitempty"`
    Stopped    *Timestamp             `json:"stopped,omitempty"`
    Disabled   bool                   `json:"disabled,omitempty"`
    Restart    bool                   `json:"restart,omitempty"`
    RunOnce    bool                   `json:"run-once,omitempty"`
    Shutdown   bool                   `json:"shutdown,omitempty"`
    ExitCode   uint8                  `json:"exit-code,omitempty"`
    KeyValue   map[string]interface{} `json:"keyvalue,omitempty"`
}

func (*History) IsValid Uses

func (self *History) IsValid() bool

type Patrol Uses

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

func CreatePatrol Uses

func CreatePatrol(
    config *Config,
) (
    *Patrol,
    error,
)

func (*Patrol) API Uses

func (self *Patrol) API(
    request *API_Request,
) *API_Response

func (*Patrol) GetApp Uses

func (self *Patrol) GetApp(
    key string,
) *App

func (*Patrol) GetApps Uses

func (self *Patrol) GetApps() map[string]*App

func (*Patrol) GetConfig Uses

func (self *Patrol) GetConfig() *Config

func (*Patrol) GetInstanceID Uses

func (self *Patrol) GetInstanceID() string

func (*Patrol) GetService Uses

func (self *Patrol) GetService(
    key string,
) *Service

func (*Patrol) GetServices Uses

func (self *Patrol) GetServices() map[string]*Service

func (*Patrol) GetStarted Uses

func (self *Patrol) GetStarted() time.Time

func (*Patrol) GetStatus Uses

func (self *Patrol) GetStatus() *API_Status

func (*Patrol) HandleUDPConnection Uses

func (self *Patrol) HandleUDPConnection(
    conn net.PacketConn,
) error

func (*Patrol) IsRunning Uses

func (self *Patrol) IsRunning() bool

func (*Patrol) IsShutdown Uses

func (self *Patrol) IsShutdown() bool

func (*Patrol) IsValid Uses

func (self *Patrol) IsValid() bool

func (*Patrol) NewAPIHistory Uses

func (self *Patrol) NewAPIHistory() *History

func (*Patrol) NewAPIResponse Uses

func (self *Patrol) NewAPIResponse() *API_Response

use this when our response needs a reference to patrol for custom timestamp unmarshaling

func (*Patrol) NewAPITimestamp Uses

func (self *Patrol) NewAPITimestamp() *Timestamp

func (*Patrol) ServeHTTPAPI Uses

func (self *Patrol) ServeHTTPAPI(
    w http.ResponseWriter,
    r *http.Request,
)

func (*Patrol) ServeHTTPStatus Uses

func (self *Patrol) ServeHTTPStatus(
    w http.ResponseWriter,
    r *http.Request,
)

func (*Patrol) Shutdown Uses

func (self *Patrol) Shutdown()

func (*Patrol) Start Uses

func (self *Patrol) Start() error

func (*Patrol) Stop Uses

func (self *Patrol) Stop() error

type Service Uses

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

func (*Service) Disable Uses

func (self *Service) Disable()

func (*Service) DisableRunOnce Uses

func (self *Service) DisableRunOnce()

func (*Service) Enable Uses

func (self *Service) Enable()

func (*Service) EnableRunOnce Uses

func (self *Service) EnableRunOnce()

func (*Service) GetCAS Uses

func (self *Service) GetCAS() uint64

func (*Service) GetConfig Uses

func (self *Service) GetConfig() *ConfigService

func (*Service) GetHistory Uses

func (self *Service) GetHistory() []*History

func (*Service) GetID Uses

func (self *Service) GetID() string

func (*Service) GetInstanceID Uses

func (self *Service) GetInstanceID() string

func (*Service) GetKeyValue Uses

func (self *Service) GetKeyValue() map[string]interface{}

func (*Service) GetLastSeen Uses

func (self *Service) GetLastSeen() time.Time

func (*Service) GetPatrol Uses

func (self *Service) GetPatrol() *Patrol

func (*Service) GetStarted Uses

func (self *Service) GetStarted() time.Time

func (*Service) IsDisabled Uses

func (self *Service) IsDisabled() bool

func (*Service) IsRestart Uses

func (self *Service) IsRestart() bool

func (*Service) IsRunOnce Uses

func (self *Service) IsRunOnce() bool

func (*Service) IsRunOnceConsumed Uses

func (self *Service) IsRunOnceConsumed() bool

func (*Service) IsRunning Uses

func (self *Service) IsRunning() bool

func (*Service) IsValid Uses

func (self *Service) IsValid() bool

func (*Service) ReplaceKeyValue Uses

func (self *Service) ReplaceKeyValue(
    kv map[string]interface{},
)

func (*Service) Restart Uses

func (self *Service) Restart()

func (*Service) SetKeyValue Uses

func (self *Service) SetKeyValue(
    kv map[string]interface{},
)

func (*Service) Snapshot Uses

func (self *Service) Snapshot() *API_Response

func (*Service) Toggle Uses

func (self *Service) Toggle(
    toggle uint8,
)

type Timestamp Uses

type Timestamp struct {
    time.Time
    TimestampFormat string
}

func (Timestamp) MarshalJSON Uses

func (self Timestamp) MarshalJSON() ([]byte, error)

func (Timestamp) String Uses

func (self Timestamp) String() string

func (*Timestamp) UnmarshalJSON Uses

func (self *Timestamp) UnmarshalJSON(
    data []byte,
) error

Directories

PathSynopsis
cas
http

Package patrol imports 20 packages (graph) and is imported by 3 packages. Updated 2018-09-25. Refresh now. Tools for package owners.