go routines - bug fixes - added plugin test tool

pull/10/head v0.29.3
Hunter Long 2018-07-04 12:14:28 -07:00
parent ab2832d0a3
commit b920ba56c3
15 changed files with 163 additions and 32 deletions

View File

@ -18,7 +18,7 @@ services:
env:
global:
- VERSION=0.29.2
- VERSION=0.29.3
- DB_HOST=localhost
- DB_USER=travis
- DB_PASS=

View File

@ -1,6 +1,6 @@
FROM alpine:latest
ENV VERSION=v0.29.2
ENV VERSION=v0.29.3
RUN apk --no-cache add libstdc++ ca-certificates
RUN wget -q https://github.com/hunterlong/statup/releases/download/$VERSION/statup-linux-alpine.tar.gz && \

88
cli.go
View File

@ -3,8 +3,12 @@ package main
import (
"fmt"
"github.com/hunterlong/statup/core"
"github.com/hunterlong/statup/plugin"
"github.com/hunterlong/statup/utils"
"github.com/joho/godotenv"
"strings"
"time"
"upper.io/db.v3/sqlite"
)
func CatchCLI(args []string) {
@ -18,6 +22,12 @@ func CatchCLI(args []string) {
core.CompileSASS()
case "api":
HelpEcho()
case "test":
cmd := args[2]
switch cmd {
case "plugins":
LoadPlugins(true)
}
case "export":
var err error
fmt.Printf("Statup v%v Exporting Static 'index.html' page...\n", VERSION)
@ -86,6 +96,7 @@ func HelpEcho() {
fmt.Println(" statup - Main command to run Statup server")
fmt.Println(" statup version - Returns the current version of Statup")
fmt.Println(" statup run - Check all service 1 time and then quit")
fmt.Println(" statup test plugins - Test all plugins for required information")
fmt.Println(" statup assets - Export all assets used locally to be edited.")
fmt.Println(" statup env - Show all environment variables being used for Statup")
fmt.Println(" statup export - Exports the index page as a static HTML for pushing")
@ -95,3 +106,80 @@ func HelpEcho() {
fmt.Println(" statup help - Shows the user basic information about Statup")
fmt.Println("Give Statup a Star at https://github.com/hunterlong/statup")
}
func TestPlugin(plug plugin.PluginActions) {
RenderBoxes()
defer utils.DeleteFile("./.plugin_test.db")
core.CoreApp.AllPlugins = []plugin.PluginActions{plug}
info := plug.GetInfo()
utils.Log(1, "=======================================================================")
utils.Log(1, fmt.Sprintf(" Plugin Name: %v", info.Name))
utils.Log(1, fmt.Sprintf(" Plugin Description: %v", info.Description))
utils.Log(1, fmt.Sprintf(" Plugin Routes: %v", len(plug.Routes())))
for k, r := range plug.Routes() {
utils.Log(1, fmt.Sprintf(" - Route %v - (%v) /%v", k+1, r.Method, r.URL))
}
fakeSrv := &core.Service{
Id: 56,
Name: "Test Plugin Service",
Domain: "https://google.com",
}
fakeFailD := core.FailureData{
Issue: "No issue, just testing this plugin.",
}
fakeCore := &core.Core{
Name: "Plugin Test",
Description: "This is a fake Core for testing your plugin",
ApiSecret: "0x0x0x0x0",
ApiKey: "abcdefg12345",
Services: []*core.Service{fakeSrv},
}
fakeUser := &core.User{
Id: 6334,
Username: "Bulbasaur",
Password: "$2a$14$NzT/fLdE3f9iB1Eux2C84O6ZoPhI4NfY0Ke32qllCFo8pMTkUPZzy",
Email: "info@testdomain.com",
Admin: true,
CreatedAt: time.Now(),
}
utils.Log(1, fmt.Sprintf("Creating a SQLite database for testing, will be deleted automatically..."))
sqlFake := sqlite.ConnectionURL{
Database: "./.plugin_test.db",
}
fakeDb, err := sqlite.Open(sqlFake)
if err != nil {
utils.Log(3, err)
}
up, _ := core.SqlBox.String("sqlite_up.sql")
requests := strings.Split(up, ";")
for _, request := range requests {
_, err := fakeDb.Exec(request)
if err != nil {
utils.Log(2, err)
}
}
utils.Log(1, fmt.Sprintf("Finished creating Test SQLite database, sending events."))
utils.Log(1, "======> Sending 'OnLoad(sqlbuilder.Database)'")
core.OnLoad(fakeDb)
utils.Log(1, "======> Sending 'OnSuccess(Service)'")
core.OnSuccess(fakeSrv)
utils.Log(1, "======> Sending 'OnFailure(Service, FailureData)'")
core.OnFailure(fakeSrv, fakeFailD)
utils.Log(1, "======> Sending 'OnSettingsSaved(Core)'")
core.OnSettingsSaved(fakeCore)
utils.Log(1, "======> Sending 'OnNewService(Service)'")
core.OnNewService(fakeSrv)
utils.Log(1, "======> Sending 'OnNewUser(User)'")
core.OnNewUser(fakeUser)
utils.Log(1, "======> Sending 'OnUpdateService(Service)'")
core.OnUpdateService(fakeSrv)
utils.Log(1, "======> Sending 'OnDeletedService(Service)'")
core.OnDeletedService(fakeSrv)
}

View File

@ -21,19 +21,26 @@ func CheckServices() {
for _, v := range CoreApp.Services {
obj := v
//go obj.StartCheckins()
obj.stopRoutine = make(chan struct{})
go obj.CheckQueue()
}
}
func (s *Service) CheckQueue() {
defer s.CheckQueue()
s.Check()
if s.Interval < 1 {
s.Interval = 1
for {
select {
case <-s.stopRoutine:
return
default:
s.Check()
if s.Interval < 1 {
s.Interval = 1
}
msg := fmt.Sprintf("Service: %v | Online: %v | Latency: %0.0fms", s.Name, s.Online, (s.Latency * 1000))
utils.Log(1, msg)
time.Sleep(time.Duration(s.Interval) * time.Second)
}
}
msg := fmt.Sprintf("Service: %v | Online: %v | Latency: %0.0fms", s.Name, s.Online, (s.Latency * 1000))
utils.Log(1, msg)
time.Sleep(time.Duration(s.Interval) * time.Second)
}
func (s *Service) DNSCheck() (float64, error) {

View File

@ -61,6 +61,7 @@ func Create(c *types.Communication) (int64, error) {
return 0, err
}
c.Id = uuid.(int64)
c.Routine = make(chan struct{})
if CoreApp != nil {
CoreApp.Communications = append(CoreApp.Communications, c)
}

View File

@ -1,7 +1,6 @@
package core
import (
"fmt"
"github.com/GeertJohan/go.rice"
"github.com/hunterlong/statup/plugin"
"github.com/hunterlong/statup/types"
@ -67,10 +66,6 @@ func InitApp() {
func (c *Core) Update() (*Core, error) {
res := DbSession.Collection("core").Find().Limit(1)
err := res.Update(c)
CoreApp.Services, err = SelectAllServices()
fmt.Println(CoreApp.Name, CoreApp.Description)
return c, err
}

View File

@ -25,9 +25,12 @@ func OnFailure(s *Service, f FailureData) {
for _, p := range CoreApp.AllPlugins {
p.OnFailure(structs.Map(s))
}
onFailureEmail(s, f)
onFailureSlack(s, f)
if notifications.SlackComm != nil {
onFailureSlack(s, f)
}
if notifications.EmailComm != nil {
onFailureEmail(s, f)
}
}
func onFailureSlack(s *Service, f FailureData) {

View File

@ -32,7 +32,7 @@ type Service struct {
OrderId int64 `json:"order_id"`
Failures []*Failure `json:"failures"`
Checkins []*Checkin `json:"checkins"`
runRoutine bool
stopRoutine chan struct{}
LastResponse string
LastStatusCode int
LastOnline time.Time
@ -212,6 +212,11 @@ func (u *Service) Delete() error {
utils.Log(3, fmt.Sprintf("Failed to delete service %v. %v", u.Name, err))
return err
}
utils.Log(1, fmt.Sprintf("Stopping %v Monitoring...", u.Name))
if u.stopRoutine != nil {
close(u.stopRoutine)
}
utils.Log(1, fmt.Sprintf("Stopped %v Monitoring Service", u.Name))
u.RemoveArray()
OnDeletedService(u)
return err
@ -237,8 +242,9 @@ func (u *Service) Create() (int64, error) {
return 0, err
}
u.Id = uuid.(int64)
u.stopRoutine = make(chan struct{})
CoreApp.Services = append(CoreApp.Services, u)
//go u.CheckQueue()
go u.CheckQueue()
OnNewService(u)
return uuid.(int64), err
}

View File

@ -26,9 +26,9 @@ func RunHTTPServer() {
for _, p := range core.CoreApp.AllPlugins {
info := p.GetInfo()
for _, route := range p.Routes() {
path := fmt.Sprintf("/plugins/%v/%v", info.Name, route.URL)
path := fmt.Sprintf("%v", route.URL)
r.Handle(path, http.HandlerFunc(route.Handler)).Methods(route.Method)
fmt.Printf("Added Route %v for plugin %v\n", path, info.Name)
utils.Log(1, fmt.Sprintf("Added Route %v for plugin %v\n", path, info.Name))
}
}
srv := &http.Server{

View File

@ -11,7 +11,7 @@ type index struct {
}
func IndexHandler(w http.ResponseWriter, r *http.Request) {
if core.CoreApp.Services == nil {
if core.CoreApp == nil {
http.Redirect(w, r, "/setup", http.StatusSeeOther)
return
}

30
main.go
View File

@ -3,6 +3,7 @@ package main
import (
"fmt"
"github.com/GeertJohan/go.rice"
"github.com/fatih/structs"
"github.com/hunterlong/statup/core"
"github.com/hunterlong/statup/handlers"
"github.com/hunterlong/statup/plugin"
@ -68,7 +69,7 @@ func mainProcess() {
core.InitApp()
if !core.SetupMode {
LoadPlugins()
LoadPlugins(false)
handlers.RunHTTPServer()
}
}
@ -81,14 +82,13 @@ func ForEachPlugin() {
}
}
func LoadPlugins() {
func LoadPlugins(debug bool) {
utils.Log(1, fmt.Sprintf("Loading any available Plugins from /plugins directory"))
if _, err := os.Stat("./plugins"); os.IsNotExist(err) {
os.Mkdir("./plugins", os.ModePerm)
}
//ForEachPlugin()
files, err := ioutil.ReadDir("./plugins")
if err != nil {
utils.Log(2, fmt.Sprintf("Plugins directory was not found. Error: %v\n", err))
@ -116,18 +116,30 @@ func LoadPlugins() {
continue
}
if debug {
utils.Log(1, fmt.Sprintf("Plugin '%v' struct:", f.Name()))
utils.Log(1, structs.Map(symPlugin))
}
var plugActions plugin.PluginActions
plugActions, ok := symPlugin.(plugin.PluginActions)
if !ok {
utils.Log(3, fmt.Sprintf("Plugin '%v' could not load correctly, error: %v", f.Name(), err))
if debug {
//fmt.Println(symPlugin.(plugin.PluginActions))
}
continue
}
plugActions.OnLoad(core.DbSession)
core.CoreApp.Plugins = append(core.CoreApp.Plugins, plugActions.GetInfo())
core.CoreApp.AllPlugins = append(core.CoreApp.AllPlugins, plugActions)
if debug {
TestPlugin(plugActions)
} else {
plugActions.OnLoad(core.DbSession)
core.CoreApp.Plugins = append(core.CoreApp.Plugins, plugActions.GetInfo())
core.CoreApp.AllPlugins = append(core.CoreApp.AllPlugins, plugActions)
}
}
if !debug {
utils.Log(1, fmt.Sprintf("Loaded %v Plugins\n", len(core.CoreApp.Plugins)))
}
utils.Log(1, fmt.Sprintf("Loaded %v Plugins\n", len(core.CoreApp.Plugins)))
}

View File

@ -37,6 +37,7 @@ func (p *PluginInfo) Form() string {
type PluginActions interface {
GetInfo() Info
GetForm() string
OnLoad(sqlbuilder.Database)
SetInfo(map[string]interface{}) Info
Routes() []Routing
OnSave(map[string]interface{})
@ -52,7 +53,6 @@ type PluginActions interface {
OnBeforeRequest(map[string]interface{})
OnAfterRequest(map[string]interface{})
OnShutdown()
OnLoad(sqlbuilder.Database)
}
type Routing struct {

View File

@ -41,6 +41,14 @@
<div class="col-12 full-col-12">
{{ if not .Services }}
<div class="alert alert-danger" role="alert">
<h4 class="alert-heading">No Services to Monitor!</h4>
<p>Your Statup Status Page is working correctly, but you don't have any services to monitor. Go to the <b>Dashboard</b> and add a website to begin really using your status page!</p>
<hr>
<p class="mb-0">If this is a bug, please make an issue in the Statup Github Repo. <a href="https://github.com/hunterlong/statup" class="btn btn-sm btn-outline-danger float-right">Statup Github Repo</a></p>
</div>
{{end}}
{{ range .Services }}
<div class="mt-4" id="service_id_{{.Id}}">
<div class="card">

View File

@ -55,6 +55,7 @@ type Communication struct {
Limits int64 `db:"limits" json:"-"`
Removable bool `db:"removable" json:"-"`
CreatedAt time.Time `db:"created_at" json:"created_at"`
Routine chan struct{}
}
type Email struct {

View File

@ -1,6 +1,7 @@
package utils
import (
"os"
"regexp"
"strconv"
"strings"
@ -33,3 +34,12 @@ func UnderScoreString(str string) string {
return newStr
}
func DeleteFile(file string) bool {
err := os.Remove(file)
if err != nil {
Log(3, err)
return false
}
return true
}