484 lines
16 KiB
Go
484 lines
16 KiB
Go
package main
|
|
|
|
import (
|
|
"bufio"
|
|
"encoding/json"
|
|
"fmt"
|
|
"github.com/pkg/errors"
|
|
"github.com/statping/statping/source"
|
|
"github.com/statping/statping/types/checkins"
|
|
"github.com/statping/statping/types/configs"
|
|
"github.com/statping/statping/types/core"
|
|
"github.com/statping/statping/types/groups"
|
|
"github.com/statping/statping/types/messages"
|
|
"github.com/statping/statping/types/services"
|
|
"github.com/statping/statping/types/users"
|
|
"github.com/statping/statping/utils"
|
|
"io/ioutil"
|
|
"os"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
func assetsCli() error {
|
|
dir := utils.Directory
|
|
if err := utils.InitLogs(); err != nil {
|
|
return err
|
|
}
|
|
if err := source.Assets(); err != nil {
|
|
return err
|
|
}
|
|
if err := source.CreateAllAssets(dir); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func exportCli(args []string) error {
|
|
filename := fmt.Sprintf("%s/statping-%s.json", utils.Directory, time.Now().Format("01-02-2006-1504"))
|
|
if len(args) == 1 {
|
|
filename = fmt.Sprintf("%s/%s", utils.Directory, args)
|
|
}
|
|
var data []byte
|
|
if err := utils.InitLogs(); err != nil {
|
|
return err
|
|
}
|
|
if err := source.Assets(); err != nil {
|
|
return err
|
|
}
|
|
config, err := configs.LoadConfigs()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if err = configs.ConnectConfigs(config); err != nil {
|
|
return err
|
|
}
|
|
if _, err := services.SelectAllServices(false); err != nil {
|
|
return err
|
|
}
|
|
if data, err = ExportSettings(); err != nil {
|
|
return fmt.Errorf("could not export settings: %v", err.Error())
|
|
}
|
|
if err = utils.SaveFile(filename, data); err != nil {
|
|
return fmt.Errorf("could not write file statping-export.json: %v", err.Error())
|
|
}
|
|
log.Infoln("Statping export file saved to ", filename)
|
|
return nil
|
|
}
|
|
|
|
func sassCli() error {
|
|
if err := utils.InitLogs(); err != nil {
|
|
return err
|
|
}
|
|
if err := source.Assets(); err != nil {
|
|
return err
|
|
}
|
|
if err := source.CompileSASS(source.DefaultScss...); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func resetCli() error {
|
|
d := utils.Directory
|
|
fmt.Println("Statping directory: ", d)
|
|
assets := d + "/assets"
|
|
if utils.FolderExists(assets) {
|
|
fmt.Printf("Deleting %s folder.\n", assets)
|
|
if err := utils.DeleteDirectory(assets); err != nil {
|
|
return err
|
|
}
|
|
} else {
|
|
fmt.Printf("Assets folder does not exist %s\n", assets)
|
|
}
|
|
|
|
logDir := d + "/logs"
|
|
if utils.FolderExists(logDir) {
|
|
fmt.Printf("Deleting %s directory.\n", logDir)
|
|
if err := utils.DeleteDirectory(logDir); err != nil {
|
|
return err
|
|
}
|
|
} else {
|
|
fmt.Printf("Logs folder does not exist %s\n", logDir)
|
|
}
|
|
|
|
c := d + "/config.yml"
|
|
if utils.FileExists(c) {
|
|
fmt.Printf("Deleting %s file.\n", c)
|
|
if err := utils.DeleteFile(c); err != nil {
|
|
return err
|
|
}
|
|
} else {
|
|
fmt.Printf("Config file does not exist %s\n", c)
|
|
}
|
|
|
|
dbFile := d + "/statping.db"
|
|
if utils.FileExists(dbFile) {
|
|
fmt.Printf("Backuping up %s file.\n", dbFile)
|
|
if err := utils.RenameDirectory(dbFile, d+"/statping.db.backup"); err != nil {
|
|
return err
|
|
}
|
|
} else {
|
|
fmt.Printf("Statping SQL Database file does not exist %s\n", dbFile)
|
|
}
|
|
|
|
fmt.Println("Statping has been reset")
|
|
return nil
|
|
}
|
|
|
|
func envCli() error {
|
|
fmt.Println("Statping Configuration")
|
|
for k, v := range utils.Params.AllSettings() {
|
|
fmt.Printf("%s=%v\n", strings.ToUpper(k), v)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func onceCli() error {
|
|
if err := utils.InitLogs(); err != nil {
|
|
return err
|
|
}
|
|
if err := source.Assets(); err != nil {
|
|
return err
|
|
}
|
|
log.Infoln("Running 1 time and saving to database...")
|
|
if err := runOnce(); err != nil {
|
|
return err
|
|
}
|
|
//core.CloseDB()
|
|
fmt.Println("Check is complete.")
|
|
return nil
|
|
}
|
|
|
|
func importCli(args []string) error {
|
|
var err error
|
|
var data []byte
|
|
filename := args[1]
|
|
if data, err = ioutil.ReadFile(filename); err != nil {
|
|
return err
|
|
}
|
|
var exportData ExportData
|
|
if err = json.Unmarshal(data, &exportData); err != nil {
|
|
return err
|
|
}
|
|
log.Printf("=== %s ===\n", exportData.Core.Name)
|
|
log.Printf("Services: %d\n", len(exportData.Services))
|
|
log.Printf("Checkins: %d\n", len(exportData.Checkins))
|
|
log.Printf("Groups: %d\n", len(exportData.Groups))
|
|
log.Printf("Messages: %d\n", len(exportData.Messages))
|
|
log.Printf("Users: %d\n", len(exportData.Users))
|
|
|
|
config, err := configs.LoadConfigs()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if err = configs.ConnectConfigs(config); err != nil {
|
|
return err
|
|
}
|
|
if data, err = ExportSettings(); err != nil {
|
|
return fmt.Errorf("could not export settings: %v", err.Error())
|
|
}
|
|
|
|
if ask("Import Core settings?") {
|
|
c := exportData.Core
|
|
if err := c.Update(); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
for _, s := range exportData.Groups {
|
|
if ask(fmt.Sprintf("Import Group '%s'?", s.Name)) {
|
|
s.Id = 0
|
|
if err := s.Create(); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
for _, s := range exportData.Services {
|
|
if ask(fmt.Sprintf("Import Service '%s'?", s.Name)) {
|
|
s.Id = 0
|
|
if err := s.Create(); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
for _, s := range exportData.Checkins {
|
|
if ask(fmt.Sprintf("Import Checkin '%s'?", s.Name)) {
|
|
s.Id = 0
|
|
if err := s.Create(); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
for _, s := range exportData.Messages {
|
|
if ask(fmt.Sprintf("Import Message '%s'?", s.Title)) {
|
|
s.Id = 0
|
|
if err := s.Create(); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
for _, s := range exportData.Users {
|
|
if ask(fmt.Sprintf("Import User '%s'?", s.Username)) {
|
|
s.Id = 0
|
|
if err := s.Create(); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
log.Infof("Import complete")
|
|
return nil
|
|
}
|
|
|
|
func ask(format string) bool {
|
|
fmt.Printf(fmt.Sprintf(format + " [y/N]: "))
|
|
reader := bufio.NewReader(os.Stdin)
|
|
text, _ := reader.ReadString('\n')
|
|
text = strings.Replace(text, "\n", "", -1)
|
|
return strings.ToLower(text) == "y"
|
|
}
|
|
|
|
func updateDisplay() error {
|
|
gitCurrent, err := checkGithubUpdates()
|
|
if err != nil {
|
|
return errors.Wrap(err, "Issue connecting to https://github.com/statping/statping")
|
|
}
|
|
if gitCurrent.TagName == "" {
|
|
return nil
|
|
}
|
|
if len(gitCurrent.TagName) < 2 {
|
|
return nil
|
|
}
|
|
if VERSION != gitCurrent.TagName[1:] {
|
|
fmt.Printf("New Update %v Available!\n", gitCurrent.TagName[1:])
|
|
fmt.Printf("Update Command:\n")
|
|
fmt.Printf("curl -o- -L https://statping.com/install.sh | bash\n\n")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// runOnce will initialize the Statping application and check each service 1 time, will not run HTTP server
|
|
func runOnce() error {
|
|
config, err := configs.LoadConfigs()
|
|
if err != nil {
|
|
return errors.Wrap(err, "config.yml file not found")
|
|
}
|
|
err = configs.ConnectConfigs(config)
|
|
if err != nil {
|
|
return errors.Wrap(err, "issue connecting to database")
|
|
}
|
|
c, err := core.Select()
|
|
if err != nil {
|
|
return errors.Wrap(err, "core database was not found or setup")
|
|
}
|
|
|
|
core.App = c
|
|
|
|
_, err = services.SelectAllServices(true)
|
|
if err != nil {
|
|
return errors.Wrap(err, "could not select all services")
|
|
}
|
|
for _, srv := range services.Services() {
|
|
srv.CheckService(true)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// HelpEcho prints out available commands and flags for Statping
|
|
func HelpEcho() {
|
|
fmt.Printf("Statping v%v - Statping.com\n", VERSION)
|
|
fmt.Printf("A simple Application Status Monitor that is opensource and lightweight.\n")
|
|
fmt.Printf("Commands:\n")
|
|
fmt.Println(" statping - Main command to run Statping server")
|
|
fmt.Println(" statping version - Returns the current version of Statping")
|
|
fmt.Println(" statping run - Check all services 1 time and then quit")
|
|
fmt.Println(" statping assets - Dump all assets used locally to be edited.")
|
|
//fmt.Println(" statping static - Creates a static HTML file of the index page")
|
|
fmt.Println(" statping sass - Compile .scss files into the css directory")
|
|
fmt.Println(" statping env - Show all environment variables being used for Statping")
|
|
fmt.Println(" statping update - Attempts to update to the latest version")
|
|
fmt.Println(" statping export - Exports your Statping settings to a 'statping-export.json' file.")
|
|
fmt.Println(" statping import <file> - Imports settings from a previously saved JSON file.")
|
|
fmt.Println(" statping help - Shows the user basic information about Statping")
|
|
fmt.Printf("Flags:\n")
|
|
fmt.Println(" -ip 127.0.0.1 - Run HTTP server on specific IP address (default: localhost)")
|
|
fmt.Println(" -port 8080 - Run HTTP server on Port (default: 8080)")
|
|
fmt.Println(" -verbose 1 - Verbose mode levels 1 - 4 (default: 1)")
|
|
fmt.Println(" -env path/debug.env - Optional .env file to set as environment variables while running server")
|
|
fmt.Printf("Environment Variables:\n")
|
|
fmt.Println(" PORT - Set the outgoing port for the HTTP server (or use -port)")
|
|
fmt.Println(" IP - Bind a specific IP address to the HTTP server (or use -ip)")
|
|
fmt.Println(" VERBOSE - Display more logs in verbose mode. (1 - 4)")
|
|
fmt.Println(" STATPING_DIR - Set a absolute path for the root path of Statping server (logs, assets, SQL db)")
|
|
fmt.Println(" DB_CONN - Automatic Database connection (sqlite, postgres, mysql)")
|
|
fmt.Println(" DB_HOST - Database hostname or IP address")
|
|
fmt.Println(" DB_USER - Database username")
|
|
fmt.Println(" DB_PASS - Database password")
|
|
fmt.Println(" DB_PORT - Database port (5432, 3306, ...)")
|
|
fmt.Println(" DB_DATABASE - Database connection's database name")
|
|
fmt.Println(" POSTGRES_SSLMODE - Enable Postgres SSL Mode 'ssl_mode=VALUE' (enable/disable/verify-full/verify-ca)")
|
|
fmt.Println(" DISABLE_LOGS - Disable viewing and writing to the log file (default is false)")
|
|
fmt.Println(" GO_ENV - Run Statping in testmode, will bypass HTTP authentication (if set as 'test')")
|
|
fmt.Println(" NAME - Set a name for the Statping status page")
|
|
fmt.Println(" DESCRIPTION - Set a description for the Statping status page")
|
|
fmt.Println(" DOMAIN - Set a URL for the Statping status page")
|
|
fmt.Println(" ADMIN_USER - Username for administrator account (default: admin)")
|
|
fmt.Println(" ADMIN_PASS - Password for administrator account (default: admin)")
|
|
fmt.Println(" SASS - Set the absolute path to the sass binary location")
|
|
fmt.Println(" USE_ASSETS - Automatically use assets from 'assets folder' (true/false)")
|
|
fmt.Println(" HTTP_PROXY - Use a HTTP Proxy for HTTP Requests")
|
|
fmt.Println(" AUTH_USERNAME - HTTP Basic Authentication username")
|
|
fmt.Println(" AUTH_PASSWORD - HTTP Basic Authentication password")
|
|
fmt.Println(" BASE_PATH - Set the base URL prefix (set to 'monitor' if URL is domain.com/monitor)")
|
|
fmt.Println(" PREFIX - A Prefix for each value in Prometheus /metric exporter")
|
|
fmt.Println(" API_KEY - Set a custom API Key for Statping")
|
|
fmt.Println(" API_SECRET - Set a custom API Secret for API Authentication")
|
|
fmt.Println(" MAX_OPEN_CONN - Set Maximum Open Connections for database server (default: 5)")
|
|
fmt.Println(" MAX_IDLE_CONN - Set Maximum Idle Connections for database server")
|
|
fmt.Println(" MAX_LIFE_CONN - Set Maximum Life Connections for database server")
|
|
fmt.Println(" * You can insert environment variables into a '.env' file in root directory.")
|
|
fmt.Println("Give Statping a Star at https://github.com/statping/statping")
|
|
}
|
|
|
|
func checkGithubUpdates() (githubResponse, error) {
|
|
url := "https://api.github.com/repos/statping/statping/releases/latest"
|
|
contents, _, err := utils.HttpRequest(url, "GET", nil, nil, nil, time.Duration(2*time.Second), true)
|
|
if err != nil {
|
|
return githubResponse{}, err
|
|
}
|
|
var gitResp githubResponse
|
|
err = json.Unmarshal(contents, &gitResp)
|
|
return gitResp, err
|
|
}
|
|
|
|
type githubResponse struct {
|
|
URL string `json:"url"`
|
|
AssetsURL string `json:"assets_url"`
|
|
UploadURL string `json:"upload_url"`
|
|
HTMLURL string `json:"html_url"`
|
|
ID int `json:"id"`
|
|
NodeID string `json:"node_id"`
|
|
TagName string `json:"tag_name"`
|
|
TargetCommitish string `json:"target_commitish"`
|
|
Name string `json:"name"`
|
|
Draft bool `json:"draft"`
|
|
Author gitAuthor `json:"author"`
|
|
Prerelease bool `json:"prerelease"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
PublishedAt time.Time `json:"published_at"`
|
|
Assets []gitAssets `json:"assets"`
|
|
TarballURL string `json:"tarball_url"`
|
|
ZipballURL string `json:"zipball_url"`
|
|
Body string `json:"body"`
|
|
}
|
|
|
|
type gitAuthor struct {
|
|
Login string `json:"login"`
|
|
ID int `json:"id"`
|
|
NodeID string `json:"node_id"`
|
|
AvatarURL string `json:"avatar_url"`
|
|
GravatarID string `json:"gravatar_id"`
|
|
URL string `json:"url"`
|
|
HTMLURL string `json:"html_url"`
|
|
FollowersURL string `json:"followers_url"`
|
|
FollowingURL string `json:"following_url"`
|
|
GistsURL string `json:"gists_url"`
|
|
StarredURL string `json:"starred_url"`
|
|
SubscriptionsURL string `json:"subscriptions_url"`
|
|
OrganizationsURL string `json:"organizations_url"`
|
|
ReposURL string `json:"repos_url"`
|
|
EventsURL string `json:"events_url"`
|
|
ReceivedEventsURL string `json:"received_events_url"`
|
|
Type string `json:"type"`
|
|
SiteAdmin bool `json:"site_admin"`
|
|
}
|
|
|
|
type gitAssets struct {
|
|
URL string `json:"url"`
|
|
ID int `json:"id"`
|
|
NodeID string `json:"node_id"`
|
|
Name string `json:"name"`
|
|
Label string `json:"label"`
|
|
Uploader gitUploader `json:"uploader"`
|
|
ContentType string `json:"content_type"`
|
|
State string `json:"state"`
|
|
Size int `json:"size"`
|
|
DownloadCount int `json:"download_count"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
UpdatedAt time.Time `json:"updated_at"`
|
|
BrowserDownloadURL string `json:"browser_download_url"`
|
|
}
|
|
|
|
type gitUploader struct {
|
|
Login string `json:"login"`
|
|
ID int `json:"id"`
|
|
NodeID string `json:"node_id"`
|
|
AvatarURL string `json:"avatar_url"`
|
|
GravatarID string `json:"gravatar_id"`
|
|
URL string `json:"url"`
|
|
HTMLURL string `json:"html_url"`
|
|
FollowersURL string `json:"followers_url"`
|
|
FollowingURL string `json:"following_url"`
|
|
GistsURL string `json:"gists_url"`
|
|
StarredURL string `json:"starred_url"`
|
|
SubscriptionsURL string `json:"subscriptions_url"`
|
|
OrganizationsURL string `json:"organizations_url"`
|
|
ReposURL string `json:"repos_url"`
|
|
EventsURL string `json:"events_url"`
|
|
ReceivedEventsURL string `json:"received_events_url"`
|
|
Type string `json:"type"`
|
|
SiteAdmin bool `json:"site_admin"`
|
|
}
|
|
|
|
// ExportChartsJs renders the charts for the index page
|
|
|
|
type ExportData struct {
|
|
Core *core.Core `json:"core"`
|
|
Services []services.Service `json:"services"`
|
|
Messages []*messages.Message `json:"messages"`
|
|
Checkins []*checkins.Checkin `json:"checkins"`
|
|
Users []*users.User `json:"users"`
|
|
Groups []*groups.Group `json:"groups"`
|
|
Notifiers []core.AllNotifiers `json:"notifiers"`
|
|
}
|
|
|
|
// ExportSettings will export a JSON file containing all of the settings below:
|
|
// - Core
|
|
// - Notifiers
|
|
// - Checkins
|
|
// - Users
|
|
// - Services
|
|
// - Groups
|
|
// - Messages
|
|
func ExportSettings() ([]byte, error) {
|
|
c, err := core.Select()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
data := ExportData{
|
|
Core: c,
|
|
//Notifiers: notifications.All(),
|
|
Checkins: checkins.All(),
|
|
Users: users.All(),
|
|
Services: services.AllInOrder(),
|
|
Groups: groups.All(),
|
|
Messages: messages.All(),
|
|
}
|
|
export, err := json.Marshal(data)
|
|
return export, err
|
|
}
|
|
|
|
// ExportIndexHTML returns the HTML of the index page as a string
|
|
//func ExportIndexHTML() []byte {
|
|
// source.Assets()
|
|
// core.CoreApp.Connect(core.CoreApp., utils.Directory)
|
|
// core.SelectAllServices(false)
|
|
// core.CoreApp.UseCdn = types.NewNullBool(true)
|
|
// for _, srv := range core.Services() {
|
|
// core.CheckService(srv, true)
|
|
// }
|
|
// w := httptest.NewRecorder()
|
|
// r := httptest.NewRequest("GET", "/", nil)
|
|
// handlers.ExecuteResponse(w, r, "index.gohtml", nil, nil)
|
|
// return w.Body.Bytes()
|
|
//}
|