diff --git a/.travis.yml.equinox b/.travis.yml.equinox deleted file mode 100644 index ad2abef..0000000 --- a/.travis.yml.equinox +++ /dev/null @@ -1,22 +0,0 @@ -language: go -go: -- 1.7 -before_install: -- openssl aes-256-cbc -K $encrypted_6219389dc5b7_key -iv $encrypted_6219389dc5b7_iv - -in equinox.key.enc -out equinox.key -d -before_script: - - go get -v github.com/jteeuwen/go-bindata/... - - go get -v github.com/elazarl/go-bindata-assetfs/... - - go-bindata-assetfs -tags bindata res/... -script: - - go test -v - - go test -v -tags bindata -env: - global: - secure: H5IcPyLA9JBgHZZL8sb/7gFY68284VvOUnsAeZcbgpFupIv8iaGgvql5NVnvwovD/SxFWlZ8z4X2BdQWtgURQ1Tr6oLrsTZWZi4Pr5eKhXyCElgZmSP+z8YuUMYs37/uM/iKH/D7vmJlwpoHGJDFbZ0QC5t/W48gyeC0JuAkY05/mqgGCs0/T+yq7YyCvaogZyJhqY2Xq3y3zlleMxYPMkpLsm48JEPtPGoWV6cbXYZHn1FWYAK9w2yKhw+je6EGiAPxT4W9pTWxAHlmvuByPcN2QS2AvgmTkMeYo8KzwOCWTDBwtWU9mjmKerC5EvSwpvhXq77zstorUUxUBWUiJpZnRg+o86M900WLE6x813niLc4KFUXm6wQP9laLgcDkPkSZ9me/TXDcogGgjFXkw1HFsbq4I41b8YuZmiYCkoHvZI68TfkKqSVZ2jp+j7wBxidFlRZO2BJQC4YsX7SJlFDBgOIcyEPNjiZiCFcIa+USHX9AfUyERoP+FBI9cCtki433fVTXInNDu43+GO8C7Jr+0ULDjPGJSWXXU5/+mApXTsDPwUSZ1RE3VxiO2evxmigajqicH0kJbd70JZNqlTaSBgNbgFTiWU0auKJFsnIdSu8BtJ+Neg8isWJ/j2ItbX4Ci4zSIy9JaN2IY8CuLRGLZbiVe5hKbVVNQMGqxMI= -deploy: - skip_cleanup: true - provider: script - script: ./deploy.sh - on: - branch: master \ No newline at end of file diff --git a/fsm.go b/fsm.go index a0a07b4..4295c39 100644 --- a/fsm.go +++ b/fsm.go @@ -25,6 +25,7 @@ import ( "syscall" "time" + "github.com/codeskyblue/gosuv/pushover" "github.com/codeskyblue/kexec" "github.com/kennygrant/sanitize" "github.com/qiniu/log" @@ -99,14 +100,19 @@ var ( ) type Program struct { - Name string `yaml:"name" json:"name"` - Command string `yaml:"command" json:"command"` - Environ []string `yaml:"environ" json:"environ"` - Dir string `yaml:"directory" json:"directory"` - StartAuto bool `yaml:"start_auto" json:"startAuto"` // change to *bool, which support unexpected - StartRetries int `yaml:"start_retries" json:"startRetries"` - StartSeconds int `yaml:"start_seconds" json:"startSeconds"` - // LogDir string `yaml:"logdir"` + Name string `yaml:"name" json:"name"` + Command string `yaml:"command" json:"command"` + Environ []string `yaml:"environ" json:"environ"` + Dir string `yaml:"directory" json:"directory"` + StartAuto bool `yaml:"start_auto" json:"startAuto"` + StartRetries int `yaml:"start_retries" json:"startRetries"` + StartSeconds int `yaml:"start_seconds" json:"startSeconds"` + Notifications struct { + Pushover struct { + ApiKey string `yaml:"api_key"` + Users []string `yaml:"users"` + } `yaml:"pushover,omitempty"` + } `yaml:"notifications,omitempty" json:"-"` } func (p *Program) Check() error { @@ -122,6 +128,21 @@ func (p *Program) Check() error { return nil } +func (p *Program) RunNotification() { + po := p.Notifications.Pushover + if po.ApiKey != "" && len(po.Users) > 0 { + log.Println("TODO: trigger pushover notification") + for _, user := range po.Users { + pushover.Notify(pushover.Params{ + Token: po.ApiKey, + User: user, + Title: p.Name, + Message: "todo", + }) + } + } +} + type Process struct { *FSM `json:"-"` Program `json:"program"` @@ -247,6 +268,11 @@ func NewProcess(pg Program) *Process { } pr.StateChange = func(_, newStatus FSMState) { pr.Status = string(newStatus) + + // TODO: status need to filter with config, not hard coded. + if newStatus == Fatal { + go pr.Program.RunNotification() + } } if pr.StartSeconds <= 0 { pr.StartSeconds = 3 diff --git a/pushover/pushover.go b/pushover/pushover.go new file mode 100644 index 0000000..5a5493a --- /dev/null +++ b/pushover/pushover.go @@ -0,0 +1,63 @@ +package pushover + +import ( + "encoding/json" + "errors" + "fmt" + "log" + "net/http" + "net/url" + "strings" + "time" +) + +const ( + // API is the Pushover API endpoint. + API = "https://api.pushover.net/1/messages.json" +) + +type apiResponse struct { + Info string `json:"info"` + Status int `json:"status"` + Request string `json:"request"` + Errors []string `json:"errors"` + Token string `json:"token"` +} + +type Params struct { + Token string + User string + Title string + Message string +} + +// Notify sends a push request to the Pushover API. +func Notify(p Params) error { + vals := make(url.Values) + vals.Set("token", p.Token) + vals.Set("user", p.User) + vals.Set("message", p.Message) + vals.Set("title", p.Title) + + log.Println(vals.Encode()) + webClient := &http.Client{Timeout: 30 * time.Second} + resp, err := webClient.PostForm(API, vals) + if err != nil { + return err + } + defer resp.Body.Close() + log.Println("posted") + + var r apiResponse + if err := json.NewDecoder(resp.Body).Decode(&r); err != nil { + return fmt.Errorf("decoding response: %s", err) + } + + if r.Status != 1 { + return errors.New(strings.Join(r.Errors, ": ")) //noti.APIError{Site: "Pushover", Msg: strings.Join(r.Errors, ": ")} + } else if strings.Contains(r.Info, "no active devices") { + return errors.New(r.Info) //noti.APIError{Site: "Pushover", Msg: r.Info} + } + + return nil +}