mirror of https://github.com/statping/statping
				
				
				
			
							parent
							
								
									ab2832d0a3
								
							
						
					
					
						commit
						b920ba56c3
					
				|  | @ -18,7 +18,7 @@ services: | |||
| 
 | ||||
| env: | ||||
|   global: | ||||
|      - VERSION=0.29.2 | ||||
|      - VERSION=0.29.3 | ||||
|      - DB_HOST=localhost | ||||
|      - DB_USER=travis | ||||
|      - DB_PASS= | ||||
|  |  | |||
|  | @ -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
								
								
								
								
							
							
						
						
									
										88
									
								
								cli.go
								
								
								
								
							|  | @ -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) | ||||
| 
 | ||||
| } | ||||
|  |  | |||
|  | @ -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) { | ||||
|  |  | |||
|  | @ -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) | ||||
| 	} | ||||
|  |  | |||
|  | @ -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 | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -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) { | ||||
|  |  | |||
|  | @ -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 | ||||
| } | ||||
|  |  | |||
|  | @ -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{ | ||||
|  |  | |||
|  | @ -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
								
								
								
								
							
							
						
						
									
										30
									
								
								main.go
								
								
								
								
							|  | @ -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))) | ||||
| } | ||||
|  |  | |||
|  | @ -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 { | ||||
|  |  | |||
|  | @ -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"> | ||||
|  |  | |||
|  | @ -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 { | ||||
|  |  | |||
|  | @ -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 | ||||
| } | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 Hunter Long
						Hunter Long