Merge branch 'dev' into gotify-notify

pull/730/head
Hunter Long 2020-07-09 15:56:55 -07:00 committed by GitHub
commit 2f8fd9197d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 173 additions and 140 deletions

View File

@ -310,25 +310,16 @@ jobs:
run: echo ::set-env name=VERSION::$(cat version.txt)
shell: bash
- name: Base Docker Image
uses: elgohr/Publish-Docker-Github-Action@master
with:
name: statping/statping
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
dockerfile: Dockerfile.base
tags: "base"
- name: Set up Docker Buildx
uses: crazy-max/ghaction-docker-buildx@v3
- name: Dev Docker Image
uses: elgohr/Publish-Docker-Github-Action@master
- name: Docker Login
env:
VERSION: ${{ env.VERSION }}
ARCH: amd64
DOCKER_CLI_EXPERIMENTAL: enabled
with:
name: statping/statping
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
dockerfile: Dockerfile
tags: "dev"
buildargs: VERSION,ARCH
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
run: echo "${DOCKER_PASSWORD}" | docker login --username "${DOCKER_USERNAME}" --password-stdin
- name: Docker Buildx (push)
run: |
docker buildx create --use
docker buildx build --tag=statping/statping:dev --build-arg=VERSION=${VERSION} --platform=linux/amd64,linux/386,linux/arm64,linux/arm/v7,darwin/amd64 --output type=image,name=docker.io/statping/statping,push=true .

View File

@ -412,28 +412,19 @@ jobs:
run: echo ::set-env name=VERSION::$(cat version.txt)
shell: bash
- name: Base Docker Image
uses: elgohr/Publish-Docker-Github-Action@master
with:
name: statping/statping
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
dockerfile: Dockerfile.base
tags: "base"
- name: Set up Docker Buildx
uses: crazy-max/ghaction-docker-buildx@v3
- name: Latest/Version Docker Image
uses: elgohr/Publish-Docker-Github-Action@master
- name: Docker Login
env:
VERSION: ${{ env.VERSION }}
ARCH: amd64
DOCKER_CLI_EXPERIMENTAL: enabled
with:
name: statping/statping
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
dockerfile: Dockerfile
tags: "latest,v${{ env.VERSION }}"
buildargs: VERSION,ARCH
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
run: echo "${DOCKER_PASSWORD}" | docker login --username "${DOCKER_USERNAME}" --password-stdin
- name: Docker Buildx (push)
run: |
docker buildx create --use
docker buildx build --tag=statping/statping,statping/statping:v${VERSION} --build-arg=VERSION=${VERSION} --platform=linux/amd64,linux/386,linux/arm64,linux/arm/v7,darwin/amd64 --output type=image,name=docker.io/statping/statping,push=true .
sentry-release:
needs: upload-release

View File

@ -1,3 +1,8 @@
# 0.90.58 (07-09-2020)
- Fixed ICMP latency/ping durations
- Fixed webhook notifier
- Modified file structure for Vue admin dashboard components.
# 0.90.57 (07-04-2020)
- Fixed login issue

View File

@ -331,5 +331,9 @@ certs:
-keyout key.pem \
-subj "/C=US/ST=California/L=Santa Monica/O=Statping/OU=Development/CN=localhost"
.PHONY: all build build-all build-alpine test-all test test-api docker frontend up down print_details lite sentry-release snapcraft build-linux build-mac build-win build-all postman
buildx:
docker buildx create --use
docker buildx build --tag=statping/statping:dev --build-arg=VERSION=${VERSION} --platform=linux/amd64,linux/386,linux/arm64,linux/arm/v7 --output type=image,name=docker.io/statping/statping,push=true .
.PHONY: all build build-all buildx build-alpine test-all test test-api docker frontend up down print_details lite sentry-release snapcraft build-linux build-mac build-win build-all postman
.SILENT: travis_s3_creds

View File

@ -153,8 +153,10 @@ func onceCli() error {
func importCli(args []string) error {
var err error
var data []byte
filename := args[1]
if data, err = ioutil.ReadFile(filename); err != nil {
if len(args) < 1 {
return errors.New("invalid command arguments")
}
if data, err = ioutil.ReadFile(args[0]); err != nil {
return err
}
var exportData ExportData
@ -162,11 +164,40 @@ func importCli(args []string) error {
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))
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.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 User: %s\n", exportData.Config.DbUser)
log.Printf("Database Password: %s\n", exportData.Config.DbPass)
log.Printf("Database Host: %s\n", exportData.Config.DbHost)
log.Printf("Database Port: %d\n", exportData.Config.DbPort)
if err := exportData.Config.Save(utils.Directory); err != nil {
return err
}
}
}
config, err := configs.LoadConfigs(configFile)
if err != nil {
@ -175,8 +206,10 @@ func importCli(args []string) error {
if err = configs.ConnectConfigs(config, false); err != nil {
return err
}
if data, err = ExportSettings(); err != nil {
return fmt.Errorf("could not export settings: %v", err.Error())
if ask("Create database rows and sample data?") {
if err := config.ResetCore(); err != nil {
return err
}
}
if ask("Import Core settings?") {
@ -221,7 +254,7 @@ func importCli(args []string) error {
if ask(fmt.Sprintf("Import User '%s'?", s.Username)) {
s.Id = 0
if err := s.Create(); err != nil {
return err
log.Errorln(err)
}
}
}
@ -376,6 +409,7 @@ type gitUploader struct {
// 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"`
@ -403,7 +437,14 @@ func ExportSettings() ([]byte, error) {
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(),

View File

@ -96,39 +96,8 @@ func start() {
exit(err)
}
if !confgs.Db.HasTable("core") {
var srvs int64
if confgs.Db.HasTable(&services.Service{}) {
confgs.Db.Model(&services.Service{}).Count(&srvs)
if srvs > 0 {
exit(errors.Wrap(err, "there are already services setup."))
return
}
}
if err := confgs.DropDatabase(); err != nil {
exit(errors.Wrap(err, "error dropping database"))
}
if err := confgs.CreateDatabase(); err != nil {
exit(errors.Wrap(err, "error creating database"))
}
if err := configs.CreateAdminUser(confgs); err != nil {
exit(errors.Wrap(err, "error creating default admin user"))
}
if utils.Params.GetBool("SAMPLE_DATA") {
log.Infoln("Adding Sample Data")
if err := configs.TriggerSamples(); err != nil {
exit(errors.Wrap(err, "error adding sample data"))
}
} else {
if err := core.Samples(); err != nil {
exit(errors.Wrap(err, "error added core details"))
}
}
if err = confgs.ResetCore(); err != nil {
exit(err)
}
if err = confgs.DatabaseChanges(); err != nil {

View File

@ -23,7 +23,7 @@
</template>
<script>
const ServiceInfo = () => import('@/components/Service/ServiceInfo')
const ServiceInfo = () => import('@/components/Dashboard/ServiceInfo')
export default {
name: 'DashboardIndex',

View File

@ -17,7 +17,7 @@
<div v-if="false" class="row mb-4 align-content-center">
<div v-if="!service.online" class="col-3 text-left">
<span class="text-danger font-5 font-weight-bold"></span>
<span css="text-danger font-5 font-weight-bold"></span>
<span class="font-2 d-block">Current Downtime</span>
</div>
@ -103,7 +103,7 @@
import Checkin from '../../forms/Checkin';
import FormIncident from '../../forms/Incident';
import FormMessage from '../../forms/Message';
import ServiceFailures from './ServiceFailures';
import ServiceFailures from '../Service/ServiceFailures';
import ServiceSparkLine from "./ServiceSparkLine";
import Api from "../../API";

View File

@ -65,7 +65,7 @@
offsetY: 0,
},
x: {
show: false,
show: true,
},
y: {
formatter: (value) => { return value + " %" },

View File

@ -14,7 +14,7 @@
<script>
import MiniSparkLine from './MiniSparkLine';
import ServiceSparkLine from './ServiceSparkLine';
import ServiceSparkLine from '../Dashboard/ServiceSparkLine';
export default {
name: 'Analytics',

View File

@ -10,20 +10,6 @@
<ServiceTopStats :service="service"/>
<div v-if="expanded" class="row">
<Analytics title="Last Failure" :func="stats.total_failures"/>
<Analytics title="Total Failures" :func="stats.total_failures"/>
<Analytics title="Highest Latency" :func="stats.high_latency"/>
<Analytics title="Lowest Latency" :func="stats.lowest_latency"/>
<Analytics title="Total Uptime" :func="stats.high_ping"/>
<Analytics title="Total Downtime" :func="stats.low_ping"/>
<div class="col-12">
<router-link :to="serviceLink(service)" class="btn btn-block btn-outline-success mt-4" :class="{'btn-outline-success': service.online, 'btn-outline-danger': !service.online}">
View More Details
</router-link>
</div>
</div>
</div>
</div>

View File

@ -82,24 +82,27 @@ func (w *webhooker) Select() *notifications.Notification {
func (w *webhooker) sendHttpWebhook(body string) (*http.Response, error) {
utils.Log.Infoln(fmt.Sprintf("sending body: '%v' to %v as a %v request", body, w.Host, w.Var1))
client := new(http.Client)
client.Timeout = time.Duration(10 * time.Second)
buf := bytes.NewBuffer(nil)
if w.Var2 != "" {
buf = bytes.NewBuffer([]byte(body))
}
req, err := http.NewRequest(w.Var1, w.Host, buf)
client.Timeout = 10 * time.Second
req, err := http.NewRequest(w.Var1, w.Host, bytes.NewBufferString(body))
if err != nil {
return nil, err
}
if w.ApiSecret != "" {
splitArray := strings.Split(w.ApiSecret, ",")
for _, a := range splitArray {
split := strings.Split(a, "=")
req.Header.Add(split[0], split[1])
keyVal := strings.SplitN(w.ApiSecret, "=", 2)
if len(keyVal) == 2 {
if keyVal[0] != "" && keyVal[1] != "" {
if strings.ToLower(keyVal[0]) == "host" {
req.Host = strings.TrimSpace(keyVal[1])
} else {
req.Header.Set(keyVal[0], keyVal[1])
}
}
}
}
if w.ApiKey != "" {
req.Header.Add("Content-Type", w.ApiKey)
} else {
req.Header.Add("Content-Type", "application/json")
}
req.Header.Set("User-Agent", "Statping")
req.Header.Set("Statping-Version", utils.Version)

View File

@ -21,18 +21,6 @@ func ConnectConfigs(configs *DbConfig, retry bool) error {
return nil
}
func LoadConfigs(cfgFile string) (*DbConfig, error) {
writeAble, err := utils.DirWritable(utils.Directory)
if err != nil {
return nil, err
}
if !writeAble {
return nil, errors.Errorf("Directory %s is not writable!", utils.Directory)
}
return LoadConfigFile(cfgFile)
}
func findDbFile(configs *DbConfig) (string, error) {
location := utils.Directory + "/" + SqliteFilename
if configs == nil {

View File

@ -1,21 +1,28 @@
package configs
import (
"github.com/statping/statping/types/errors"
"errors"
"github.com/statping/statping/utils"
"gopkg.in/yaml.v2"
"os"
)
func LoadConfigFile(configFile string) (*DbConfig, error) {
func LoadConfigs(cfgFile string) (*DbConfig, error) {
writeAble, err := utils.DirWritable(utils.Directory)
if err != nil {
return nil, err
}
if !writeAble {
return nil, errors.New("Directory %s is not writable: " + utils.Directory)
}
p := utils.Params
log.Infof("Attempting to read config file at: %s", configFile)
p.SetConfigFile(configFile)
log.Infof("Attempting to read config file at: %s", cfgFile)
p.SetConfigFile(cfgFile)
p.SetConfigType("yaml")
p.ReadInConfig()
db := new(DbConfig)
content, err := utils.OpenFile(configFile)
content, err := utils.OpenFile(cfgFile)
if err == nil {
if err := yaml.Unmarshal([]byte(content), &db); err != nil {
return nil, err
@ -74,7 +81,7 @@ func LoadConfigFile(configFile string) (*DbConfig, error) {
Language: p.GetString("LANGUAGE"),
SendReports: p.GetBool("ALLOW_REPORTS"),
}
log.WithFields(utils.ToFields(configs)).Debugln("read config file: " + configFile)
log.WithFields(utils.ToFields(configs)).Debugln("read config file: " + cfgFile)
if configs.DbConn == "" {
return configs, errors.New("Starting in setup mode")

View File

@ -5,6 +5,7 @@ import (
_ "github.com/jinzhu/gorm/dialects/mysql"
_ "github.com/jinzhu/gorm/dialects/postgres"
_ "github.com/mattn/go-sqlite3"
"github.com/pkg/errors"
"github.com/statping/statping/source"
"github.com/statping/statping/types/notifications"
"github.com/statping/statping/utils"
@ -20,6 +21,39 @@ import (
"github.com/statping/statping/types/users"
)
func (d *DbConfig) ResetCore() error {
if d.Db.HasTable("core") {
return nil
}
var srvs int64
if d.Db.HasTable(&services.Service{}) {
d.Db.Model(&services.Service{}).Count(&srvs)
if srvs > 0 {
return errors.New("there are already services setup.")
}
}
if err := d.DropDatabase(); err != nil {
return errors.Wrap(err, "error dropping database")
}
if err := d.CreateDatabase(); err != nil {
return errors.Wrap(err, "error creating database")
}
if err := CreateAdminUser(d); err != nil {
return errors.Wrap(err, "error creating default admin user")
}
if utils.Params.GetBool("SAMPLE_DATA") {
log.Infoln("Adding Sample Data")
if err := TriggerSamples(); err != nil {
return errors.Wrap(err, "error adding sample data")
}
} else {
if err := core.Samples(); err != nil {
return errors.Wrap(err, "error added core details")
}
}
return nil
}
func (d *DbConfig) DatabaseChanges() error {
var cr core.Core
d.Db.Model(&core.Core{}).Find(&cr)

View File

@ -91,14 +91,21 @@ func CheckIcmp(s *Service, record bool) (*Service, error) {
timer := prometheus.NewTimer(metrics.ServiceTimer(s.Name))
defer timer.ObserveDuration()
if err := utils.Ping(s.Domain, s.Timeout); err != nil {
dur, err := utils.Ping(s.Domain, s.Timeout)
if err != nil {
if record {
recordFailure(s, fmt.Sprintf("Could not send ICMP to service %v, %v", s.Domain, err))
}
return s, err
}
s.PingTime = dur
s.Latency = dur
s.LastResponse = ""
s.Online = true
if record {
recordSuccess(s)
}
return s, nil
}

View File

@ -105,7 +105,6 @@ func (t Timestamp) Ago() string {
// Command will run a terminal command with 'sh -c COMMAND' and return stdout and errOut as strings
// in, out, err := Command("sass assets/scss assets/css/base.css")
func Command(name string, args ...string) (string, string, error) {
Log.Info("Running command: " + name + " " + strings.Join(args, " "))
testCmd := exec.Command(name, args...)
var stdout, stderr []byte
var errStdout, errStderr error

View File

@ -6,6 +6,7 @@ import (
"errors"
"os"
"os/exec"
"regexp"
"strconv"
"strings"
"syscall"
@ -36,20 +37,27 @@ func DirWritable(path string) (bool, error) {
return true, nil
}
func Ping(address string, secondsTimeout int) error {
func Ping(address string, secondsTimeout int) (int64, error) {
ping, err := exec.LookPath("ping")
if err != nil {
return err
return 0, err
}
out, _, err := Command(ping, address, "-c", "1", "-W", strconv.Itoa(secondsTimeout))
if err != nil {
return err
return 0, err
}
if strings.Contains(out, "Unknown host") {
return errors.New("unknown host")
return 0, errors.New("unknown host")
}
if strings.Contains(out, "100.0% packet loss") {
return errors.New("destination host unreachable")
return 0, errors.New("destination host unreachable")
}
return nil
r := regexp.MustCompile(`time=(.*) ms`)
strs := r.FindStringSubmatch(out)
if len(strs) < 2 {
return 0, errors.New("could not parse ping duration")
}
f, _ := strconv.ParseFloat(strs[1], 64)
return int64(f * 1000), nil
}

View File

@ -1 +1 @@
0.90.57
0.90.58