Documentation ¶
Index ¶
- Constants
- Variables
- func IsAppServiceID(key string) bool
- func IsPathClean(path string) bool
- func OpenFile(path string) (*os.File, error)
- type API_Request
- type API_Response
- type API_Status
- type App
- func (self *App) Disable()
- func (self *App) DisableRunOnce()
- func (self *App) Enable()
- func (self *App) EnableRunOnce()
- func (self *App) GetCAS() uint64
- func (self *App) GetConfig() *ConfigApp
- func (self *App) GetHistory() []*History
- func (self *App) GetID() string
- func (self *App) GetInstanceID() string
- func (self *App) GetKeyValue() map[string]interface{}
- func (self *App) GetLastSeen() time.Time
- func (self *App) GetPID() uint32
- func (self *App) GetPatrol() *Patrol
- func (self *App) GetStarted() time.Time
- func (self *App) GetStartedLog() time.Time
- func (self *App) GetStderrLog() string
- func (self *App) GetStdoutLog() string
- func (self *App) IsDisabled() bool
- func (self *App) IsRestart() bool
- func (self *App) IsRunOnce() bool
- func (self *App) IsRunOnceConsumed() bool
- func (self *App) IsRunning() bool
- func (self *App) IsSTDMerged() bool
- func (self *App) IsValid() bool
- func (self *App) ReplaceKeyValue(kv map[string]interface{})
- func (self *App) Restart()
- func (self *App) SetKeyValue(kv map[string]interface{})
- func (self *App) Snapshot() *API_Response
- func (self *App) Toggle(toggle uint8)
- type Config
- type ConfigApp
- type ConfigHTTP
- type ConfigService
- func (self *ConfigService) Clone() *ConfigService
- func (self *ConfigService) GetManagementRestart() int
- func (self *ConfigService) GetManagementRestartParameter() string
- func (self *ConfigService) GetManagementStart() int
- func (self *ConfigService) GetManagementStartParameter() string
- func (self *ConfigService) GetManagementStatus() int
- func (self *ConfigService) GetManagementStatusParameter() string
- func (self *ConfigService) GetManagementStop() int
- func (self *ConfigService) GetManagementStopParameter() string
- func (self *ConfigService) IsValid() bool
- func (self *ConfigService) Validate() error
- type ConfigUDP
- type History
- type Patrol
- func (self *Patrol) API(request *API_Request) *API_Response
- func (self *Patrol) GetApp(key string) *App
- func (self *Patrol) GetApps() map[string]*App
- func (self *Patrol) GetConfig() *Config
- func (self *Patrol) GetInstanceID() string
- func (self *Patrol) GetService(key string) *Service
- func (self *Patrol) GetServices() map[string]*Service
- func (self *Patrol) GetStarted() time.Time
- func (self *Patrol) GetStatus() *API_Status
- func (self *Patrol) HandleUDPConnection(conn net.PacketConn) error
- func (self *Patrol) IsRunning() bool
- func (self *Patrol) IsShutdown() bool
- func (self *Patrol) IsValid() bool
- func (self *Patrol) NewAPIHistory() *History
- func (self *Patrol) NewAPIResponse() *API_Response
- func (self *Patrol) NewAPITimestamp() *Timestamp
- func (self *Patrol) ServeHTTPAPI(w http.ResponseWriter, r *http.Request)
- func (self *Patrol) ServeHTTPStatus(w http.ResponseWriter, r *http.Request)
- func (self *Patrol) Shutdown()
- func (self *Patrol) Start() error
- func (self *Patrol) Stop() error
- type Service
- func (self *Service) Disable()
- func (self *Service) DisableRunOnce()
- func (self *Service) Enable()
- func (self *Service) EnableRunOnce()
- func (self *Service) GetCAS() uint64
- func (self *Service) GetConfig() *ConfigService
- func (self *Service) GetHistory() []*History
- func (self *Service) GetID() string
- func (self *Service) GetInstanceID() string
- func (self *Service) GetKeyValue() map[string]interface{}
- func (self *Service) GetLastSeen() time.Time
- func (self *Service) GetPatrol() *Patrol
- func (self *Service) GetStarted() time.Time
- func (self *Service) IsDisabled() bool
- func (self *Service) IsRestart() bool
- func (self *Service) IsRunOnce() bool
- func (self *Service) IsRunOnceConsumed() bool
- func (self *Service) IsRunning() bool
- func (self *Service) IsValid() bool
- func (self *Service) ReplaceKeyValue(kv map[string]interface{})
- func (self *Service) Restart()
- func (self *Service) SetKeyValue(kv map[string]interface{})
- func (self *Service) Snapshot() *API_Response
- func (self *Service) Toggle(toggle uint8)
- type Timestamp
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") )
Functions ¶
func IsAppServiceID ¶
func IsPathClean ¶
Types ¶
type API_Request ¶
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 ¶
func (self *API_Request) IsValid() bool
type API_Response ¶
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 ¶
func (self *API_Response) IsValid() bool
func (*API_Response) NewAPIHistory ¶
func (self *API_Response) NewAPIHistory() *History
func (*API_Response) NewAPITimestamp ¶
func (self *API_Response) NewAPITimestamp() *Timestamp
func (*API_Response) UnmarshalJSON ¶
func (self *API_Response) UnmarshalJSON( data []byte, ) error
type API_Status ¶
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 ¶
type App struct {
// contains filtered or unexported fields
}
func (*App) DisableRunOnce ¶
func (self *App) DisableRunOnce()
func (*App) EnableRunOnce ¶
func (self *App) EnableRunOnce()
func (*App) GetHistory ¶
func (*App) GetInstanceID ¶
func (*App) GetKeyValue ¶
func (*App) GetLastSeen ¶
func (*App) GetStarted ¶
func (*App) GetStartedLog ¶
func (*App) GetStderrLog ¶
func (*App) GetStdoutLog ¶
func (*App) IsDisabled ¶
func (*App) IsRunOnceConsumed ¶
func (*App) IsSTDMerged ¶
func (*App) ReplaceKeyValue ¶
func (*App) SetKeyValue ¶
func (*App) Snapshot ¶
func (self *App) Snapshot() *API_Response
type Config ¶
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 ¶
type ConfigApp ¶
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"` }
type ConfigHTTP ¶
type ConfigHTTP struct { Listen string `json:"listen,omitempty"` // Extra Unstructured Data X json.RawMessage `json:"x,omitempty"` }
func (*ConfigHTTP) Clone ¶
func (self *ConfigHTTP) Clone() *ConfigHTTP
func (*ConfigHTTP) IsValid ¶
func (self *ConfigHTTP) IsValid() bool
type ConfigService ¶
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 ¶
func (self *ConfigService) Clone() *ConfigService
func (*ConfigService) GetManagementRestart ¶
func (self *ConfigService) GetManagementRestart() int
func (*ConfigService) GetManagementRestartParameter ¶
func (self *ConfigService) GetManagementRestartParameter() string
func (*ConfigService) GetManagementStart ¶
func (self *ConfigService) GetManagementStart() int
func (*ConfigService) GetManagementStartParameter ¶
func (self *ConfigService) GetManagementStartParameter() string
func (*ConfigService) GetManagementStatus ¶
func (self *ConfigService) GetManagementStatus() int
func (*ConfigService) GetManagementStatusParameter ¶
func (self *ConfigService) GetManagementStatusParameter() string
func (*ConfigService) GetManagementStop ¶
func (self *ConfigService) GetManagementStop() int
func (*ConfigService) GetManagementStopParameter ¶
func (self *ConfigService) GetManagementStopParameter() string
func (*ConfigService) IsValid ¶
func (self *ConfigService) IsValid() bool
func (*ConfigService) Validate ¶
func (self *ConfigService) Validate() error
type ConfigUDP ¶
type ConfigUDP struct { Listen string `json:"listen,omitempty"` // Extra Unstructured Data X json.RawMessage `json:"x,omitempty"` }
type History ¶
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"` }
type Patrol ¶
type Patrol struct {
// contains filtered or unexported fields
}
func CreatePatrol ¶
func (*Patrol) API ¶
func (self *Patrol) API( request *API_Request, ) *API_Response
func (*Patrol) GetInstanceID ¶
func (*Patrol) GetService ¶
func (*Patrol) GetServices ¶
func (*Patrol) GetStarted ¶
func (*Patrol) GetStatus ¶
func (self *Patrol) GetStatus() *API_Status
func (*Patrol) HandleUDPConnection ¶
func (self *Patrol) HandleUDPConnection( conn net.PacketConn, ) error
func (*Patrol) IsShutdown ¶
func (*Patrol) NewAPIHistory ¶
func (*Patrol) NewAPIResponse ¶
func (self *Patrol) NewAPIResponse() *API_Response
use this when our response needs a reference to patrol for custom timestamp unmarshaling
func (*Patrol) NewAPITimestamp ¶
func (*Patrol) ServeHTTPAPI ¶
func (self *Patrol) ServeHTTPAPI( w http.ResponseWriter, r *http.Request, )
func (*Patrol) ServeHTTPStatus ¶
func (self *Patrol) ServeHTTPStatus( w http.ResponseWriter, r *http.Request, )
type Service ¶
type Service struct {
// contains filtered or unexported fields
}
func (*Service) DisableRunOnce ¶
func (self *Service) DisableRunOnce()
func (*Service) EnableRunOnce ¶
func (self *Service) EnableRunOnce()
func (*Service) GetConfig ¶
func (self *Service) GetConfig() *ConfigService
func (*Service) GetHistory ¶
func (*Service) GetInstanceID ¶
func (*Service) GetKeyValue ¶
func (*Service) GetLastSeen ¶
func (*Service) GetStarted ¶
func (*Service) IsDisabled ¶
func (*Service) IsRunOnceConsumed ¶
func (*Service) ReplaceKeyValue ¶
func (*Service) SetKeyValue ¶
func (*Service) Snapshot ¶
func (self *Service) Snapshot() *API_Response