package main import ( "bufio" "encoding/json" "fmt" "github.com/pkg/errors" "github.com/statping/statping/handlers" "github.com/statping/statping/source" "github.com/statping/statping/types/configs" "github.com/statping/statping/types/core" "github.com/statping/statping/types/services" "github.com/statping/statping/utils" "io/ioutil" "os" "path/filepath" "strings" "time" ) var ( importAll *bool ) 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 systemctlCli(dir string, uninstall bool, port int64) error { location := "/etc/systemd/system/statping.service" if uninstall { fmt.Println("systemctl stop statping") if _, _, err := utils.Command("systemctl", "stop", "statping"); err != nil { log.Errorln(err) } fmt.Println("systemctl disable statping") if _, _, err := utils.Command("systemctl", "disable", "statping"); err != nil { log.Errorln(err) } fmt.Println("Deleting systemctl: ", location) if err := utils.DeleteFile(location); err != nil { log.Errorln(err) } return nil } if ok := utils.FolderExists(dir); !ok { return errors.New("directory does not exist: " + dir) } binPath, err := os.Executable() if err != nil { return err } config := []byte(`[Unit] Description=Statping Server After=network.target After=systemd-user-sessions.service After=network-online.target [Service] Type=simple Restart=always Environment="STATPING_DIR=` + dir + `" Environment="ALLOW_REPORTS=true" ExecStart=` + binPath + ` --port=` + utils.ToString(port) + ` WorkingDirectory=` + dir + ` [Install] WantedBy=multi-user.target" `) fmt.Println("Saving systemctl service to: ", location) fmt.Printf("Using directory %s for Statping data\n", dir) fmt.Printf("Running on port %d\n", port) fmt.Printf("\n\n%s\n\n", string(config)) if err := utils.SaveFile(location, config); err != nil { return err } fmt.Println("systemctl daemon-reload") if _, _, err := utils.Command("systemctl", "daemon-reload"); err != nil { return err } fmt.Println("systemctl enable statping") if _, _, err := utils.Command("systemctl", "enable", "statping.service"); err != nil { return err } fmt.Println("systemctl start statping") if _, _, err := utils.Command("systemctl", "start", "statping"); err != nil { return err } fmt.Println("Statping was will auto start on reboots") fmt.Println("systemctl service: ", location) return nil } func exportCli(args []string) error { filename := filepath.Join(utils.Directory, time.Now().Format("01-02-2006-1504")+".json") if len(args) == 1 { filename = fmt.Sprintf("%s/%s", utils.Directory, args) } var data *handlers.ExportData if err := utils.InitLogs(); err != nil { return err } if err := source.Assets(); err != nil { return err } config, err := configs.LoadConfigs(configFile) if err != nil { return err } if err = configs.ConnectConfigs(config, false); err != nil { return err } if _, err := services.SelectAllServices(false); err != nil { return err } if data, err = handlers.ExportSettings(); err != nil { return fmt.Errorf("could not export settings: %v", err.Error()) } if err = utils.SaveFile(filename, data.JSON()); 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(); 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") fmt.Printf("Process ID: %d\n", os.Getpid()) fmt.Printf("Running as user id: %d\n", os.Getuid()) fmt.Printf("Running as group id: %d\n", os.Getgid()) fmt.Printf("Statping Directory: %s\n", utils.Directory) 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 if len(args) < 1 { return errors.New("invalid command arguments") } if data, err = ioutil.ReadFile(args[0]); err != nil { return err } var exportData handlers.ExportData if err = json.Unmarshal(data, &exportData); err != nil { return err } log.Printf("=== %s ===\n", exportData.Core.Name) if exportData.Config != nil { log.Printf("Configs: %s\n", exportData.Config.DbConn) if exportData.Config.DbUser != "" { log.Printf(" - Host: %s\n", exportData.Config.DbHost) log.Printf(" - User: %s\n", exportData.Config.DbUser) } } if len(exportData.Services) > 0 { log.Printf("Services: %d\n", len(exportData.Services)) } if len(exportData.Checkins) > 0 { log.Printf("Checkins: %d\n", len(exportData.Checkins)) } if len(exportData.Groups) > 0 { log.Printf("Groups: %d\n", len(exportData.Groups)) } if len(exportData.Messages) > 0 { log.Printf("Messages: %d\n", len(exportData.Messages)) } if len(exportData.Incidents) > 0 { log.Printf("Incidents: %d\n", len(exportData.Incidents)) } if len(exportData.Users) > 0 { log.Printf("Users: %d\n", len(exportData.Users)) } if exportData.Config != nil { if ask("Create config.yml file from Configs?") { log.Printf("Database Host: %s\n", exportData.Config.DbHost) log.Printf("Database Port: %d\n", exportData.Config.DbPort) log.Printf("Database User: %s\n", exportData.Config.DbUser) log.Printf("Database Password: %s\n", exportData.Config.DbPass) if err := exportData.Config.Save(utils.Directory); err != nil { return err } } } config, err := configs.LoadConfigs(configFile) if err != nil { return err } if err = configs.ConnectConfigs(config, false); err != nil { return err } if ask("Create database rows and sample data?") { if err := config.ResetCore(); err != nil { return err } } if ask("Import Core settings?") { c := exportData.Core if err := c.Update(); err != nil { log.Errorln(err) } } for _, s := range exportData.Groups { if ask(fmt.Sprintf("Import Group '%s'?", s.Name)) { s.Id = 0 if err := s.Create(); err != nil { log.Errorln(err) } } } for _, s := range exportData.Services { if ask(fmt.Sprintf("Import Service '%s'?", s.Name)) { s.Id = 0 if err := s.Create(); err != nil { log.Errorln(err) } } } for _, s := range exportData.Checkins { if ask(fmt.Sprintf("Import Checkin '%s'?", s.Name)) { s.Id = 0 if err := s.Create(); err != nil { log.Errorln(err) } } } for _, s := range exportData.Messages { if ask(fmt.Sprintf("Import Message '%s'?", s.Title)) { s.Id = 0 if err := s.Create(); err != nil { log.Errorln(err) } } } for _, s := range exportData.Users { if ask(fmt.Sprintf("Import User '%s'?", s.Username)) { s.Id = 0 if err := s.Create(); err != nil { log.Errorln(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(configFile) if err != nil { return errors.Wrap(err, "config.yml file not found") } err = configs.ConnectConfigs(config, false) 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 } 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, nil) 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 { // Config *configs.DbConfig `json:"config"` // 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 // } // var srvs []services.Service // for _, s := range services.AllInOrder() { // s.Failures = nil // srvs = append(srvs, s) // } // // cfg, err := configs.LoadConfigs(configFile) // if err != nil { // return nil, err // } // // data := ExportData{ // Config: cfg, // Core: c, // Notifiers: core.App.Notifications, // Checkins: checkins.All(), // Users: users.All(), // Services: srvs, // 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() //}