mirror of https://github.com/statping/statping
Merge branch 'master' into announcement
commit
eef5e89045
|
@ -5,7 +5,9 @@ about: If you're having an issue or see an error
|
|||
---
|
||||
|
||||
### Describe the bug
|
||||
Try to explain what issue your'e having in detail. You can copy and paste the issue from the log file in your root directory `/logs/statup.log`.
|
||||
Try to explain what issue your'e having in detail. You can copy and paste the issue from the log file in your root directory `/logs/statping.log`.
|
||||
|
||||
You can set the environment variable `ALLOW_REPORTS` to `true` to allow errors to be sent to our error reporting server.
|
||||
|
||||
### To Reproduce
|
||||
Steps to reproduce the behavior:
|
||||
|
|
|
@ -7,6 +7,8 @@ about: If you're having an issue or see an error
|
|||
### Describe the bug
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
You can set the environment variable `ALLOW_REPORTS` to `true` to allow errors to be sent to our error reporting server.
|
||||
|
||||
### To Reproduce
|
||||
Steps to reproduce the behavior:
|
||||
1. Go to '...'
|
||||
|
|
|
@ -160,8 +160,7 @@ jobs:
|
|||
- name: Postman Tests
|
||||
uses: matt-ball/newman-action@master
|
||||
with:
|
||||
postmanApiKey: ${{ secrets.POSTMAN_API }}
|
||||
collection: 1898229-94807b85-ef65-4370-9144-b1a74e04cb0e
|
||||
environment: ./dev/postman_environment.json
|
||||
collection: ./dev/postman.json
|
||||
environment: ./dev/postman_environment_sqlite.json
|
||||
timeoutRequest: 15000
|
||||
delayRequest: 1000
|
||||
delayRequest: 500
|
||||
|
|
|
@ -101,7 +101,7 @@ jobs:
|
|||
env:
|
||||
VERSION: ${{ env.VERSION }}
|
||||
run: |
|
||||
make build
|
||||
make build certs
|
||||
chmod +x statping
|
||||
mv statping $(go env GOPATH)/bin/
|
||||
|
||||
|
@ -143,7 +143,7 @@ jobs:
|
|||
env:
|
||||
COVERALLS: ${{ secrets.COVERALLS }}
|
||||
|
||||
test-postman:
|
||||
test-postman-sqlite:
|
||||
needs: compile
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
@ -175,17 +175,128 @@ jobs:
|
|||
|
||||
- name: Run Statping
|
||||
run: |
|
||||
API_SECRET=demosecret123 statping --port=8080 > /dev/null &
|
||||
API_SECRET=demosecret123 statping --port=8585 > /dev/null &
|
||||
sleep 3
|
||||
|
||||
- name: Postman Tests
|
||||
- name: Postman SQLite Tests
|
||||
uses: matt-ball/newman-action@master
|
||||
with:
|
||||
postmanApiKey: ${{ secrets.POSTMAN_API }}
|
||||
collection: 1898229-94807b85-ef65-4370-9144-b1a74e04cb0e
|
||||
environment: ./dev/postman_environment.json
|
||||
apiKey: ${{ secrets.POSTMAN_API }}
|
||||
collection: ./dev/postman.json
|
||||
environment: ./dev/postman_env_sqlite.json
|
||||
timeoutRequest: 15000
|
||||
delayRequest: 1000
|
||||
delayRequest: 500
|
||||
|
||||
test-postman-mysql:
|
||||
needs: compile
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
services:
|
||||
mysql:
|
||||
image: mysql:5.7
|
||||
env:
|
||||
MYSQL_ROOT_PASSWORD: password123
|
||||
MYSQL_DATABASE: statping
|
||||
ports:
|
||||
- 3306:3306
|
||||
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: '1.14.2'
|
||||
|
||||
- name: Setting ENV's
|
||||
run: |
|
||||
echo "::add-path::$(go env GOPATH)/bin"
|
||||
echo "::add-path::/opt/hostedtoolcache/node/10.20.1/x64/bin"
|
||||
echo ::set-env name=VERSION::$(cat version.txt)
|
||||
shell: bash
|
||||
|
||||
- name: Download Compiled Frontend (rice-box.go)
|
||||
uses: actions/download-artifact@v1
|
||||
with:
|
||||
name: static-rice-box
|
||||
path: ./source
|
||||
|
||||
- name: Install Statping
|
||||
env:
|
||||
VERSION: ${{ env.VERSION }}
|
||||
run: |
|
||||
make build
|
||||
chmod +x statping
|
||||
mv statping $(go env GOPATH)/bin/
|
||||
|
||||
- name: Run Statping
|
||||
run: |
|
||||
API_SECRET=demosecret123 statping --port=8585 > /dev/null &
|
||||
sleep 3
|
||||
|
||||
- name: Postman MySQL Tests
|
||||
uses: matt-ball/newman-action@master
|
||||
with:
|
||||
apiKey: ${{ secrets.POSTMAN_API }}
|
||||
collection: ./dev/postman.json
|
||||
environment: ./dev/postman_env_mysql.json
|
||||
timeoutRequest: 15000
|
||||
delayRequest: 500
|
||||
|
||||
test-postman-postgres:
|
||||
needs: compile
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:10.8
|
||||
env:
|
||||
POSTGRES_USER: root
|
||||
POSTGRES_PASSWORD: password123
|
||||
POSTGRES_DB: statping
|
||||
ports:
|
||||
- 5432:5432
|
||||
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: '1.14.2'
|
||||
|
||||
- name: Setting ENV's
|
||||
run: |
|
||||
echo "::add-path::$(go env GOPATH)/bin"
|
||||
echo "::add-path::/opt/hostedtoolcache/node/10.20.1/x64/bin"
|
||||
echo ::set-env name=VERSION::$(cat version.txt)
|
||||
shell: bash
|
||||
|
||||
- name: Download Compiled Frontend (rice-box.go)
|
||||
uses: actions/download-artifact@v1
|
||||
with:
|
||||
name: static-rice-box
|
||||
path: ./source
|
||||
|
||||
- name: Install Statping
|
||||
env:
|
||||
VERSION: ${{ env.VERSION }}
|
||||
run: |
|
||||
make build
|
||||
chmod +x statping
|
||||
mv statping $(go env GOPATH)/bin/
|
||||
|
||||
- name: Run Statping
|
||||
run: |
|
||||
API_SECRET=demosecret123 statping --port=8585 > /dev/null &
|
||||
sleep 3
|
||||
|
||||
- name: Postman Postgres Tests
|
||||
uses: matt-ball/newman-action@master
|
||||
with:
|
||||
apiKey: ${{ secrets.POSTMAN_API }}
|
||||
collection: ./dev/postman.json
|
||||
environment: ./dev/postman_env_postgres.json
|
||||
timeoutRequest: 15000
|
||||
delayRequest: 500
|
||||
|
||||
build-binaries:
|
||||
needs: compile
|
||||
|
@ -250,7 +361,7 @@ jobs:
|
|||
path: ./build
|
||||
|
||||
upload-release:
|
||||
needs: [test, test-postman, build-binaries]
|
||||
needs: [test, test-postman-sqlite, test-postman-mysql, test-postman-postgres, build-binaries]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
|
|
@ -8,11 +8,11 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Stale Issues
|
||||
uses: actions/stale@v1.1.0
|
||||
uses: actions/stale@v3
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
stale-issue-message: "This issue hasn't had any updates in a while. If this is still a problem, please create a new issue."
|
||||
stale-issue-label: "stale"
|
||||
days-before-stale: 30
|
||||
days-before-close: 7
|
||||
exempt-issue-labels: "bug,urgent,feature,pinned,locked"
|
||||
exempt-issue-label: "bug,urgent,feature,pinned,locked"
|
||||
|
|
22
CHANGELOG.md
22
CHANGELOG.md
|
@ -1,3 +1,25 @@
|
|||
# 0.90.45 (06-01-2020)
|
||||
- Merged PR [#612](https://github.com/statping/statping/pull/612) for edit/create service issue.
|
||||
|
||||
# 0.90.44 (05-25-2020)
|
||||
- Modified Makefile to include "netgo" tag during golang build
|
||||
|
||||
# 0.90.43 (05-21-2020)
|
||||
- Fixed service TLS checkbox form for edit and create
|
||||
- Modified ICMP ping's to use system's "ping" command (doesn't need root access)
|
||||
|
||||
# 0.90.42 (05-20-2020)
|
||||
- Fixed TCP services that dont use TLS.
|
||||
|
||||
# 0.90.41 (05-20-2020)
|
||||
- Added TLS Client Cert/Key feature for HTTP and TCP/UDP services
|
||||
- Replaced environment variable ADMIN_PASS to ADMIN_PASSWORD.
|
||||
|
||||
# 0.90.40 (05-18-2020)
|
||||
- Fixed issues with MySQL and Postgres taking forever to insert sample data (now run in bulk)
|
||||
- Removed API Authentication for /api/logout route
|
||||
- Modified Core Sample/Upstart row to include NAME, DESCRIPTION, and DOMAIN environment vars (also added default values)
|
||||
|
||||
# 0.90.39 (05-15-2020)
|
||||
- Modified some SCSS designs for services failures in group
|
||||
- Fixed Twilio notifier and tests
|
||||
|
|
|
@ -9,6 +9,7 @@ COPY --from=base /usr/local/bin/sass /usr/local/bin/
|
|||
COPY --from=base /usr/local/share/ca-certificates /usr/local/share/
|
||||
|
||||
WORKDIR /app
|
||||
VOLUME /app
|
||||
|
||||
ENV IS_DOCKER=true
|
||||
ENV SASS=/usr/local/bin/sass
|
||||
|
|
14
Makefile
14
Makefile
|
@ -162,13 +162,13 @@ build-win:
|
|||
go build -a -ldflags "-s -w -extldflags -static -X main.VERSION=${VERSION}" -o releases/statping-windows-386/statping.exe ./cmd
|
||||
|
||||
build-darwin:
|
||||
GO111MODULE="on" GOOS=darwin GOARCH=amd64 go build -a -ldflags "-s -w -X main.VERSION=${VERSION}" -o releases/statping-darwin-amd64/statping --tags "darwin" ./cmd
|
||||
GO111MODULE="on" GOOS=darwin GOARCH=amd64 go build -a -ldflags "-s -w -X main.VERSION=${VERSION}" -o releases/statping-darwin-amd64/statping --tags "netgo darwin" ./cmd
|
||||
|
||||
build-linux:
|
||||
CGO_ENABLED=1 GO111MODULE="on" GOOS=linux GOARCH=amd64 \
|
||||
go build -a -ldflags "-s -w -extldflags -static -X main.VERSION=${VERSION}" -o releases/statping-linux-amd64/statping --tags "linux" ./cmd
|
||||
go build -a -ldflags "-s -w -extldflags -static -X main.VERSION=${VERSION}" -o releases/statping-linux-amd64/statping --tags "netgo linux" ./cmd
|
||||
CGO_ENABLED=1 GO111MODULE="on" GOOS=linux GOARCH=386 \
|
||||
go build -a -ldflags "-s -w -extldflags -static -X main.VERSION=${VERSION}" -o releases/statping-linux-386/statping --tags "linux" ./cmd
|
||||
go build -a -ldflags "-s -w -extldflags -static -X main.VERSION=${VERSION}" -o releases/statping-linux-386/statping --tags "netgo linux" ./cmd
|
||||
|
||||
build-linux-arm:
|
||||
CGO_ENABLED=1 CC=arm-linux-gnueabihf-gcc-6 CXX=arm-linux-gnueabihf-g++-6 GO111MODULE="on" GOOS=linux GOARCH=arm GOARM=7 \
|
||||
|
@ -322,5 +322,13 @@ postman: clean compile
|
|||
newman run -e dev/postman_environment.json dev/postman.json
|
||||
killall statping
|
||||
|
||||
certs:
|
||||
openssl req -newkey rsa:2048 \
|
||||
-new -nodes -x509 \
|
||||
-days 3650 \
|
||||
-out cert.pem \
|
||||
-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
|
||||
.SILENT: travis_s3_creds
|
||||
|
|
|
@ -285,7 +285,7 @@ func runOnce() error {
|
|||
|
||||
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)
|
||||
contents, _, err := utils.HttpRequest(url, "GET", nil, nil, nil, time.Duration(2*time.Second), true, nil)
|
||||
if err != nil {
|
||||
return githubResponse{}, err
|
||||
}
|
||||
|
|
|
@ -114,8 +114,9 @@ func start() {
|
|||
}
|
||||
|
||||
if utils.Params.GetBool("SAMPLE_DATA") {
|
||||
log.Infoln("Adding Sample Data")
|
||||
if err := configs.TriggerSamples(); err != nil {
|
||||
exit(errors.Wrap(err, "error creating database"))
|
||||
exit(errors.Wrap(err, "error adding sample data"))
|
||||
}
|
||||
} else {
|
||||
if err := core.Samples(); err != nil {
|
||||
|
|
|
@ -104,6 +104,23 @@ type Database interface {
|
|||
FormatTime(t time.Time) string
|
||||
ParseTime(t string) (time.Time, error)
|
||||
DbType() string
|
||||
GormDB() *gorm.DB
|
||||
ChunkSize() int
|
||||
}
|
||||
|
||||
func (it *Db) ChunkSize() int {
|
||||
switch it.Database.Dialect().GetName() {
|
||||
case "mysql":
|
||||
return 3000
|
||||
case "postgres":
|
||||
return 3000
|
||||
default:
|
||||
return 100
|
||||
}
|
||||
}
|
||||
|
||||
func (it *Db) GormDB() *gorm.DB {
|
||||
return it.Database
|
||||
}
|
||||
|
||||
func (it *Db) DbType() string {
|
||||
|
|
|
@ -10,7 +10,7 @@ services:
|
|||
POSTGRES_DB: statping
|
||||
POSTGRES_USER: root
|
||||
ports:
|
||||
- "127.0.0.1:5432:5432"
|
||||
- 5432:5432
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U root"]
|
||||
interval: 15s
|
||||
|
@ -27,7 +27,7 @@ services:
|
|||
MYSQL_USER: root
|
||||
MYSQL_PASSWORD: password123
|
||||
ports:
|
||||
- "127.0.0.1:3306:3306"
|
||||
- 3306:3306
|
||||
healthcheck:
|
||||
test: [ "CMD", "mysqladmin" ,"ping", "-h", "localhost" ]
|
||||
timeout: 20s
|
||||
|
|
|
@ -1,73 +1,48 @@
|
|||
version: '2.3'
|
||||
|
||||
|
||||
###############################################
|
||||
# Statping Full Stack
|
||||
#
|
||||
# Statping SQLIte => http://localhost:8080
|
||||
# Statping MySQL => http://localhost:8081
|
||||
# Statping Postgres => http://localhost:8082
|
||||
# Statping MariaDB => http://localhost:8083
|
||||
#
|
||||
# Adminer => http://localhost:8282
|
||||
# Prometheus => http://localhost:7050
|
||||
# Grafana => http://localhost:3000
|
||||
#
|
||||
# MySQL => http://localhost:3306
|
||||
# Postgres => http://localhost:5432
|
||||
# MariaDB => http://localhost:3307
|
||||
#
|
||||
###############################################
|
||||
|
||||
services:
|
||||
|
||||
nginx-proxy:
|
||||
image: jwilder/nginx-proxy
|
||||
ports:
|
||||
- 80:80
|
||||
volumes:
|
||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
||||
networks:
|
||||
- statping
|
||||
|
||||
# statping_dev:
|
||||
# container_name: statping_dev
|
||||
# build:
|
||||
# context: .
|
||||
# dockerfile: ./dev/Dockerfile.dev
|
||||
# args:
|
||||
# VERSION: DEV
|
||||
# COMMIT: DEV
|
||||
# restart: on-failure
|
||||
# volumes:
|
||||
# - ./:/go/src/github.com/statping/statping
|
||||
# environment:
|
||||
# VIRTUAL_HOST: local.statping.com
|
||||
# VIRTUAL_PORT: 8888
|
||||
# GO_ENV: test
|
||||
# DB_CONN: sqlite
|
||||
# API_SECRET: exampleapisecret
|
||||
# NAME: Statping on SQLite
|
||||
# DOMAIN: http://localhost:4000
|
||||
# DESCRIPTION: This is a dev environment on SQLite!
|
||||
# ADMIN_USER: admin
|
||||
# ADMIN_PASS: admin
|
||||
# PORT: 8585
|
||||
# SERVICES: '[{"name": "Local Statping", "type": "http", "domain": "http://localhost:8585", "interval": 30}]'
|
||||
# ports:
|
||||
# - 8888:8888
|
||||
# - 8585:8585
|
||||
# networks:
|
||||
# - statping
|
||||
# healthcheck:
|
||||
# test: ["CMD-SHELL", "curl -f http://localhost:8585/health || false"]
|
||||
# timeout: 2s
|
||||
# interval: 20s
|
||||
# retries: 30
|
||||
|
||||
statping:
|
||||
container_name: statping
|
||||
statping_sqlite:
|
||||
container_name: statping_sqlite
|
||||
build:
|
||||
context: ./
|
||||
context: ../
|
||||
restart: on-failure
|
||||
volumes:
|
||||
- ./docker/statping/sqlite:/app
|
||||
- ./services.yml:/app/services.yml
|
||||
environment:
|
||||
SERVICES: '[{"name": "Local Statping", "type": "http", "domain": "http://localhost:8585", "interval": 30}]'
|
||||
VIRTUAL_HOST: sqlite.dev.statping.com
|
||||
VIRTUAL_PORT: 8080
|
||||
DB_CONN: sqlite
|
||||
API_SECRET: exampleapisecret
|
||||
NAME: Statping on SQLite
|
||||
DOMAIN: http://localhost:4000
|
||||
NAME: Statping
|
||||
DOMAIN: http://localhost:8080
|
||||
DESCRIPTION: This is a dev environment on SQLite!
|
||||
ADMIN_USER: admin
|
||||
ADMIN_PASS: admin
|
||||
ADMIN_PASSWORD: admin
|
||||
SAMPLE_DATA: 'false'
|
||||
ports:
|
||||
- 4000:8080
|
||||
- 8080:8080
|
||||
networks:
|
||||
- statping
|
||||
- database
|
||||
- frontend
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "curl -f http://localhost:8080/health || false"]
|
||||
timeout: 2s
|
||||
|
@ -77,88 +52,124 @@ services:
|
|||
statping_mysql:
|
||||
container_name: statping_mysql
|
||||
build:
|
||||
context: ./
|
||||
context: ../
|
||||
restart: on-failure
|
||||
ports:
|
||||
- 4005:8080
|
||||
volumes:
|
||||
- ./docker/statping/mysql:/app
|
||||
links:
|
||||
- mysql
|
||||
- ./services.yml:/app/services.yml
|
||||
environment:
|
||||
VIRTUAL_HOST: mysql.dev.statping.com
|
||||
VIRTUAL_PORT: 8080
|
||||
DB_CONN: mysql
|
||||
DB_HOST: mysql
|
||||
DB_PORT: 3306
|
||||
DB_DATABASE: statping
|
||||
DB_USER: root
|
||||
DB_PASS: password123
|
||||
DB_DATABASE: statping
|
||||
DB_PORT: 3306
|
||||
API_SECRET: exampleapisecret
|
||||
NAME: Statping on MySQL
|
||||
DOMAIN: http://localhost:4005
|
||||
NAME: Statping MySQL
|
||||
DOMAIN: http://localhost:8081
|
||||
DESCRIPTION: This is a dev environment on MySQL!
|
||||
ADMIN_USER: admin
|
||||
ADMIN_PASS: admin
|
||||
ADMIN_PASSWORD: admin
|
||||
SAMPLE_DATA: 'false'
|
||||
ports:
|
||||
- 8081:8080
|
||||
networks:
|
||||
- statping
|
||||
depends_on:
|
||||
mysql:
|
||||
condition: service_healthy
|
||||
- database
|
||||
- frontend
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "curl -f http://localhost:8080/health || false"]
|
||||
timeout: 2s
|
||||
interval: 10s
|
||||
retries: 20
|
||||
depends_on:
|
||||
mysql:
|
||||
condition: service_healthy
|
||||
|
||||
statping_postgres:
|
||||
container_name: statping_postgres
|
||||
build:
|
||||
context: ./
|
||||
context: ../
|
||||
restart: on-failure
|
||||
ports:
|
||||
- 4010:8080
|
||||
volumes:
|
||||
- ./docker/statping/postgres:/app
|
||||
links:
|
||||
- postgres
|
||||
- ./docker/statping/mysql:/app
|
||||
- ./services.yml:/app/services.yml
|
||||
environment:
|
||||
VIRTUAL_HOST: postgres.dev.statping.com
|
||||
VIRTUAL_PORT: 8080
|
||||
DB_CONN: postgres
|
||||
DB_HOST: postgres
|
||||
DB_PORT: 5432
|
||||
DB_DATABASE: statping
|
||||
DB_USER: root
|
||||
DB_PASS: password123
|
||||
DB_DATABASE: statping
|
||||
DB_PORT: 5432
|
||||
API_SECRET: exampleapisecret
|
||||
NAME: Statping on Postgres
|
||||
DOMAIN: http://localhost:4010
|
||||
NAME: Statping Postgres
|
||||
DOMAIN: http://localhost:8082
|
||||
DESCRIPTION: This is a dev environment on Postgres!
|
||||
ADMIN_USER: admin
|
||||
ADMIN_PASS: admin
|
||||
ADMIN_PASSWORD: admin
|
||||
SAMPLE_DATA: 'false'
|
||||
ports:
|
||||
- 8082:8080
|
||||
networks:
|
||||
- statping
|
||||
- database
|
||||
- frontend
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "curl -f http://localhost:8080/health || false"]
|
||||
timeout: 2s
|
||||
interval: 10s
|
||||
retries: 20
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
|
||||
statping_mariadb:
|
||||
container_name: statping_mariadb
|
||||
build:
|
||||
context: ../
|
||||
restart: on-failure
|
||||
volumes:
|
||||
- ./docker/statping/mariadb:/app
|
||||
- ./services.yml:/app/services.yml
|
||||
environment:
|
||||
DB_CONN: mysql
|
||||
DB_HOST: mariadb
|
||||
DB_USER: root
|
||||
DB_PASS: password123
|
||||
DB_DATABASE: statping
|
||||
DB_PORT: 3306
|
||||
API_SECRET: exampleapisecret
|
||||
NAME: Statping MariaDB
|
||||
DOMAIN: http://localhost:8083
|
||||
DESCRIPTION: This is a dev environment on MariaDB!
|
||||
ADMIN_USER: admin
|
||||
ADMIN_PASSWORD: admin
|
||||
SAMPLE_DATA: 'false'
|
||||
ports:
|
||||
- 8083:8080
|
||||
networks:
|
||||
- database
|
||||
- frontend
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "curl -f http://localhost:8080/health || false"]
|
||||
timeout: 5s
|
||||
interval: 5s
|
||||
retries: 30
|
||||
timeout: 2s
|
||||
interval: 10s
|
||||
retries: 20
|
||||
depends_on:
|
||||
mariadb:
|
||||
condition: service_healthy
|
||||
|
||||
postgres:
|
||||
container_name: postgres
|
||||
image: postgres
|
||||
volumes:
|
||||
- ./docker/databases/postgres:/var/lib/postgresql/data
|
||||
ports:
|
||||
- 5432:5432
|
||||
environment:
|
||||
POSTGRES_PASSWORD: password123
|
||||
POSTGRES_DB: statping
|
||||
POSTGRES_USER: root
|
||||
networks:
|
||||
- statping
|
||||
- database
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U root"]
|
||||
interval: 15s
|
||||
|
@ -175,95 +186,59 @@ services:
|
|||
MYSQL_ROOT_PASSWORD: password123
|
||||
MYSQL_DATABASE: statping
|
||||
MYSQL_USER: root
|
||||
MYSQL_PASSWORD: password
|
||||
MYSQL_PASSWORD: password123
|
||||
ports:
|
||||
- 3306:3306
|
||||
networks:
|
||||
- statping
|
||||
- database
|
||||
healthcheck:
|
||||
test: [ "CMD", "mysqladmin" ,"ping", "-h", "localhost" ]
|
||||
timeout: 20s
|
||||
interval: 15s
|
||||
retries: 30
|
||||
|
||||
phpmyadmin:
|
||||
container_name: phpmyadmin
|
||||
image: phpmyadmin/phpmyadmin
|
||||
restart: on-failure
|
||||
depends_on:
|
||||
mysql:
|
||||
condition: service_healthy
|
||||
ports:
|
||||
- 5050:80
|
||||
links:
|
||||
- mysql:db
|
||||
environment:
|
||||
VIRTUAL_HOST: phpmyadmin.statping.com
|
||||
VIRTUAL_PORT: 80
|
||||
MYSQL_ROOT_PASSWORD: password123
|
||||
PMA_HOST: mysql
|
||||
PMA_USER: root
|
||||
PMA_PASSWORD: password123
|
||||
PMA_PORT: 3306
|
||||
networks:
|
||||
- statping
|
||||
|
||||
sqlite-web:
|
||||
container_name: sqlite-web
|
||||
image: coleifer/sqlite-web
|
||||
restart: on-failure
|
||||
command: sqlite_web -H 0.0.0.0 -r -x /data/statping.db
|
||||
depends_on:
|
||||
statping:
|
||||
condition: service_healthy
|
||||
ports:
|
||||
- 6050:8080
|
||||
links:
|
||||
- statping
|
||||
mariadb:
|
||||
container_name: mariadb
|
||||
image: mariadb
|
||||
volumes:
|
||||
- ./docker/statping/sqlite/statping.db:/data/statping.db:ro
|
||||
- ./docker/databases/mariadb:/var/lib/mysql
|
||||
restart: always
|
||||
environment:
|
||||
VIRTUAL_HOST: sqladmin.statping.com
|
||||
VIRTUAL_PORT: 8080
|
||||
SQLITE_DATABASE: /data/statping.db
|
||||
networks:
|
||||
- statping
|
||||
|
||||
pgadmin4:
|
||||
container_name: pgadmin4
|
||||
image: fenglc/pgadmin4
|
||||
restart: on-failure
|
||||
environment:
|
||||
VIRTUAL_HOST: pgadmin.statping.com
|
||||
VIRTUAL_PORT: 5050
|
||||
DEFAULT_USER: admin@admin.com
|
||||
DEFAULT_PASSWORD: admin
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
MYSQL_ROOT_PASSWORD: password123
|
||||
MYSQL_DATABASE: statping
|
||||
MYSQL_USER: root
|
||||
MYSQL_PASSWORD: password123
|
||||
ports:
|
||||
- 7000:5050
|
||||
links:
|
||||
- postgres:postgres
|
||||
- 3307:3306
|
||||
networks:
|
||||
- statping
|
||||
- database
|
||||
healthcheck:
|
||||
test: [ "CMD", "mysqladmin" ,"ping", "-h", "localhost" ]
|
||||
timeout: 20s
|
||||
interval: 15s
|
||||
retries: 30
|
||||
|
||||
adminer:
|
||||
container_name: adminer
|
||||
image: adminer
|
||||
restart: always
|
||||
networks:
|
||||
- database
|
||||
- frontend
|
||||
ports:
|
||||
- 8282:8080
|
||||
|
||||
prometheus:
|
||||
container_name: prometheus
|
||||
image: prom/prometheus:v2.0.0
|
||||
restart: on-failure
|
||||
volumes:
|
||||
- ./dev/prometheus.yml:/etc/prometheus/prometheus.yml
|
||||
- ./prometheus.yml:/etc/prometheus/prometheus.yml
|
||||
- ./docker/databases/prometheus:/prometheus
|
||||
links:
|
||||
- statping
|
||||
- statping_mysql
|
||||
- statping_postgres
|
||||
ports:
|
||||
- 7050:9090
|
||||
networks:
|
||||
- statping
|
||||
environment:
|
||||
VIRTUAL_HOST: prometheus.statping.com
|
||||
VIRTUAL_PORT: 9090
|
||||
- database
|
||||
healthcheck:
|
||||
test: "/bin/wget -q -Y off http://localhost:9090/status -O /dev/null > /dev/null 2>&1"
|
||||
interval: 10s
|
||||
|
@ -277,25 +252,23 @@ services:
|
|||
- 3000:3000
|
||||
volumes:
|
||||
- ./docker/grafana:/var/lib/grafana
|
||||
- ./dev/grafana/datasource.yml:/etc/grafana/provisioning/datasources/datasource.yml
|
||||
- ./dev/grafana/dashboard.yml:/etc/grafana/provisioning/dashboards/dashboard.yml
|
||||
- ./dev/grafana/statping_dashboard.json:/etc/grafana/provisioning/dashboards/statping_dashboard.json
|
||||
- ./grafana/datasource.yml:/etc/grafana/provisioning/datasources/datasource.yml
|
||||
- ./grafana/dashboard.yml:/etc/grafana/provisioning/dashboards/dashboard.yml
|
||||
- ./grafana/statping_dashboard.json:/etc/grafana/provisioning/dashboards/statping_dashboard.json
|
||||
environment:
|
||||
- VIRTUAL_HOST=grafana.statping.com
|
||||
- VIRTUAL_PORT=3000
|
||||
- GF_USERS_ALLOW_SIGN_UP=false
|
||||
- GF_AUTH_ANONYMOUS_ENABLED=true
|
||||
depends_on:
|
||||
prometheus:
|
||||
condition: service_healthy
|
||||
links:
|
||||
- prometheus
|
||||
networks:
|
||||
- statping
|
||||
- frontend
|
||||
- database
|
||||
healthcheck:
|
||||
test: "/usr/bin/wget -q -Y off http://localhost:3000/api/health -O /dev/null > /dev/null 2>&1"
|
||||
interval: 10s
|
||||
retries: 20
|
||||
|
||||
networks:
|
||||
statping:
|
||||
frontend:
|
||||
database:
|
||||
|
|
|
@ -24,7 +24,7 @@ services:
|
|||
DOMAIN: http://localhost:8585
|
||||
DESCRIPTION: This is a dev environment with auto reloading!
|
||||
ADMIN_USER: admin
|
||||
ADMIN_PASS: admin
|
||||
ADMIN_PASSWORD: admin
|
||||
PORT: 8585
|
||||
ports:
|
||||
- 8888:8888
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
[users]
|
||||
# disable user signup / registration
|
||||
allow_sign_up = false
|
||||
viewers_can_edit = true
|
||||
editors_can_admin = true
|
||||
|
||||
[auth.anonymous]
|
||||
# enable anonymous access
|
||||
enabled = true
|
||||
|
||||
|
|
|
@ -558,24 +558,14 @@
|
|||
"templating": {
|
||||
"list": [
|
||||
{
|
||||
"allValue": null,
|
||||
"current": {},
|
||||
"datasource": "${DS_PROMETHEUS}",
|
||||
"hide": 0,
|
||||
"includeAll": false,
|
||||
"label": "service",
|
||||
"multi": false,
|
||||
"name": "service",
|
||||
"label": "datasource",
|
||||
"name": "DS_PROMETHEUS",
|
||||
"options": [],
|
||||
"query": "label_values(statup_service_latency, name)",
|
||||
"query": "prometheus",
|
||||
"refresh": 1,
|
||||
"regex": "",
|
||||
"sort": 0,
|
||||
"tagValuesQuery": "",
|
||||
"tags": [],
|
||||
"tagsQuery": "",
|
||||
"type": "query",
|
||||
"useTags": false
|
||||
"type": "datasource"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,49 @@
|
|||
{
|
||||
"id": "0ff1dcd6-54f3-44a7-9c18-cc3c8e7df357",
|
||||
"name": "Local Statping",
|
||||
"values": [
|
||||
{
|
||||
"key": "endpoint",
|
||||
"value": "http://0.0.0.0:8585",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"key": "api_key",
|
||||
"value": "demosecret123",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"key": "db_connection",
|
||||
"value": "mysql",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"key": "db_host",
|
||||
"value": "localhost",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"key": "db_user",
|
||||
"value": "root",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"key": "db_password",
|
||||
"value": "password123",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"key": "db_database",
|
||||
"value": "statping",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"key": "db_port",
|
||||
"value": "3306",
|
||||
"enabled": true
|
||||
}
|
||||
],
|
||||
"_postman_variable_scope": "environment",
|
||||
"_postman_exported_at": "2020-05-18T20:44:05.571Z",
|
||||
"_postman_exported_using": "Postman/7.24.0"
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
{
|
||||
"id": "0ff1dcd6-54f3-44a7-9c18-cc3c8e7df357",
|
||||
"name": "Local Statping",
|
||||
"values": [
|
||||
{
|
||||
"key": "endpoint",
|
||||
"value": "http://0.0.0.0:8585",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"key": "api_key",
|
||||
"value": "demosecret123",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"key": "db_connection",
|
||||
"value": "postgres",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"key": "db_host",
|
||||
"value": "localhost",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"key": "db_user",
|
||||
"value": "root",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"key": "db_password",
|
||||
"value": "password123",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"key": "db_database",
|
||||
"value": "statping",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"key": "db_port",
|
||||
"value": "5432",
|
||||
"enabled": true
|
||||
}
|
||||
],
|
||||
"_postman_variable_scope": "environment",
|
||||
"_postman_exported_at": "2020-05-18T20:44:05.571Z",
|
||||
"_postman_exported_using": "Postman/7.24.0"
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
{
|
||||
"id": "0ff1dcd6-54f3-44a7-9c18-cc3c8e7df357",
|
||||
"name": "Local Statping",
|
||||
"values": [
|
||||
{
|
||||
"key": "endpoint",
|
||||
"value": "http://0.0.0.0:8585",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"key": "api_key",
|
||||
"value": "demosecret123",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"key": "db_connection",
|
||||
"value": "sqlite",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"key": "db_host",
|
||||
"value": "localhost",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"key": "db_user",
|
||||
"value": "root",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"key": "db_password",
|
||||
"value": "password123",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"key": "db_database",
|
||||
"value": "statping",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"key": "db_port",
|
||||
"value": "3306",
|
||||
"enabled": true
|
||||
}
|
||||
],
|
||||
"_postman_variable_scope": "environment",
|
||||
"_postman_exported_at": "2020-05-18T20:44:05.571Z",
|
||||
"_postman_exported_using": "Postman/7.24.0"
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
{
|
||||
"id": "0ff1dcd6-54f3-44a7-9c18-cc3c8e7df357",
|
||||
"name": "Local Statping",
|
||||
"values": [
|
||||
{
|
||||
"key": "endpoint",
|
||||
"value": "http://127.0.0.1:8080",
|
||||
"description": "",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"key": "api_key",
|
||||
"value": "demosecret123",
|
||||
"description": "",
|
||||
"enabled": true
|
||||
}
|
||||
],
|
||||
"_postman_variable_scope": "environment",
|
||||
"_postman_exported_at": "2018-11-17T16:55:15.031Z",
|
||||
"_postman_exported_using": "Postman/6.5.2"
|
||||
}
|
|
@ -3,17 +3,11 @@ global:
|
|||
evaluation_interval: 15s
|
||||
|
||||
scrape_configs:
|
||||
- job_name: 'statping_local'
|
||||
scrape_interval: 15s
|
||||
bearer_token: 'samplesecret'
|
||||
static_configs:
|
||||
- targets: ['docker0:8585']
|
||||
|
||||
- job_name: 'statping'
|
||||
- job_name: 'statping_sqlite'
|
||||
scrape_interval: 15s
|
||||
bearer_token: 'exampleapisecret'
|
||||
static_configs:
|
||||
- targets: ['statping:8080']
|
||||
- targets: ['statping_sqlite:8080']
|
||||
|
||||
- job_name: 'statping_mysql'
|
||||
scrape_interval: 15s
|
||||
|
@ -21,14 +15,14 @@ scrape_configs:
|
|||
static_configs:
|
||||
- targets: ['statping_mysql:8080']
|
||||
|
||||
- job_name: 'statping_mariadb'
|
||||
scrape_interval: 15s
|
||||
bearer_token: 'exampleapisecret'
|
||||
static_configs:
|
||||
- targets: ['statping_mariadb:8080']
|
||||
|
||||
- job_name: 'statping_postgres'
|
||||
scrape_interval: 15s
|
||||
bearer_token: 'exampleapisecret'
|
||||
static_configs:
|
||||
- targets: ['statping_postgres:8080']
|
||||
|
||||
- job_name: 'statping_dev'
|
||||
scrape_interval: 15s
|
||||
bearer_token: 'exampleapisecret'
|
||||
static_configs:
|
||||
- targets: ['statping_dev:8585']
|
||||
|
|
|
@ -18,7 +18,7 @@ services:
|
|||
DOMAIN: http://localhost:8080
|
||||
DESCRIPTION: This is a dev environment on SQLite!
|
||||
ADMIN_USER: admin
|
||||
ADMIN_PASS: admin
|
||||
ADMIN_PASSWORD: admin
|
||||
|
||||
postgres:
|
||||
hostname: postgres
|
||||
|
|
|
@ -22,7 +22,12 @@ const webpackConfig = {
|
|||
{
|
||||
test: /\.vue$/,
|
||||
loader: 'vue-loader',
|
||||
include: [ helpers.root('src') ]
|
||||
include: [ helpers.root('src') ],
|
||||
options: {
|
||||
loaders: {
|
||||
i18n: '@kazupon/vue-i18n-loader'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
test: /\.js$/,
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
"vue-cookies": "^1.7.0",
|
||||
"vue-flatpickr-component": "^8.1.5",
|
||||
"vue-github-button": "^1.1.2",
|
||||
"vue-i18n": "^8.18.1",
|
||||
"vue-moment": "^4.1.0",
|
||||
"vue-observe-visibility": "^0.4.6",
|
||||
"vue-router": "~3.0",
|
||||
|
@ -51,6 +52,7 @@
|
|||
"@babel/plugin-syntax-import-meta": "~7.2",
|
||||
"@babel/polyfill": "~7.2",
|
||||
"@babel/preset-env": "^7.9.0",
|
||||
"@kazupon/vue-i18n-loader": "^0.5.0",
|
||||
"@vue/babel-preset-app": "^4.1.2",
|
||||
"@vue/cli-plugin-babel": "^4.1.0",
|
||||
"@vue/cli-service": "^4.2.3",
|
||||
|
|
|
@ -7,14 +7,13 @@
|
|||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0">
|
||||
<meta name="description" content="{{CoreApp.Description}}">
|
||||
<link rel="shortcut icon" type="image/x-icon" href="favicon.ico">
|
||||
<base href="{{BasePath}}">
|
||||
{{if USE_CDN}}
|
||||
<link rel="shortcut icon" type="image/x-icon" href="https://assets.statping.com/favicon.ico">
|
||||
<link rel="stylesheet" href="https://assets.statping.com/vendor.css">
|
||||
<link rel="stylesheet" href="https://assets.statping.com/style.css">
|
||||
<link rel="stylesheet" href="https://assets.statping.com/main.css">
|
||||
{{else}}
|
||||
<link rel="shortcut icon" type="image/x-icon" href="favicon.ico">
|
||||
{{if USING_ASSETS}}
|
||||
<link href="css/vendor.css" rel="stylesheet">
|
||||
<link href="css/style.css" rel="stylesheet">
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 1.1 KiB |
|
@ -5,6 +5,7 @@
|
|||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no, maximum-scale=1.0, user-scalable=0">
|
||||
<base href="/">
|
||||
<link rel="icon" type="image/x-icon" href="/favicon.ico">
|
||||
<title>Statping</title>
|
||||
</head>
|
||||
<body>
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import Api from './API';
|
||||
import Footer from "./components/Index/Footer";
|
||||
|
||||
export default {
|
||||
|
@ -28,6 +27,9 @@
|
|||
async beforeMount() {
|
||||
await this.$store.dispatch('loadCore')
|
||||
|
||||
this.$i18n.locale = this.core.language || "en";
|
||||
// this.$i18n.locale = "ru";
|
||||
|
||||
if (!this.core.setup) {
|
||||
this.$router.push('/setup')
|
||||
}
|
||||
|
|
|
@ -6,6 +6,13 @@
|
|||
background-color: $sm-background-color;
|
||||
}
|
||||
|
||||
.service-tm-menu {
|
||||
height: 300px;
|
||||
}
|
||||
|
||||
.service-tm-menu A {
|
||||
height: 27px;
|
||||
}
|
||||
|
||||
.index-chart {
|
||||
height: 380px;
|
||||
|
|
|
@ -67,6 +67,8 @@
|
|||
this.edit = v
|
||||
},
|
||||
editUser(u, mode) {
|
||||
delete(u.password)
|
||||
delete(u.confirm_password)
|
||||
this.user = u
|
||||
this.edit = !mode
|
||||
},
|
||||
|
|
|
@ -1,23 +1,47 @@
|
|||
<template>
|
||||
<div class="col-12">
|
||||
<FormService :in_service="service"/>
|
||||
|
||||
<div v-if='ready'>
|
||||
|
||||
<div v-if='errorCode==404' class="col-12">
|
||||
<div class="alert alert-warning" role="alert">
|
||||
Service {{ this.$route.params.id }} not found!
|
||||
<router-link v-if="$store.state.admin" to="/dashboard/create_service" class="btn btn-sm btn-outline-success float-right">
|
||||
<font-awesome-icon icon="plus"/> Create One?
|
||||
</router-link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-else-if='errorCode==401' class="col-12">
|
||||
<div class="alert alert-danger" role="alert">
|
||||
Unauthorized! Perhaps your session has expired?
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-else class="col-12">
|
||||
<FormService :in_service="service"/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div v-else>
|
||||
|
||||
<div class="text-center">
|
||||
<div class="spinner-border text-primary" role="status">
|
||||
<span class="sr-only">Loading...</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import FormGroup from "../../forms/Group";
|
||||
import Api from "../../API";
|
||||
import ToggleSwitch from "../../forms/ToggleSwitch";
|
||||
import draggable from 'vuedraggable'
|
||||
import FormService from "../../forms/Service";
|
||||
import Api from "@/API";
|
||||
import FormService from "@/forms/Service";
|
||||
|
||||
export default {
|
||||
name: 'EditService',
|
||||
components: {
|
||||
FormService,
|
||||
ToggleSwitch,
|
||||
FormGroup,
|
||||
draggable
|
||||
},
|
||||
props: {
|
||||
|
||||
|
@ -25,24 +49,100 @@
|
|||
data () {
|
||||
return {
|
||||
ready: false,
|
||||
service: {}
|
||||
errorCode: 'none',
|
||||
service: {
|
||||
name: "",
|
||||
type: "http",
|
||||
domain: "",
|
||||
group_id: 0,
|
||||
method: "GET",
|
||||
post_data: "",
|
||||
headers: "",
|
||||
expected: "",
|
||||
expected_status: 200,
|
||||
port: 80,
|
||||
check_interval: 60,
|
||||
timeout: 15,
|
||||
permalink: "",
|
||||
order: 1,
|
||||
verify_ssl: true,
|
||||
redirect: true,
|
||||
allow_notifications: true,
|
||||
notify_all_changes: true,
|
||||
notify_after: 2,
|
||||
public: true,
|
||||
tls_cert: "",
|
||||
tls_cert_key: "",
|
||||
tls_cert_root: "",
|
||||
},
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
||||
|
||||
// because route changes within the same component are re-used
|
||||
|
||||
watch: {
|
||||
$route(to, from) {
|
||||
this.errorCode = 'none';
|
||||
this.ready = true;
|
||||
}
|
||||
},
|
||||
async beforeCreate() {
|
||||
|
||||
// beforeCreated() causes sync issues with mounted() as they are executed
|
||||
// one after the other regardless of async/await methods inside.
|
||||
|
||||
mounted() {
|
||||
|
||||
const id = this.$route.params.id
|
||||
|
||||
if (id) {
|
||||
this.service = await Api.service(id)
|
||||
}
|
||||
this.ready = true
|
||||
},
|
||||
beforeMount() {
|
||||
|
||||
this.loadService(id);
|
||||
|
||||
} else {
|
||||
|
||||
this.errorCode = 'none';
|
||||
this.ready = true;
|
||||
|
||||
};
|
||||
|
||||
},
|
||||
|
||||
methods: {
|
||||
|
||||
async loadService(id){
|
||||
|
||||
this.ready = false;
|
||||
|
||||
// api still responds if session is invalid
|
||||
// specifically, if statping is restarted and an existing session exists
|
||||
// theres a further check to not display the data in the form component it seems ??
|
||||
|
||||
await Api.service(id).then(
|
||||
response => {
|
||||
this.service = response;
|
||||
this.errorCode = 'none';
|
||||
this.ready = true;
|
||||
},
|
||||
error => {
|
||||
|
||||
const respStatus = error.response.status;
|
||||
|
||||
if ( respStatus == '404' ) {
|
||||
this.errorCode = 404;
|
||||
} else if ( respStatus == '401' ) {
|
||||
this.errorCode = 401 ;
|
||||
} else {
|
||||
this.errorCode = 'none';
|
||||
};
|
||||
|
||||
this.ready = true;
|
||||
|
||||
}
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -6,11 +6,11 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="row mt-2">
|
||||
<div class="col-4 text-left font-2 text-muted">30 Days Ago</div>
|
||||
<div class="col-4 text-center font-2" :class="{'text-muted': service.online, 'text-danger': !service.online}">
|
||||
<div class="col-3 text-left font-2 text-muted">30 Days Ago</div>
|
||||
<div class="col-6 text-center font-2" :class="{'text-muted': service.online, 'text-danger': !service.online}">
|
||||
{{service_txt}}
|
||||
</div>
|
||||
<div class="col-4 text-right font-2 text-muted">Today</div>
|
||||
<div class="col-3 text-right font-2 text-muted">Today</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -36,14 +36,7 @@ export default {
|
|||
},
|
||||
computed: {
|
||||
service_txt() {
|
||||
const s = this.service
|
||||
if (!s.online) {
|
||||
if (!this.toUnix(this.parseISO(s.last_success))) {
|
||||
return `Always Offline`
|
||||
}
|
||||
return `Offline for ${this.ago(s.last_success)}`
|
||||
}
|
||||
return `${this.service.online_24_hours}% Uptime`
|
||||
return this.smallText(this.service)
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
|
|
|
@ -223,18 +223,6 @@ export default {
|
|||
this.stats.low_ping.chart = pingData.chart;
|
||||
this.stats.low_ping.value = this.humanTime(pingData.low);
|
||||
},
|
||||
smallText(s) {
|
||||
const incidents = s.incidents
|
||||
if (s.online) {
|
||||
return `Checked ${this.ago(s.last_success)} ago`
|
||||
} else {
|
||||
const last = s.last_failure
|
||||
if (last) {
|
||||
return `Offline, last error: ${last} ${this.ago(last.created_at)}`
|
||||
}
|
||||
return `Service has been offline for ${this.ago(s.last_success)}`
|
||||
}
|
||||
},
|
||||
visibleChart(isVisible, entry) {
|
||||
if (isVisible && !this.visible) {
|
||||
this.visible = true
|
||||
|
|
|
@ -31,6 +31,18 @@
|
|||
<small class="form-text text-muted">HTML is allowed inside the footer</small>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Language</label>
|
||||
<select v-model="core.language" class="form-control">
|
||||
<option value="en">English</option>
|
||||
<option value="es">Spanish</option>
|
||||
<option value="fr">French</option>
|
||||
<option value="ru">Russian</option>
|
||||
<option value="de">German</option>
|
||||
</select>
|
||||
<small class="form-text text-muted">HTML is allowed inside the footer</small>
|
||||
</div>
|
||||
|
||||
<div class="form-group row mt-3">
|
||||
<label class="col-sm-10 col-form-label">Enable Error Reporting</label>
|
||||
<div class="col-sm-2 float-right">
|
||||
|
|
|
@ -51,7 +51,7 @@
|
|||
<label for="gh_callback" class="col-sm-4 col-form-label">Callback URL</label>
|
||||
<div class="col-sm-8">
|
||||
<div class="input-group">
|
||||
<input v-bind:value="`${core.domain}/api/oauth/github`" type="text" class="form-control" id="gh_callback" readonly>
|
||||
<input v-bind:value="`${core.domain}/oauth/github`" type="text" class="form-control" id="gh_callback" readonly>
|
||||
<div class="input-group-append copy-btn">
|
||||
<button @click.prevent="copy(`${core.domain}/oauth/github`)" class="btn btn-outline-secondary" type="button">Copy</button>
|
||||
</div>
|
||||
|
@ -90,7 +90,7 @@
|
|||
<label for="google_callback" class="col-sm-4 col-form-label">Callback URL</label>
|
||||
<div class="col-sm-8">
|
||||
<div class="input-group">
|
||||
<input v-bind:value="`${core.domain}/api/oauth/google`" type="text" class="form-control" id="google_callback" readonly>
|
||||
<input v-bind:value="`${core.domain}/oauth/google`" type="text" class="form-control" id="google_callback" readonly>
|
||||
<div class="input-group-append copy-btn">
|
||||
<button @click.prevent="copy(`${core.domain}/oauth/google`)" class="btn btn-outline-secondary" type="button">Copy</button>
|
||||
</div>
|
||||
|
@ -136,7 +136,7 @@
|
|||
<label for="slack_callback" class="col-sm-4 col-form-label">Callback URL</label>
|
||||
<div class="col-sm-8">
|
||||
<div class="input-group">
|
||||
<input v-bind:value="`${core.domain}/api/oauth/slack`" type="text" class="form-control" id="slack_callback" readonly>
|
||||
<input v-bind:value="`${core.domain}/oauth/slack`" type="text" class="form-control" id="slack_callback" readonly>
|
||||
<div class="input-group-append copy-btn">
|
||||
<button @click.prevent="copy(`${core.domain}/oauth/slack`)" class="btn btn-outline-secondary" type="button">Copy</button>
|
||||
</div>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<form @submit.prevent="saveService">
|
||||
<form v-if="service.type" @submit.prevent="saveService">
|
||||
<div class="card contain-card text-black-50 bg-white mb-4">
|
||||
<div class="card-header">Service Information</div>
|
||||
<div class="card-body">
|
||||
|
@ -54,18 +54,21 @@
|
|||
|
||||
<div class="form-group row">
|
||||
<label for="service_interval" class="col-sm-4 col-form-label">Check Interval</label>
|
||||
<div class="col-sm-8">
|
||||
<div class="col-sm-6">
|
||||
<span class="slider-info">{{secondsHumanize(service.check_interval)}}</span>
|
||||
<input v-model="service.check_interval" type="range" class="slider" id="service_interval" min="1" max="1800" :step="stepVal(service.check_interval)">
|
||||
<input v-model="service.check_interval" type="range" class="slider" id="service_interval" min="1" max="1800" :step="1">
|
||||
<small id="interval" class="form-text text-muted">Interval to check your service state</small>
|
||||
</div>
|
||||
<div class="col-sm-2">
|
||||
<input v-model="service.check_interval" type="text" name="check_interval" class="form-control">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card contain-card text-black-50 bg-white mb-4">
|
||||
<div class="card-header">{{service.type.toUpperCase()}} Request Details</div>
|
||||
<div class="card-header">Request Details</div>
|
||||
<div class="card-body">
|
||||
|
||||
<div class="form-group row">
|
||||
|
@ -77,7 +80,7 @@
|
|||
</div>
|
||||
|
||||
<div v-if="service.type.match(/^(tcp|udp|grpc)$/)" class="form-group row">
|
||||
<label class="col-sm-4 col-form-label">{{service.type.toUpperCase()}} Port</label>
|
||||
<label class="col-sm-4 col-form-label">Port</label>
|
||||
<div class="col-sm-8">
|
||||
<input v-model="service.port" type="number" name="port" class="form-control" id="service_port" placeholder="8080">
|
||||
</div>
|
||||
|
@ -99,11 +102,16 @@
|
|||
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-4 col-form-label">Request Timeout</label>
|
||||
<div class="col-sm-8">
|
||||
<span class="slider-info">{{secondsHumanize(service.timeout)}}</span>
|
||||
<div class="col-sm-6">
|
||||
<span v-if="service.timeout >= 0" class="slider-info">{{secondsHumanize(service.timeout)}}</span>
|
||||
<input v-model="service.timeout" type="range" id="timeout" name="timeout" class="slider" min="1" max="180">
|
||||
<small class="form-text text-muted">If the endpoint does not respond within this time it will be considered to be offline</small>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-2">
|
||||
<input v-model="service.timeout" type="text" name="service_timeout" class="form-control">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div v-if="service.type.match(/^(http)$/) && service.method.match(/^(POST|PATCH|DELETE|PUT)$/)" class="form-group row">
|
||||
|
@ -156,6 +164,41 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="service.type.match(/^(tcp|http)$/)" class="form-group row">
|
||||
<label class="col-sm-4 col-form-label">Use TLS Certificate</label>
|
||||
<div class="col-8 mt-1">
|
||||
<span @click="use_tls = !!use_tls" class="switch float-left">
|
||||
<input v-model="use_tls" type="checkbox" name="verify_ssl-option" class="switch" id="switch-use-tls" v-bind:checked="use_tls">
|
||||
<label for="switch-use-tls" v-if="use_tls">Custom TLS Certificates for mTLS services</label>
|
||||
<label for="switch-use-tls" v-if="!use_tls">Ignore TLS Certificates</label>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="use_tls" class="form-group row">
|
||||
<label for="service_tls_cert" class="col-sm-4 col-form-label">TLS Client Certificate</label>
|
||||
<div class="col-sm-8">
|
||||
<textarea v-model="service.tls_cert" name="tls_cert" class="form-control" id="service_tls_cert"></textarea>
|
||||
<small class="form-text text-muted">Absolute path to TLS Client Certificate file or in PEM format</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="use_tls" class="form-group row">
|
||||
<label for="service_tls_cert_key" class="col-sm-4 col-form-label">TLS Client Key</label>
|
||||
<div class="col-sm-8">
|
||||
<textarea v-model="service.tls_cert_key" name="tls_cert_key" class="form-control" id="service_tls_cert_key"></textarea>
|
||||
<small class="form-text text-muted">Absolute path to TLS Client Key file or in PEM format</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="use_tls" class="form-group row">
|
||||
<label for="service_tls_cert_chain" class="col-sm-4 col-form-label">Root CA</label>
|
||||
<div class="col-sm-8">
|
||||
<textarea v-model="service.tls_cert_root" name="tls_cert_key" class="form-control" id="service_tls_cert_chain"></textarea>
|
||||
<small class="form-text text-muted">Absolute path to Root CA file or in PEM format (optional)</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -235,7 +278,11 @@
|
|||
notify_all_changes: true,
|
||||
notify_after: 2,
|
||||
public: true,
|
||||
tls_cert: "",
|
||||
tls_cert_key: "",
|
||||
tls_cert_root: "",
|
||||
},
|
||||
use_tls: false,
|
||||
groups: [],
|
||||
}
|
||||
},
|
||||
|
@ -245,17 +292,28 @@
|
|||
}
|
||||
},
|
||||
watch: {
|
||||
in_service () {
|
||||
this.service = this.in_service
|
||||
in_service: function(svr) {
|
||||
this.service = svr
|
||||
this.use_tls = svr.tls_cert
|
||||
}
|
||||
},
|
||||
async mounted () {
|
||||
if (!this.$store.getters.groups) {
|
||||
const groups = await Api.groups()
|
||||
this.$store.commit('setGroups', groups)
|
||||
const groups = await Api.groups()
|
||||
this.$store.commit('setGroups', groups)
|
||||
}
|
||||
this.update()
|
||||
},
|
||||
methods: {
|
||||
created () {
|
||||
this.update()
|
||||
},
|
||||
methods: {
|
||||
update() {
|
||||
if (this.in_service) {
|
||||
this.service = this.in_service
|
||||
}
|
||||
this.use_tls = this.service.tls_cert
|
||||
},
|
||||
updatePermalink() {
|
||||
const a = 'àáâäæãåāăąçćčđďèéêëēėęěğǵḧîïíīįìłḿñńǹňôöòóœøōõőṕŕřßśšşșťțûüùúūǘůűųẃẍÿýžźż·/_,:;'
|
||||
const b = 'aaaaaaaaaacccddeeeeeeeegghiiiiiilmnnnnoooooooooprrsssssttuuuuuuuuuwxyyzzz------'
|
||||
|
|
|
@ -9,7 +9,17 @@
|
|||
<div class="row">
|
||||
<div class="col-6">
|
||||
<div class="form-group">
|
||||
<label>Database Connection</label>
|
||||
<label>{{ $t('setup.language') }}</label>
|
||||
<select @change="changeLanguages" v-model="setup.language" id="language" class="form-control">
|
||||
<option value="en">English</option>
|
||||
<option value="es">Spanish</option>
|
||||
<option value="fr">French</option>
|
||||
<option value="ru">Russian</option>
|
||||
<option value="de">German</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>{{ $t('setup.connection') }}</label>
|
||||
<select @change="canSubmit" v-model="setup.db_connection" id="db_connection" class="form-control">
|
||||
<option value="sqlite">SQLite</option>
|
||||
<option value="postgres">Postgres</option>
|
||||
|
@ -17,23 +27,23 @@
|
|||
</select>
|
||||
</div>
|
||||
<div v-if="setup.db_connection !== 'sqlite'" class="form-group">
|
||||
<label>Host</label>
|
||||
<label>{{ $t('setup.host') }}</label>
|
||||
<input @keyup="canSubmit" v-model="setup.db_host" id="db_host" type="text" class="form-control" placeholder="localhost">
|
||||
</div>
|
||||
<div v-if="setup.db_connection !== 'sqlite'" class="form-group">
|
||||
<label>Database Port</label>
|
||||
<label>{{ $t('port') }}</label>
|
||||
<input @keyup="canSubmit" v-model="setup.db_port" id="db_port" type="text" class="form-control" placeholder="localhost">
|
||||
</div>
|
||||
<div v-if="setup.db_connection !== 'sqlite'" class="form-group">
|
||||
<label>Username</label>
|
||||
<label>{{ $t('username') }}</label>
|
||||
<input @keyup="canSubmit" v-model="setup.db_user" id="db_user" type="text" class="form-control" placeholder="root">
|
||||
</div>
|
||||
<div v-if="setup.db_connection !== 'sqlite'" class="form-group">
|
||||
<label for="db_password">Password</label>
|
||||
<label for="db_password">{{ $t('password') }}</label>
|
||||
<input @keyup="canSubmit" v-model="setup.db_password" id="db_password" type="password" class="form-control" placeholder="password123">
|
||||
</div>
|
||||
<div v-if="setup.db_connection !== 'sqlite'" class="form-group">
|
||||
<label for="db_database">Database</label>
|
||||
<label for="db_database">{{ $t('database') }}</label>
|
||||
<input @keyup="canSubmit" v-model="setup.db_database" id="db_database" type="text" class="form-control" placeholder="Database name">
|
||||
</div>
|
||||
|
||||
|
@ -42,35 +52,51 @@
|
|||
<div class="col-6">
|
||||
|
||||
<div class="form-group">
|
||||
<label>Project Name</label>
|
||||
<label>{{ $t('setup.project_name') }}</label>
|
||||
<input @keyup="canSubmit" v-model="setup.project" id="project" type="text" class="form-control" placeholder="Great Uptime" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Project Description</label>
|
||||
<label>{{ $t('setup.project_description') }}</label>
|
||||
<input @keyup="canSubmit" v-model="setup.description" id="description" type="text" class="form-control" placeholder="Great Uptime">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="domain">Domain URL</label>
|
||||
<label for="domain">{{ $t('setup.domain') }}</label>
|
||||
<input @keyup="canSubmit" v-model="setup.domain" type="text" class="form-control" id="domain" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Admin Username</label>
|
||||
<label>{{ $t('setup.username') }}</label>
|
||||
<input @keyup="canSubmit" v-model="setup.username" id="username" type="text" class="form-control" placeholder="admin" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Admin Password</label>
|
||||
<label>{{ $t('setup.username') }}</label>
|
||||
<input @keyup="canSubmit" v-model="setup.password" id="password" type="password" class="form-control" placeholder="password" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Confirm Admin Password</label>
|
||||
<label>{{ $t('setup.password_confirm') }}</label>
|
||||
<input @keyup="canSubmit" v-model="setup.confirm_password" id="password_confirm" type="password" class="form-control" placeholder="password" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<div class="col-8">
|
||||
<label>{{ $t('email') }}</label>
|
||||
<input @keyup="canSubmit" v-model="setup.email" id="email" type="text" class="form-control" placeholder="myemail@domain.com">
|
||||
</div>
|
||||
<div class="col-4">
|
||||
<label class="d-none d-sm-block">{{ $t('setup.newsletter') }}</label>
|
||||
<span @click="setup.newsletter = !!setup.newsletter" class="switch">
|
||||
<input v-model="setup.newsletter" type="checkbox" name="using_cdn" class="switch" id="send_newsletter" :checked="setup.newsletter">
|
||||
<label for="send_newsletter"></label>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<small>{{ $t('setup.newsletter_note') }}</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="error" class="col-12 alert alert-danger">
|
||||
|
@ -99,6 +125,7 @@
|
|||
loading: false,
|
||||
disabled: true,
|
||||
setup: {
|
||||
language: "en",
|
||||
db_connection: "sqlite",
|
||||
db_host: "",
|
||||
db_port: "",
|
||||
|
@ -111,7 +138,9 @@
|
|||
username: "",
|
||||
password: "",
|
||||
confirm_password: "",
|
||||
sample_data: true
|
||||
sample_data: true,
|
||||
newsletter: true,
|
||||
email: "",
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -128,6 +157,9 @@
|
|||
this.setup.domain = window.location.protocol + "//" + window.location.hostname + (window.location.port ? ":"+window.location.port : "")
|
||||
},
|
||||
methods: {
|
||||
changeLanguages() {
|
||||
this.$i18n.locale = this.setup.language
|
||||
},
|
||||
canSubmit() {
|
||||
this.error = null
|
||||
const s = this.setup
|
||||
|
|
|
@ -82,10 +82,7 @@
|
|||
},
|
||||
watch: {
|
||||
in_user() {
|
||||
let u = this.in_user
|
||||
u.password = null
|
||||
u.password_confirm = null
|
||||
this.user = u
|
||||
this.user = this.in_user
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
const english = {
|
||||
setup: {
|
||||
language: "Language",
|
||||
connection: "Database Connection",
|
||||
host: "Host",
|
||||
database: "Database",
|
||||
project_name: "Project Name",
|
||||
project_description: "Project Description",
|
||||
domain: "Domain URL",
|
||||
username: "Admin Username",
|
||||
password: "Admin Username",
|
||||
password_confirm: "Confirm Admin Username",
|
||||
newsletter: "Newsletter",
|
||||
newsletter_note: "We will not share your email, emails are only for major updates.",
|
||||
},
|
||||
email: "Email Address",
|
||||
port: "Database Port",
|
||||
username: "Username",
|
||||
password: 'password',
|
||||
service: 'service',
|
||||
online: 'online',
|
||||
offline: 'offline',
|
||||
incident: 'incident',
|
||||
group: 'group',
|
||||
message: 'message',
|
||||
logout: 'logout',
|
||||
sample_data: 'Sample Data',
|
||||
today: 'Today',
|
||||
day: 'day',
|
||||
hour: 'hour',
|
||||
}
|
||||
|
||||
export default english
|
|
@ -0,0 +1,19 @@
|
|||
const french = {
|
||||
setup: {
|
||||
language: "Langue",
|
||||
database_connection: "Database Connection"
|
||||
},
|
||||
service: 'service',
|
||||
online: 'online',
|
||||
offline: 'offline',
|
||||
incident: 'incident',
|
||||
group: 'group',
|
||||
message: 'message',
|
||||
logout: 'logout',
|
||||
sample_data: 'Sample Data',
|
||||
today: 'Today',
|
||||
day: 'day',
|
||||
hour: 'hour',
|
||||
}
|
||||
|
||||
export default french
|
|
@ -0,0 +1,19 @@
|
|||
const german = {
|
||||
setup: {
|
||||
language: "Sprache",
|
||||
database_connection: "Database Connection"
|
||||
},
|
||||
service: 'service',
|
||||
online: 'online',
|
||||
offline: 'offline',
|
||||
incident: 'incident',
|
||||
group: 'group',
|
||||
message: 'message',
|
||||
logout: 'logout',
|
||||
sample_data: 'Sample Data',
|
||||
today: 'Today',
|
||||
day: 'day',
|
||||
hour: 'hour',
|
||||
}
|
||||
|
||||
export default german
|
|
@ -0,0 +1,15 @@
|
|||
import english from "./english"
|
||||
import spanish from "./spanish"
|
||||
import german from "./german"
|
||||
import russian from "./russian";
|
||||
import french from "./french";
|
||||
|
||||
const language = {
|
||||
en: english,
|
||||
es: spanish,
|
||||
de: german,
|
||||
ru: russian,
|
||||
fr: french,
|
||||
}
|
||||
|
||||
export default language
|
|
@ -0,0 +1,19 @@
|
|||
const russian = {
|
||||
setup: {
|
||||
language: "язык",
|
||||
database_connection: "Database Connection"
|
||||
},
|
||||
service: 'service',
|
||||
online: 'online',
|
||||
offline: 'offline',
|
||||
incident: 'incident',
|
||||
group: 'group',
|
||||
message: 'message',
|
||||
logout: 'logout',
|
||||
sample_data: 'Sample Data',
|
||||
today: 'Today',
|
||||
day: 'day',
|
||||
hour: 'hour',
|
||||
}
|
||||
|
||||
export default russian
|
|
@ -0,0 +1,19 @@
|
|||
const spanish = {
|
||||
setup: {
|
||||
language: "Idioma",
|
||||
database_connection: "Database Connection"
|
||||
},
|
||||
service: 'service',
|
||||
online: 'online',
|
||||
offline: 'offline',
|
||||
incident: 'incident',
|
||||
group: 'group',
|
||||
message: 'message',
|
||||
logout: 'logout',
|
||||
sample_data: 'Sample Data',
|
||||
today: 'Today',
|
||||
day: 'day',
|
||||
hour: 'hour',
|
||||
}
|
||||
|
||||
export default spanish
|
|
@ -4,9 +4,13 @@ import VueApexCharts from 'vue-apexcharts'
|
|||
import VueObserveVisibility from 'vue-observe-visibility'
|
||||
import VueClipboard from 'vue-clipboard2'
|
||||
import VueCookies from 'vue-cookies'
|
||||
|
||||
import VueI18n from 'vue-i18n'
|
||||
import router from './routes'
|
||||
import "./mixin"
|
||||
import "./icons"
|
||||
import App from '@/App.vue'
|
||||
import store from './store'
|
||||
import language from './languages'
|
||||
|
||||
Vue.component('apexchart', VueApexCharts)
|
||||
|
||||
|
@ -14,16 +18,19 @@ Vue.use(VueClipboard);
|
|||
Vue.use(VueRouter);
|
||||
Vue.use(VueObserveVisibility);
|
||||
Vue.use(VueCookies);
|
||||
Vue.use(VueI18n);
|
||||
|
||||
const i18n = new VueI18n({
|
||||
fallbackLocale: "en",
|
||||
messages: language
|
||||
});
|
||||
|
||||
Vue.$cookies.config('3d')
|
||||
|
||||
import router from './routes'
|
||||
import "./mixin"
|
||||
import "./icons"
|
||||
|
||||
|
||||
Vue.config.productionTip = false
|
||||
new Vue({
|
||||
router,
|
||||
store,
|
||||
i18n,
|
||||
render: h => h(App),
|
||||
}).$mount('#app')
|
||||
|
|
|
@ -19,17 +19,9 @@ export default Vue.mixin({
|
|||
startToday() {
|
||||
return startOfToday()
|
||||
},
|
||||
secondsHumanize (val) {
|
||||
const t2 = addSeconds(new Date(0), val)
|
||||
if (val >= 60) {
|
||||
let minword = "minute"
|
||||
if (val >= 120) {
|
||||
minword = "minutes"
|
||||
}
|
||||
return format(t2, "m '"+minword+"' s 'seconds'")
|
||||
}
|
||||
return format(t2, "s 'seconds'")
|
||||
},
|
||||
secondsHumanize (val) {
|
||||
return `${val} seconds`
|
||||
},
|
||||
utc(val) {
|
||||
return new Date.UTC(val)
|
||||
},
|
||||
|
@ -51,8 +43,26 @@ export default Vue.mixin({
|
|||
niceDate(val) {
|
||||
return format(parseISO(val), "EEEE, MMM do h:mma")
|
||||
},
|
||||
parseISO(v) {
|
||||
return parseISO(v)
|
||||
parseISO(v) {
|
||||
return parseISO(v)
|
||||
},
|
||||
isZero(val) {
|
||||
return getUnixTime(parseISO(val)) <= 0
|
||||
},
|
||||
smallText(s) {
|
||||
const incidents = s.incidents
|
||||
if (s.online) {
|
||||
return `Online, checked ${this.ago(s.last_success)} ago`
|
||||
} else {
|
||||
const last = s.last_failure
|
||||
if (last) {
|
||||
return `Offline, last error: ${last} ${this.ago(last.created_at)}`
|
||||
}
|
||||
if (this.isZero(s.last_success)) {
|
||||
return `Service has never been online`
|
||||
}
|
||||
return `Service has been offline for ${this.ago(s.last_success)}`
|
||||
}
|
||||
},
|
||||
toUnix(val) {
|
||||
return getUnixTime(val)
|
||||
|
|
|
@ -1371,6 +1371,14 @@
|
|||
"@types/yargs" "^15.0.0"
|
||||
chalk "^3.0.0"
|
||||
|
||||
"@kazupon/vue-i18n-loader@^0.5.0":
|
||||
version "0.5.0"
|
||||
resolved "https://registry.yarnpkg.com/@kazupon/vue-i18n-loader/-/vue-i18n-loader-0.5.0.tgz#64819fc9dbe21bac523e3436b7e15c32bcd33b92"
|
||||
integrity sha512-Tp2mXKemf9/RBhI9CW14JjR9oKjL2KH7tV6S0eKEjIBuQBAOFNuPJu3ouacmz9hgoXbNp+nusw3MVQmxZWFR9g==
|
||||
dependencies:
|
||||
js-yaml "^3.13.1"
|
||||
json5 "^2.1.1"
|
||||
|
||||
"@mrmlnc/readdir-enhanced@^2.2.1":
|
||||
version "2.2.1"
|
||||
resolved "https://registry.yarnpkg.com/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde"
|
||||
|
@ -7063,6 +7071,13 @@ json5@^2.1.0:
|
|||
dependencies:
|
||||
minimist "^1.2.0"
|
||||
|
||||
json5@^2.1.1:
|
||||
version "2.1.3"
|
||||
resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.3.tgz#c9b0f7fa9233bfe5807fe66fcf3a5617ed597d43"
|
||||
integrity sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==
|
||||
dependencies:
|
||||
minimist "^1.2.5"
|
||||
|
||||
json5@^2.1.2:
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.2.tgz#43ef1f0af9835dd624751a6b7fa48874fb2d608e"
|
||||
|
@ -11884,6 +11899,11 @@ vue-hot-reload-api@^2.3.0:
|
|||
resolved "https://registry.yarnpkg.com/vue-hot-reload-api/-/vue-hot-reload-api-2.3.4.tgz#532955cc1eb208a3d990b3a9f9a70574657e08f2"
|
||||
integrity sha512-BXq3jwIagosjgNVae6tkHzzIk6a8MHFtzAdwhnV5VlvPTFxDCvIttgSiHWjdGoTJvXtmRu5HacExfdarRcFhog==
|
||||
|
||||
vue-i18n@^8.18.1:
|
||||
version "8.18.1"
|
||||
resolved "https://registry.yarnpkg.com/vue-i18n/-/vue-i18n-8.18.1.tgz#2e683ac93a15617bdcd210f99359d6034e8425dd"
|
||||
integrity sha512-K+hFQJksF8Ph23pnhbwSyoQx+4Y1q/rh2o7GiXI/3rLCCrwanUbzudC8+trp0Mb8rn9y83DYF6RXNrMd+VsuCw==
|
||||
|
||||
vue-loader@^15.8.3:
|
||||
version "15.9.0"
|
||||
resolved "https://registry.yarnpkg.com/vue-loader/-/vue-loader-15.9.0.tgz#5d4b0378a4606188fc83e587ed23c94bc3a10998"
|
||||
|
|
14
go.mod
14
go.mod
|
@ -12,24 +12,16 @@ require (
|
|||
github.com/fsnotify/fsnotify v1.4.9 // indirect
|
||||
github.com/getsentry/sentry-go v0.5.1
|
||||
github.com/go-mail/mail v2.3.1+incompatible
|
||||
github.com/gogo/protobuf v1.3.1 // indirect
|
||||
github.com/golang/protobuf v1.3.5
|
||||
github.com/gorilla/mux v1.7.4
|
||||
github.com/gorilla/securecookie v1.1.1
|
||||
github.com/gorilla/sessions v1.2.0
|
||||
github.com/jinzhu/gorm v1.9.12
|
||||
github.com/joho/godotenv v1.3.0
|
||||
github.com/kataras/iris/v12 v12.0.1
|
||||
github.com/magiconair/properties v1.8.1
|
||||
github.com/mattn/go-sqlite3 v2.0.3+incompatible
|
||||
github.com/mitchellh/mapstructure v1.2.2 // indirect
|
||||
github.com/pelletier/go-toml v1.7.0 // indirect
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/prometheus/common v0.9.1
|
||||
github.com/rendon/testcli v0.0.0-20161027181003-6283090d169f
|
||||
github.com/russross/blackfriday/v2 v2.0.1
|
||||
github.com/sirupsen/logrus v1.4.2
|
||||
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 // indirect
|
||||
github.com/spf13/afero v1.2.2 // indirect
|
||||
github.com/spf13/cast v1.3.1 // indirect
|
||||
github.com/spf13/cobra v1.0.0
|
||||
|
@ -37,12 +29,12 @@ require (
|
|||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/spf13/viper v1.6.3
|
||||
github.com/stretchr/testify v1.5.1
|
||||
github.com/tatsushid/go-fastping v0.0.0-20160109021039-d7bb493dee3e
|
||||
golang.org/x/crypto v0.0.0-20200320181102-891825fb96df
|
||||
github.com/t-tiger/gorm-bulk-insert/v2 v2.0.1
|
||||
golang.org/x/crypto v0.0.0-20200406173513-056763e48d71
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b // indirect
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be
|
||||
golang.org/x/sys v0.0.0-20200413165638-669c56c373c4 // indirect
|
||||
golang.org/x/text v0.3.2 // indirect
|
||||
golang.org/x/tools v0.0.0-20200321014904-268ba720d32c // indirect
|
||||
google.golang.org/grpc v1.28.0
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
|
||||
gopkg.in/ini.v1 v1.55.0 // indirect
|
||||
|
|
64
go.sum
64
go.sum
|
@ -5,6 +5,8 @@ github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ
|
|||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/CloudyKit/fastprinter v0.0.0-20170127035650-74b38d55f37a/go.mod h1:EFZQ978U7x8IRnstaskI3IysnWY5Ao3QgZUKOXlsAdw=
|
||||
github.com/CloudyKit/jet v2.1.3-0.20180809161101-62edd43e4f88+incompatible/go.mod h1:HPYO+50pSWkPoj9Q/eq0aRGByCL6ScRlUmiEX5Zgm+w=
|
||||
github.com/DATA-DOG/go-sqlmock v1.4.1 h1:ThlnYciV1iM/V0OSF/dtkqWb6xo5qITT1TJBG1MRDJM=
|
||||
github.com/DATA-DOG/go-sqlmock v1.4.1/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
|
||||
github.com/GeertJohan/go.incremental v1.0.0 h1:7AH+pY1XUgQE4Y1HcXYaMqAI0m9yrFqo/jt0CW30vsg=
|
||||
github.com/GeertJohan/go.incremental v1.0.0/go.mod h1:6fAjUhbVuX1KcMD3c8TEgVUqmo4seqhv0i0kdATSkM0=
|
||||
github.com/GeertJohan/go.rice v1.0.0 h1:KkI6O9uMaQU3VEKaj01ulavtF7o1fWT7+pk/4voiMLQ=
|
||||
|
@ -18,11 +20,7 @@ github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY
|
|||
github.com/akavel/rsrc v0.8.0 h1:zjWn7ukO9Kc5Q62DOJCcxGpXC18RawVtYAGdz2aLlfw=
|
||||
github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4 h1:Hs82Z41s6SdL1CELW+XaDYmOH4hkBN4/N9og/AsOv7E=
|
||||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/ararog/timeago v0.0.0-20160328174124-e9969cf18b8d h1:ZX0t+GA3MWiP7LWt5xWOphWRQd5JwL4VW5uLW83KM8g=
|
||||
github.com/ararog/timeago v0.0.0-20160328174124-e9969cf18b8d/go.mod h1:EcJ034SpbWy4heOSDiBZJRn3b5wKJM1b4sFfYeVAkI4=
|
||||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||
|
@ -43,6 +41,7 @@ github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7
|
|||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/daaku/go.zipexe v1.0.0 h1:VSOgZtH418pH9L16hC/JrgSNJbbAL26pj7lmD1+CGdY=
|
||||
github.com/daaku/go.zipexe v1.0.0/go.mod h1:z8IiR6TsVLEYKwXAoE/I+8ys/sDkgTzSL0CLnGVd57E=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
|
@ -50,6 +49,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
|
|||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd h1:83Wprp6ROGeiHFAP8WJdI2RoxALQYgdllERc3N5N2DM=
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20200206145737-bbfc9a55622e h1:LzwWXEScfcTu7vUZNlDDWDARoSGEtvlDKK2BYHowNeE=
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20200206145737-bbfc9a55622e/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
|
||||
github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
|
@ -82,7 +83,6 @@ github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclK
|
|||
github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w=
|
||||
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-mail/mail v2.3.1+incompatible h1:UzNOn0k5lpfVtO31cK3hn6I4VEVGhe3lX8AJBAxXExM=
|
||||
|
@ -90,6 +90,8 @@ github.com/go-mail/mail v2.3.1+incompatible/go.mod h1:VPWjmmNyRsWXQZHVHT3g0YbIIN
|
|||
github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8=
|
||||
github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA=
|
||||
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
|
||||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo=
|
||||
github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
|
||||
|
@ -97,8 +99,6 @@ github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/E
|
|||
github.com/gogo/protobuf v1.1.1 h1:72R+M5VuhED/KujmZVcIquuo8mBgX4oVda//DQb3PXo=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||
github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=
|
||||
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
|
||||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY=
|
||||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
|
@ -118,13 +118,10 @@ github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
|
|||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gorilla/mux v1.7.4 h1:VuZ8uybHlWmqV03+zRzdwKL4tUnIp1MAQtp1mIFE1bc=
|
||||
github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||
github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ=
|
||||
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
|
||||
github.com/gorilla/sessions v1.2.0 h1:S7P+1Hm5V/AT9cjEcUD5uDaQSX0OE577aCXgoaKpYbQ=
|
||||
github.com/gorilla/sessions v1.2.0/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
|
||||
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
||||
|
@ -151,12 +148,13 @@ github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD
|
|||
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||
github.com/jinzhu/now v1.0.1 h1:HjfetcXq097iXP0uoPCdnM4Efp5/9MsM0/M+XOTeR3M=
|
||||
github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
|
||||
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
|
||||
github.com/jinzhu/now v1.1.1 h1:g39TucaRWyV3dwDO++eEc6qf8TVIQ/Da48WmqjZ3i7E=
|
||||
github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||
github.com/json-iterator/go v1.1.6 h1:MrUvLMLTMxbqFJ9kzlvat/rYZqZnW3u4wkLzWTaFwKs=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q=
|
||||
github.com/juju/loggo v0.0.0-20180524022052-584905176618/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U=
|
||||
|
@ -171,7 +169,6 @@ github.com/kataras/neffos v0.0.10/go.mod h1:ZYmJC07hQPW67eKuzlfY7SO3bC0mw83A3j6i
|
|||
github.com/kataras/pio v0.0.0-20190103105442-ea782b38602d h1:V5Rs9ztEWdp58oayPq/ulmlqJJZeJP6pP79uP3qjcao=
|
||||
github.com/kataras/pio v0.0.0-20190103105442-ea782b38602d/go.mod h1:NV88laa9UiiDuX9AhMbDPkGYSPugBOV6yTZB1l2K9Z0=
|
||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||
github.com/klauspost/compress v1.9.0 h1:GhthINjveNZAdFUD8QoQYfjxnOONZgztK/Yr6M23UTY=
|
||||
|
@ -183,10 +180,14 @@ github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFB
|
|||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/labstack/echo/v4 v4.1.11/go.mod h1:i541M3Fj6f76NZtHSj7TXnyM8n2gaodfvfxNnFqi74g=
|
||||
github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k=
|
||||
github.com/lib/pq v1.1.1 h1:sJZmqHoEaY7f+NPP8pgLB/WxulyR3fewgCM2qaSlBb4=
|
||||
github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.3.0 h1:/qkRGz8zljWiDcFvgpwUpwIAPu3r07TDvs3Rws+o/pU=
|
||||
github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
|
||||
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
|
@ -221,6 +222,8 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW
|
|||
github.com/nats-io/nats.go v1.8.1/go.mod h1:BrFz9vVn0fU3AcH9Vn4Kd7W0NpJ651tD5omQ3M8LwxM=
|
||||
github.com/nats-io/nkeys v0.0.2/go.mod h1:dab7URMsZm6Z/jp9Z5UGa87Uutgc2mVpXLC4B7TDb/4=
|
||||
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229 h1:E2B8qYyeSgv5MXpmzZXRNp8IAQ4vjxIjhpAf5hv/tAg=
|
||||
github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229/go.mod h1:0aYXnNPJ8l7uZxf45rWW1a/uME32OF0rhiYGNQ2oF2E=
|
||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||
|
@ -241,22 +244,14 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
|
|||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
|
||||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.9.1 h1:KOMtN28tlbam3/7ZKEYKHhKoJZYYj3gMH4uc62x7X7U=
|
||||
github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
||||
github.com/rendon/testcli v0.0.0-20161027181003-6283090d169f h1:onGP+qmYmjKs7pkmi9j0mwyr97/D5wki80e74aKIOxg=
|
||||
github.com/rendon/testcli v0.0.0-20161027181003-6283090d169f/go.mod h1:cq57a4l475CeMvE7RRpSui1MEqCmhirIt1E7kl8BC2Q=
|
||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||
github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=
|
||||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||
|
@ -269,9 +264,9 @@ github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeV
|
|||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 h1:JIAuq3EEf9cgbU6AtGPK4CTG3Zf6CKMNqf0MHTggAUA=
|
||||
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
|
||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
|
@ -308,8 +303,8 @@ github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H
|
|||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
|
||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||
github.com/tatsushid/go-fastping v0.0.0-20160109021039-d7bb493dee3e h1:nt2877sKfojlHCTOBXbpWjBkuWKritFaGIfgQwbQUls=
|
||||
github.com/tatsushid/go-fastping v0.0.0-20160109021039-d7bb493dee3e/go.mod h1:B4+Kq1u5FlULTjFSM707Q6e/cOHFv0z/6QRoxubDIQ8=
|
||||
github.com/t-tiger/gorm-bulk-insert/v2 v2.0.1 h1:HGVkRrwDCbmSP6h1CoBDj6l/mhnvsP5JbYaQ4ss0R6o=
|
||||
github.com/t-tiger/gorm-bulk-insert/v2 v2.0.1/go.mod h1:I3xbaE9ud9/TEXzehwkHx86SyJwqeSNsX2X5oV61jIg=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
|
||||
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
||||
|
@ -331,7 +326,6 @@ github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmv
|
|||
github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg=
|
||||
github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM=
|
||||
github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc=
|
||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||
|
@ -341,15 +335,13 @@ golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnf
|
|||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200320181102-891825fb96df h1:lDWgvUvNnaTnNBc/dwOty86cFeKoKWbwy2wQj0gIxbU=
|
||||
golang.org/x/crypto v0.0.0-20200320181102-891825fb96df/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200406173513-056763e48d71 h1:DOmugCavvUtnUD114C1Wh+UgTgQZ4pMLzXxi1pSt+/Y=
|
||||
golang.org/x/crypto v0.0.0-20200406173513-056763e48d71/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
|
@ -361,7 +353,6 @@ golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn
|
|||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM=
|
||||
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
|
@ -373,7 +364,6 @@ golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJ
|
|||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
|
@ -397,7 +387,6 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
|||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20181221001348-537d06c36207/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
|
@ -405,11 +394,6 @@ golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3
|
|||
golang.org/x/tools v0.0.0-20190327201419-c70d86f8b7cf/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200321014904-268ba720d32c h1:Qp5jXmUCqMiVq4676uW7bY2oskIR1ivTboSMn8qgeX0=
|
||||
golang.org/x/tools v0.0.0-20200321014904-268ba720d32c/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
|
@ -431,6 +415,8 @@ gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod
|
|||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
|
||||
gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y=
|
||||
|
|
|
@ -29,10 +29,6 @@ type oAuth struct {
|
|||
func oauthHandler(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
provider := vars["provider"]
|
||||
code := r.URL.Query().Get("code")
|
||||
fmt.Println("code: ", code)
|
||||
fmt.Println("client: ", core.App.OAuth.SlackClientID)
|
||||
fmt.Println("secret: ", core.App.OAuth.SlackClientSecret)
|
||||
|
||||
var err error
|
||||
var oauth *oAuth
|
||||
|
@ -143,7 +139,7 @@ func slackOAuth(r *http.Request) (*oAuth, error) {
|
|||
// slackIdentity will query the Slack API to fetch the users ID, username, and email address.
|
||||
func (a *oAuth) slackIdentity() (*oAuth, error) {
|
||||
url := fmt.Sprintf("https://slack.com/api/users.identity?token=%s", a.Token)
|
||||
out, resp, err := utils.HttpRequest(url, "GET", "application/x-www-form-urlencoded", nil, nil, 10*time.Second, true)
|
||||
out, resp, err := utils.HttpRequest(url, "GET", "application/x-www-form-urlencoded", nil, nil, 10*time.Second, true, nil)
|
||||
if err != nil {
|
||||
return a, err
|
||||
}
|
||||
|
|
|
@ -75,7 +75,7 @@ func Router() *mux.Router {
|
|||
r.Handle("/api", scoped(apiIndexHandler))
|
||||
r.Handle("/api/setup", http.HandlerFunc(processSetupHandler)).Methods("POST")
|
||||
api.Handle("/api/login", http.HandlerFunc(apiLoginHandler)).Methods("POST")
|
||||
api.Handle("/api/logout", authenticated(logoutHandler, false))
|
||||
api.Handle("/api/logout", http.HandlerFunc(logoutHandler))
|
||||
api.Handle("/api/renew", authenticated(apiRenewHandler, false))
|
||||
api.Handle("/api/cache", authenticated(apiCacheHandler, false)).Methods("GET")
|
||||
api.Handle("/api/clear_cache", authenticated(apiClearCacheHandler, false))
|
||||
|
@ -160,7 +160,6 @@ func Router() *mux.Router {
|
|||
// API Generic Routes
|
||||
r.Handle("/metrics", readOnly(prometheusHandler, false))
|
||||
r.Handle("/health", http.HandlerFunc(healthCheckHandler))
|
||||
api.Handle("/api/oauth/{provider}", http.HandlerFunc(oauthHandler))
|
||||
r.Handle("/.well-known/", http.StripPrefix("/.well-known/", http.FileServer(http.Dir(dir+"/.well-known"))))
|
||||
r.NotFoundHandler = http.HandlerFunc(error404Handler)
|
||||
return r
|
||||
|
|
|
@ -9,6 +9,9 @@ import (
|
|||
"github.com/statping/statping/types/services"
|
||||
"github.com/statping/statping/utils"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
@ -29,6 +32,8 @@ func processSetupHandler(w http.ResponseWriter, r *http.Request) {
|
|||
project := r.PostForm.Get("project")
|
||||
description := r.PostForm.Get("description")
|
||||
domain := r.PostForm.Get("domain")
|
||||
newsletter := r.PostForm.Get("newsletter")
|
||||
sendNews, _ := strconv.ParseBool(newsletter)
|
||||
|
||||
log.WithFields(utils.ToFields(core.App, confgs)).Debugln("new configs posted")
|
||||
|
||||
|
@ -85,6 +90,7 @@ func processSetupHandler(w http.ResponseWriter, r *http.Request) {
|
|||
CreatedAt: utils.Now(),
|
||||
UseCdn: null.NewNullBool(false),
|
||||
Footer: null.NewNullString(""),
|
||||
Language: confgs.Language,
|
||||
}
|
||||
|
||||
log.Infoln("Creating new Core")
|
||||
|
@ -96,6 +102,13 @@ func processSetupHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
core.App = c
|
||||
|
||||
if sendNews {
|
||||
log.Infof("Sending email address %s to newsletter server", confgs.Email)
|
||||
if err := registerNews(confgs.Email, confgs.Domain); err != nil {
|
||||
log.Errorln(err)
|
||||
}
|
||||
}
|
||||
|
||||
log.Infoln("Initializing new Statping instance")
|
||||
|
||||
if _, err := services.SelectAllServices(true); err != nil {
|
||||
|
@ -110,7 +123,7 @@ func processSetupHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
CacheStorage.Delete("/")
|
||||
resetCookies()
|
||||
time.Sleep(1 * time.Second)
|
||||
time.Sleep(2 * time.Second)
|
||||
out := struct {
|
||||
Message string `json:"message"`
|
||||
Config *configs.DbConfig `json:"config"`
|
||||
|
@ -120,3 +133,19 @@ func processSetupHandler(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
returnJson(out, w, r)
|
||||
}
|
||||
|
||||
func registerNews(email, domain string) error {
|
||||
if email == "" {
|
||||
return nil
|
||||
}
|
||||
v := url.Values{}
|
||||
v.Set("email", email)
|
||||
v.Set("domain", domain)
|
||||
v.Set("timezone", "UTC")
|
||||
rb := strings.NewReader(v.Encode())
|
||||
resp, err := http.Post("https://news.statping.com/new", "application/x-www-form-urlencoded", rb)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return resp.Body.Close()
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
)
|
||||
|
||||
func TestCommandNotifier(t *testing.T) {
|
||||
t.SkipNow()
|
||||
db, err := database.OpenTester()
|
||||
require.Nil(t, err)
|
||||
db.AutoMigrate(¬ifications.Notification{})
|
||||
|
|
|
@ -39,7 +39,7 @@ var Discorder = &discord{¬ifications.Notification{
|
|||
|
||||
// Send will send a HTTP Post to the discord API. It accepts type: []byte
|
||||
func (d *discord) sendRequest(msg string) error {
|
||||
_, _, err := utils.HttpRequest(Discorder.GetValue("host"), "POST", "application/json", nil, strings.NewReader(msg), time.Duration(10*time.Second), true)
|
||||
_, _, err := utils.HttpRequest(Discorder.GetValue("host"), "POST", "application/json", nil, strings.NewReader(msg), time.Duration(10*time.Second), true, nil)
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -63,7 +63,7 @@ func (d *discord) OnSuccess(s *services.Service) error {
|
|||
func (d *discord) OnTest() (string, error) {
|
||||
outError := errors.New("Incorrect discord URL, please confirm URL is correct")
|
||||
message := `{"content": "Testing the discord notifier"}`
|
||||
contents, _, err := utils.HttpRequest(Discorder.Host, "POST", "application/json", nil, bytes.NewBuffer([]byte(message)), time.Duration(10*time.Second), true)
|
||||
contents, _, err := utils.HttpRequest(Discorder.Host, "POST", "application/json", nil, bytes.NewBuffer([]byte(message)), time.Duration(10*time.Second), true, nil)
|
||||
if string(contents) == "" {
|
||||
return "", nil
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ func (l *lineNotifier) sendMessage(message string) (string, error) {
|
|||
v := url.Values{}
|
||||
v.Set("message", message)
|
||||
headers := []string{fmt.Sprintf("Authorization=Bearer %v", l.ApiSecret)}
|
||||
content, _, err := utils.HttpRequest("https://notify-api.line.me/api/notify", "POST", "application/x-www-form-urlencoded", headers, strings.NewReader(v.Encode()), time.Duration(10*time.Second), true)
|
||||
content, _, err := utils.HttpRequest("https://notify-api.line.me/api/notify", "POST", "application/x-www-form-urlencoded", headers, strings.NewReader(v.Encode()), time.Duration(10*time.Second), true, nil)
|
||||
return string(content), err
|
||||
}
|
||||
|
||||
|
|
|
@ -142,7 +142,7 @@ func pushRequest(msg *pushArray) ([]byte, error) {
|
|||
return nil, err
|
||||
}
|
||||
url := "https://push.statping.com/api/push"
|
||||
body, _, err = utils.HttpRequest(url, "POST", "application/json", nil, bytes.NewBuffer(body), time.Duration(20*time.Second), true)
|
||||
body, _, err = utils.HttpRequest(url, "POST", "application/json", nil, bytes.NewBuffer(body), time.Duration(20*time.Second), true, nil)
|
||||
return body, err
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ func init() {
|
|||
}
|
||||
|
||||
func TestMobileNotifier(t *testing.T) {
|
||||
t.SkipNow()
|
||||
db, err := database.OpenTester()
|
||||
require.Nil(t, err)
|
||||
db.AutoMigrate(¬ifications.Notification{})
|
||||
|
|
|
@ -59,7 +59,7 @@ func (t *pushover) sendMessage(message string) (string, error) {
|
|||
v.Set("message", message)
|
||||
rb := strings.NewReader(v.Encode())
|
||||
|
||||
content, _, err := utils.HttpRequest(pushoverUrl, "POST", "application/x-www-form-urlencoded", nil, rb, time.Duration(10*time.Second), true)
|
||||
content, _, err := utils.HttpRequest(pushoverUrl, "POST", "application/x-www-form-urlencoded", nil, rb, time.Duration(10*time.Second), true, nil)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
|
|
@ -50,7 +50,7 @@ var slacker = &slack{¬ifications.Notification{
|
|||
|
||||
// Send will send a HTTP Post to the slack webhooker API. It accepts type: string
|
||||
func (s *slack) sendSlack(msg string) error {
|
||||
_, resp, err := utils.HttpRequest(s.Host, "POST", "application/json", nil, strings.NewReader(msg), time.Duration(10*time.Second), true)
|
||||
_, resp, err := utils.HttpRequest(s.Host, "POST", "application/json", nil, strings.NewReader(msg), time.Duration(10*time.Second), true, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -60,7 +60,7 @@ func (s *slack) sendSlack(msg string) error {
|
|||
|
||||
func (s *slack) OnTest() (string, error) {
|
||||
testMsg := ReplaceVars(failingTemplate, exampleService, exampleFailure)
|
||||
contents, resp, err := utils.HttpRequest(s.Host, "POST", "application/json", nil, bytes.NewBuffer([]byte(testMsg)), time.Duration(10*time.Second), true)
|
||||
contents, resp, err := utils.HttpRequest(s.Host, "POST", "application/json", nil, bytes.NewBuffer([]byte(testMsg)), time.Duration(10*time.Second), true, nil)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
|
|
@ -59,7 +59,7 @@ func (t *telegram) sendMessage(message string) (string, error) {
|
|||
v.Set("text", message)
|
||||
rb := *strings.NewReader(v.Encode())
|
||||
|
||||
contents, _, err := utils.HttpRequest(apiEndpoint, "GET", "application/x-www-form-urlencoded", nil, &rb, time.Duration(10*time.Second), true)
|
||||
contents, _, err := utils.HttpRequest(apiEndpoint, "GET", "application/x-www-form-urlencoded", nil, &rb, time.Duration(10*time.Second), true, nil)
|
||||
|
||||
success, _ := telegramSuccess(contents)
|
||||
if !success {
|
||||
|
|
|
@ -72,7 +72,7 @@ func (t *twilio) sendMessage(message string) (string, error) {
|
|||
|
||||
authHeader := utils.Base64(fmt.Sprintf("%s:%s", t.ApiKey, t.ApiSecret))
|
||||
|
||||
contents, _, err := utils.HttpRequest(twilioUrl, "POST", "application/x-www-form-urlencoded", []string{"Authorization=Basic " + authHeader}, rb, 10*time.Second, true)
|
||||
contents, _, err := utils.HttpRequest(twilioUrl, "POST", "application/x-www-form-urlencoded", []string{"Authorization=Basic " + authHeader}, rb, 10*time.Second, true, nil)
|
||||
success, _ := twilioSuccess(contents)
|
||||
if !success {
|
||||
errorOut := twilioError(contents)
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
)
|
||||
|
||||
func Samples() error {
|
||||
log.Infoln("Inserting Sample Checkins...")
|
||||
checkin1 := &Checkin{
|
||||
Name: "Demo Checkin 1",
|
||||
ServiceId: 1,
|
||||
|
@ -31,6 +32,7 @@ func Samples() error {
|
|||
}
|
||||
|
||||
func SamplesChkHits() error {
|
||||
log.Infoln("Inserting Sample Checkins Hits...")
|
||||
checkTime := utils.Now().Add(-3 * time.Minute)
|
||||
|
||||
for i := int64(1); i <= 2; i++ {
|
||||
|
|
|
@ -23,6 +23,7 @@ func LoadConfigForm(r *http.Request) (*DbConfig, error) {
|
|||
description := g("description")
|
||||
domain := g("domain")
|
||||
email := g("email")
|
||||
language := g("language")
|
||||
|
||||
if project == "" || username == "" || password == "" {
|
||||
err := errors.New("Missing required elements on setup form")
|
||||
|
@ -38,6 +39,7 @@ func LoadConfigForm(r *http.Request) (*DbConfig, error) {
|
|||
p.Set("DB_DATABASE", dbDatabase)
|
||||
p.Set("NAME", project)
|
||||
p.Set("DESCRIPTION", description)
|
||||
p.Set("LANGUAGE", language)
|
||||
|
||||
confg := &DbConfig{
|
||||
DbConn: dbConn,
|
||||
|
@ -53,6 +55,7 @@ func LoadConfigForm(r *http.Request) (*DbConfig, error) {
|
|||
Password: password,
|
||||
Email: email,
|
||||
Location: utils.Directory,
|
||||
Language: language,
|
||||
}
|
||||
|
||||
return confg, nil
|
||||
|
|
|
@ -28,9 +28,8 @@ type Sampler interface {
|
|||
func TriggerSamples() error {
|
||||
return createSamples(
|
||||
core.Samples,
|
||||
//users.Samples,
|
||||
messages.Samples,
|
||||
services.Samples,
|
||||
messages.Samples,
|
||||
checkins.Samples,
|
||||
checkins.SamplesChkHits,
|
||||
failures.Samples,
|
||||
|
|
|
@ -62,7 +62,7 @@ func LoadConfigFile(configFile string) (*DbConfig, error) {
|
|||
Domain: p.GetString("DOMAIN"),
|
||||
Email: p.GetString("EMAIL"),
|
||||
Username: p.GetString("ADMIN_USER"),
|
||||
Password: p.GetString("ADMIN_PASS"),
|
||||
Password: p.GetString("ADMIN_PASSWORD"),
|
||||
Location: utils.Directory,
|
||||
SqlFile: p.GetString("SQL_FILE"),
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ type DbConfig struct {
|
|||
DbData string `yaml:"database" json:"-"`
|
||||
DbPort int `yaml:"port" json:"-"`
|
||||
ApiSecret string `yaml:"api_secret" json:"-"`
|
||||
Language string `yaml:"language" json:"language"`
|
||||
Project string `yaml:"-" json:"-"`
|
||||
Description string `yaml:"-" json:"-"`
|
||||
Domain string `yaml:"-" json:"-"`
|
||||
|
|
|
@ -50,6 +50,7 @@ func (c *Core) Create() error {
|
|||
ApiSecret: secret,
|
||||
Version: App.Version,
|
||||
Domain: c.Domain,
|
||||
Language: c.Language,
|
||||
MigrationId: utils.Now().Unix(),
|
||||
}
|
||||
q := db.Create(&newCore)
|
||||
|
|
|
@ -13,10 +13,10 @@ func Samples() error {
|
|||
}
|
||||
|
||||
core := &Core{
|
||||
Name: "Statping Sample Data",
|
||||
Description: "This data is only used to testing",
|
||||
Name: utils.Params.GetString("NAME"),
|
||||
Description: utils.Params.GetString("DESCRIPTION"),
|
||||
ApiSecret: apiSecret,
|
||||
Domain: "http://localhost:8080",
|
||||
Domain: utils.Params.GetString("DOMAIN"),
|
||||
CreatedAt: utils.Now(),
|
||||
UseCdn: null.NewNullBool(false),
|
||||
Footer: null.NewNullString(""),
|
||||
|
|
|
@ -28,6 +28,7 @@ type Core struct {
|
|||
Footer null.NullString `gorm:"column:footer" json:"footer"`
|
||||
Domain string `gorm:"not null;column:domain" json:"domain"`
|
||||
Version string `gorm:"column:version" json:"version"`
|
||||
Language string `gorm:"column:language" json:"language"`
|
||||
Setup bool `gorm:"-" json:"setup"`
|
||||
MigrationId int64 `gorm:"column:migration_id" json:"migration_id,omitempty"`
|
||||
UseCdn null.NullBool `gorm:"column:use_cdn;default:false" json:"using_cdn,omitempty"`
|
||||
|
|
|
@ -4,19 +4,19 @@ import (
|
|||
"fmt"
|
||||
"github.com/statping/statping/types"
|
||||
"github.com/statping/statping/utils"
|
||||
gormbulk "github.com/t-tiger/gorm-bulk-insert/v2"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
log = utils.Log
|
||||
log = utils.Log.WithField("type", "failure")
|
||||
)
|
||||
|
||||
func Samples() error {
|
||||
log.Infoln("Inserting Sample Service Failures...")
|
||||
createdAt := utils.Now().Add(-3 * types.Day)
|
||||
|
||||
for i := int64(1); i <= 4; i++ {
|
||||
tx := db.Begin()
|
||||
|
||||
f1 := &Failure{
|
||||
Service: i,
|
||||
Issue: "Server failure",
|
||||
|
@ -33,21 +33,20 @@ func Samples() error {
|
|||
|
||||
log.Infoln(fmt.Sprintf("Adding %v Failure records to service", 400))
|
||||
|
||||
var records []interface{}
|
||||
for fi := 0.; fi <= float64(400); fi++ {
|
||||
failure := &Failure{
|
||||
Service: i,
|
||||
Issue: "testing right here",
|
||||
CreatedAt: createdAt.UTC(),
|
||||
}
|
||||
|
||||
tx = tx.Create(&failure)
|
||||
records = append(records, failure)
|
||||
createdAt = createdAt.Add(35 * time.Minute)
|
||||
}
|
||||
if err := tx.Commit().Error(); err != nil {
|
||||
if err := gormbulk.BulkInsert(db.GormDB(), records, db.ChunkSize()); err != nil {
|
||||
log.Error(err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -3,10 +3,14 @@ package groups
|
|||
import (
|
||||
"github.com/statping/statping/database"
|
||||
"github.com/statping/statping/types/errors"
|
||||
"github.com/statping/statping/utils"
|
||||
"sort"
|
||||
)
|
||||
|
||||
var db database.Database
|
||||
var (
|
||||
db database.Database
|
||||
log = utils.Log.WithField("type", "group")
|
||||
)
|
||||
|
||||
func SetDB(database database.Database) {
|
||||
db = database.Model(&Group{})
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
)
|
||||
|
||||
func Samples() error {
|
||||
log.Infoln("Inserting Sample Groups...")
|
||||
group1 := &Group{
|
||||
Name: "Main Services",
|
||||
Public: null.NewNullBool(true),
|
||||
|
|
|
@ -5,34 +5,33 @@ import (
|
|||
_ "github.com/jinzhu/gorm/dialects/mysql"
|
||||
_ "github.com/jinzhu/gorm/dialects/postgres"
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
"github.com/statping/statping/database"
|
||||
"github.com/statping/statping/types"
|
||||
"github.com/statping/statping/utils"
|
||||
gormbulk "github.com/t-tiger/gorm-bulk-insert/v2"
|
||||
"time"
|
||||
)
|
||||
|
||||
var SampleHits = 99900.
|
||||
|
||||
func Samples() error {
|
||||
log.Infoln("Inserting Sample Service Hits...")
|
||||
for i := int64(1); i <= 5; i++ {
|
||||
tx := db.Begin()
|
||||
tx = createHitsAt(tx, i)
|
||||
|
||||
if err := tx.Commit().Error(); err != nil {
|
||||
records := createHitsAt(i)
|
||||
if err := gormbulk.BulkInsert(db.GormDB(), records, db.ChunkSize()); err != nil {
|
||||
log.Error(err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func createHitsAt(db database.Database, serviceID int64) database.Database {
|
||||
func createHitsAt(serviceID int64) []interface{} {
|
||||
log.Infoln(fmt.Sprintf("Adding Sample records to service #%d...", serviceID))
|
||||
|
||||
createdAt := utils.Now().Add(-3 * types.Day)
|
||||
p := utils.NewPerlin(2, 2, 5, utils.Now().UnixNano())
|
||||
|
||||
var records []interface{}
|
||||
for hi := 0.; hi <= SampleHits; hi++ {
|
||||
latency := p.Noise1D(hi / 500)
|
||||
|
||||
|
@ -43,7 +42,7 @@ func createHitsAt(db database.Database, serviceID int64) database.Database {
|
|||
CreatedAt: createdAt,
|
||||
}
|
||||
|
||||
db = db.Create(&hit)
|
||||
records = append(records, hit)
|
||||
|
||||
if createdAt.After(utils.Now()) {
|
||||
break
|
||||
|
@ -51,5 +50,5 @@ func createHitsAt(db database.Database, serviceID int64) database.Database {
|
|||
createdAt = createdAt.Add(30 * time.Second)
|
||||
}
|
||||
|
||||
return db
|
||||
return records
|
||||
}
|
||||
|
|
|
@ -1,10 +1,14 @@
|
|||
package incidents
|
||||
|
||||
import "github.com/statping/statping/database"
|
||||
import (
|
||||
"github.com/statping/statping/database"
|
||||
"github.com/statping/statping/utils"
|
||||
)
|
||||
|
||||
var (
|
||||
db database.Database
|
||||
dbUpdate database.Database
|
||||
log = utils.Log.WithField("type", "service")
|
||||
)
|
||||
|
||||
func SetDB(database database.Database) {
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
)
|
||||
|
||||
func Samples() error {
|
||||
log.Infoln("Inserting Sample Incidents...")
|
||||
incident1 := &Incident{
|
||||
Title: "Github Issues",
|
||||
Description: "There are new features for Statping, if you have any issues please visit the Github Repo.",
|
||||
|
|
|
@ -3,9 +3,13 @@ package messages
|
|||
import (
|
||||
"github.com/statping/statping/database"
|
||||
"github.com/statping/statping/types/errors"
|
||||
"github.com/statping/statping/utils"
|
||||
)
|
||||
|
||||
var db database.Database
|
||||
var (
|
||||
db database.Database
|
||||
log = utils.Log.WithField("type", "message")
|
||||
)
|
||||
|
||||
func SetDB(database database.Database) {
|
||||
db = database.Model(&Message{})
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
)
|
||||
|
||||
func Samples() error {
|
||||
log.Infoln("Inserting Sample Messages...")
|
||||
m1 := &Message{
|
||||
Title: "Routine Downtime",
|
||||
Description: "This is an example a upcoming message for a service!",
|
||||
|
|
|
@ -2,13 +2,16 @@ package services
|
|||
|
||||
import (
|
||||
"crypto/sha1"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/statping/statping/types"
|
||||
"github.com/statping/statping/types/errors"
|
||||
"github.com/statping/statping/types/failures"
|
||||
"github.com/statping/statping/types/hits"
|
||||
"github.com/statping/statping/utils"
|
||||
"io/ioutil"
|
||||
"sort"
|
||||
"strconv"
|
||||
"time"
|
||||
|
@ -16,6 +19,48 @@ import (
|
|||
|
||||
const limitedFailures = 25
|
||||
|
||||
func (s *Service) LoadTLSCert() (*tls.Config, error) {
|
||||
if s.TLSCert.String == "" || s.TLSCertKey.String == "" {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// load TLS cert and key from file path or PEM format
|
||||
var cert tls.Certificate
|
||||
var err error
|
||||
tlsCertExtension := utils.FileExtension(s.TLSCert.String)
|
||||
tlsCertKeyExtension := utils.FileExtension(s.TLSCertKey.String)
|
||||
if tlsCertExtension == "" && tlsCertKeyExtension == "" {
|
||||
cert, err = tls.X509KeyPair([]byte(s.TLSCert.String), []byte(s.TLSCertKey.String))
|
||||
} else {
|
||||
cert, err = tls.LoadX509KeyPair(s.TLSCert.String, s.TLSCertKey.String)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "issue loading X509KeyPair")
|
||||
}
|
||||
|
||||
config := &tls.Config{
|
||||
Certificates: []tls.Certificate{cert},
|
||||
InsecureSkipVerify: s.TLSCertRoot.String == "",
|
||||
}
|
||||
|
||||
if s.TLSCertRoot.String == "" {
|
||||
return config, nil
|
||||
}
|
||||
|
||||
// create Root CA pool or use Root CA provided
|
||||
rootCA := s.TLSCertRoot.String
|
||||
caCert, err := ioutil.ReadFile(rootCA)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "issue reading root CA file: "+rootCA)
|
||||
}
|
||||
caCertPool := x509.NewCertPool()
|
||||
caCertPool.AppendCertsFromPEM(caCert)
|
||||
|
||||
config.RootCAs = caCertPool
|
||||
|
||||
return config, nil
|
||||
}
|
||||
|
||||
func (s *Service) Duration() time.Duration {
|
||||
return time.Duration(s.Interval) * time.Second
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package services
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"google.golang.org/grpc"
|
||||
"net"
|
||||
|
@ -14,7 +15,6 @@ import (
|
|||
"github.com/statping/statping/types/failures"
|
||||
"github.com/statping/statping/types/hits"
|
||||
"github.com/statping/statping/utils"
|
||||
"github.com/tatsushid/go-fastping"
|
||||
)
|
||||
|
||||
// checkServices will start the checking go routine for each service
|
||||
|
@ -89,35 +89,23 @@ func isIPv6(address string) bool {
|
|||
}
|
||||
|
||||
// checkIcmp will send a ICMP ping packet to the service
|
||||
func CheckIcmp(s *Service, record bool) *Service {
|
||||
func CheckIcmp(s *Service, record bool) (*Service, error) {
|
||||
defer s.updateLastCheck()
|
||||
|
||||
p := fastping.NewPinger()
|
||||
resolveIP := "ip4:icmp"
|
||||
if isIPv6(s.Domain) {
|
||||
resolveIP = "ip6:icmp"
|
||||
}
|
||||
ra, err := net.ResolveIPAddr(resolveIP, s.Domain)
|
||||
err := utils.Ping(s.Domain, s.Timeout)
|
||||
if err != nil {
|
||||
recordFailure(s, fmt.Sprintf("Could not send ICMP to service %v, %v", s.Domain, err))
|
||||
return s
|
||||
}
|
||||
p.AddIPAddr(ra)
|
||||
p.OnRecv = func(addr *net.IPAddr, rtt time.Duration) {
|
||||
s.Latency = rtt.Microseconds()
|
||||
recordSuccess(s)
|
||||
}
|
||||
err = p.Run()
|
||||
if err != nil {
|
||||
recordFailure(s, fmt.Sprintf("Issue running ICMP to service %v, %v", s.Domain, err))
|
||||
return s
|
||||
if record {
|
||||
recordFailure(s, fmt.Sprintf("Could not send ICMP to service %v, %v", s.Domain, err))
|
||||
}
|
||||
return s, err
|
||||
}
|
||||
s.LastResponse = ""
|
||||
return s
|
||||
s.Online = true
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// CheckGrpc will check a gRPC service
|
||||
func CheckGrpc(s *Service, record bool) *Service {
|
||||
func CheckGrpc(s *Service, record bool) (*Service, error) {
|
||||
defer s.updateLastCheck()
|
||||
|
||||
dnsLookup, err := dnsCheck(s)
|
||||
|
@ -125,7 +113,7 @@ func CheckGrpc(s *Service, record bool) *Service {
|
|||
if record {
|
||||
recordFailure(s, fmt.Sprintf("Could not get IP address for GRPC service %v, %v", s.Domain, err))
|
||||
}
|
||||
return s
|
||||
return s, err
|
||||
}
|
||||
s.PingTime = dnsLookup
|
||||
t1 := utils.Now()
|
||||
|
@ -144,25 +132,26 @@ func CheckGrpc(s *Service, record bool) *Service {
|
|||
if record {
|
||||
recordFailure(s, fmt.Sprintf("Dial Error %v", err))
|
||||
}
|
||||
return s
|
||||
return s, err
|
||||
}
|
||||
if err := conn.Close(); err != nil {
|
||||
if record {
|
||||
recordFailure(s, fmt.Sprintf("%v Socket Close Error %v", strings.ToUpper(s.Type), err))
|
||||
}
|
||||
return s
|
||||
return s, err
|
||||
}
|
||||
t2 := utils.Now()
|
||||
s.Latency = t2.Sub(t1).Microseconds()
|
||||
s.LastResponse = ""
|
||||
s.Online = true
|
||||
if record {
|
||||
recordSuccess(s)
|
||||
}
|
||||
return s
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// checkTcp will check a TCP service
|
||||
func CheckTcp(s *Service, record bool) *Service {
|
||||
func CheckTcp(s *Service, record bool) (*Service, error) {
|
||||
defer s.updateLastCheck()
|
||||
|
||||
dnsLookup, err := dnsCheck(s)
|
||||
|
@ -170,7 +159,7 @@ func CheckTcp(s *Service, record bool) *Service {
|
|||
if record {
|
||||
recordFailure(s, fmt.Sprintf("Could not get IP address for TCP service %v, %v", s.Domain, err))
|
||||
}
|
||||
return s
|
||||
return s, err
|
||||
}
|
||||
s.PingTime = dnsLookup
|
||||
t1 := utils.Now()
|
||||
|
@ -181,26 +170,46 @@ func CheckTcp(s *Service, record bool) *Service {
|
|||
domain = fmt.Sprintf("[%v]:%v", s.Domain, s.Port)
|
||||
}
|
||||
}
|
||||
conn, err := net.DialTimeout(s.Type, domain, time.Duration(s.Timeout)*time.Second)
|
||||
|
||||
tlsConfig, err := s.LoadTLSCert()
|
||||
if err != nil {
|
||||
if record {
|
||||
recordFailure(s, fmt.Sprintf("Dial Error %v", err))
|
||||
}
|
||||
return s
|
||||
log.Errorln(err)
|
||||
}
|
||||
if err := conn.Close(); err != nil {
|
||||
if record {
|
||||
recordFailure(s, fmt.Sprintf("%v Socket Close Error %v", strings.ToUpper(s.Type), err))
|
||||
|
||||
// test TCP connection if there is no TLS Certificate set
|
||||
if s.TLSCert.String == "" {
|
||||
conn, err := net.DialTimeout(s.Type, domain, time.Duration(s.Timeout)*time.Second)
|
||||
if err != nil {
|
||||
if record {
|
||||
recordFailure(s, fmt.Sprintf("Dial Error: %v", err))
|
||||
}
|
||||
return s, err
|
||||
}
|
||||
return s
|
||||
defer conn.Close()
|
||||
} else {
|
||||
// test TCP connection if TLS Certificate was set
|
||||
dialer := &net.Dialer{
|
||||
KeepAlive: time.Duration(s.Timeout) * time.Second,
|
||||
Timeout: time.Duration(s.Timeout) * time.Second,
|
||||
}
|
||||
conn, err := tls.DialWithDialer(dialer, s.Type, domain, tlsConfig)
|
||||
if err != nil {
|
||||
if record {
|
||||
recordFailure(s, fmt.Sprintf("Dial Error: %v", err))
|
||||
}
|
||||
return s, err
|
||||
}
|
||||
defer conn.Close()
|
||||
}
|
||||
|
||||
t2 := utils.Now()
|
||||
s.Latency = t2.Sub(t1).Microseconds()
|
||||
s.LastResponse = ""
|
||||
s.Online = true
|
||||
if record {
|
||||
recordSuccess(s)
|
||||
}
|
||||
return s
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func (s *Service) updateLastCheck() {
|
||||
|
@ -208,7 +217,7 @@ func (s *Service) updateLastCheck() {
|
|||
}
|
||||
|
||||
// checkHttp will check a HTTP service
|
||||
func CheckHttp(s *Service, record bool) *Service {
|
||||
func CheckHttp(s *Service, record bool) (*Service, error) {
|
||||
defer s.updateLastCheck()
|
||||
|
||||
dnsLookup, err := dnsCheck(s)
|
||||
|
@ -216,7 +225,7 @@ func CheckHttp(s *Service, record bool) *Service {
|
|||
if record {
|
||||
recordFailure(s, fmt.Sprintf("Could not get IP address for domain %v, %v", s.Domain, err))
|
||||
}
|
||||
return s
|
||||
return s, err
|
||||
}
|
||||
s.PingTime = dnsLookup
|
||||
t1 := utils.Now()
|
||||
|
@ -258,13 +267,17 @@ func CheckHttp(s *Service, record bool) *Service {
|
|||
contentType = "application/json"
|
||||
}
|
||||
|
||||
content, res, err = utils.HttpRequest(s.Domain, s.Method, contentType,
|
||||
headers, data, timeout, s.VerifySSL.Bool)
|
||||
customTLS, err := s.LoadTLSCert()
|
||||
if err != nil {
|
||||
log.Errorln(err)
|
||||
}
|
||||
|
||||
content, res, err = utils.HttpRequest(s.Domain, s.Method, contentType, headers, data, timeout, s.VerifySSL.Bool, customTLS)
|
||||
if err != nil {
|
||||
if record {
|
||||
recordFailure(s, fmt.Sprintf("HTTP Error %v", err))
|
||||
}
|
||||
return s
|
||||
return s, err
|
||||
}
|
||||
t2 := utils.Now()
|
||||
s.Latency = t2.Sub(t1).Microseconds()
|
||||
|
@ -280,19 +293,20 @@ func CheckHttp(s *Service, record bool) *Service {
|
|||
if record {
|
||||
recordFailure(s, fmt.Sprintf("HTTP Response Body did not match '%v'", s.Expected))
|
||||
}
|
||||
return s
|
||||
return s, err
|
||||
}
|
||||
}
|
||||
if s.ExpectedStatus != res.StatusCode {
|
||||
if record {
|
||||
recordFailure(s, fmt.Sprintf("HTTP Status Code %v did not match %v", res.StatusCode, s.ExpectedStatus))
|
||||
}
|
||||
return s
|
||||
return s, err
|
||||
}
|
||||
if record {
|
||||
recordSuccess(s)
|
||||
}
|
||||
return s
|
||||
s.Online = true
|
||||
return s, err
|
||||
}
|
||||
|
||||
// recordSuccess will create a new 'hit' record in the database for a successful/online service
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
)
|
||||
|
||||
func Samples() error {
|
||||
log.Infoln("Inserting Sample Services...")
|
||||
createdOn := utils.Now().Add(((-24 * 30) * 3) * time.Hour)
|
||||
s1 := &Service{
|
||||
Name: "Google",
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
package services
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/statping/statping/database"
|
||||
"github.com/statping/statping/types/checkins"
|
||||
"github.com/statping/statping/types/failures"
|
||||
|
@ -10,6 +13,10 @@ import (
|
|||
"github.com/statping/statping/utils"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"google.golang.org/grpc"
|
||||
pb "google.golang.org/grpc/examples/route_guide/routeguide"
|
||||
"net"
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
@ -77,6 +84,83 @@ var fail2 = &failures.Failure{
|
|||
CreatedAt: utils.Now().Add(-5 * time.Second),
|
||||
}
|
||||
|
||||
type exampleGRPC struct {
|
||||
pb.UnimplementedRouteGuideServer
|
||||
}
|
||||
|
||||
func (s *exampleGRPC) GetFeature(ctx context.Context, point *pb.Point) (*pb.Feature, error) {
|
||||
return &pb.Feature{Location: point}, nil
|
||||
}
|
||||
|
||||
func TestStartExampleEndpoints(t *testing.T) {
|
||||
// root CA for Linux: /etc/ssl/certs/ca-certificates.crt
|
||||
// root CA for MacOSX: /opt/local/share/curl/curl-ca-bundle.crt
|
||||
|
||||
tlsCert := utils.Params.GetString("STATPING_DIR") + "/cert.pem"
|
||||
tlsCertKey := utils.Params.GetString("STATPING_DIR") + "/key.pem"
|
||||
|
||||
require.FileExists(t, tlsCert)
|
||||
require.FileExists(t, tlsCertKey)
|
||||
|
||||
h := func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte("ok"))
|
||||
}
|
||||
|
||||
r := mux.NewRouter()
|
||||
r.HandleFunc("/", h)
|
||||
|
||||
// start example HTTP server
|
||||
go func(t *testing.T) {
|
||||
require.Nil(t, http.ListenAndServe(":15000", r))
|
||||
}(t)
|
||||
|
||||
// start example TLS HTTP server
|
||||
go func(t *testing.T) {
|
||||
require.Nil(t, http.ListenAndServeTLS(":15001", tlsCert, tlsCertKey, r))
|
||||
}(t)
|
||||
|
||||
tcpHandle := func(conn net.Conn) {
|
||||
defer conn.Close()
|
||||
conn.Write([]byte("ok"))
|
||||
}
|
||||
|
||||
// start TCP server
|
||||
go func(t *testing.T, hdl func(conn net.Conn)) {
|
||||
ln, err := net.Listen("tcp", ":15002")
|
||||
require.Nil(t, err)
|
||||
for {
|
||||
conn, err := ln.Accept()
|
||||
require.Nil(t, err)
|
||||
go hdl(conn)
|
||||
}
|
||||
}(t, tcpHandle)
|
||||
|
||||
// start TLS TCP server
|
||||
go func(t *testing.T, hdl func(conn net.Conn)) {
|
||||
cer, err := tls.LoadX509KeyPair(tlsCert, tlsCertKey)
|
||||
require.Nil(t, err)
|
||||
ln, err := tls.Listen("tcp", ":15003", &tls.Config{Certificates: []tls.Certificate{cer}})
|
||||
require.Nil(t, err)
|
||||
for {
|
||||
conn, err := ln.Accept()
|
||||
require.Nil(t, err)
|
||||
go hdl(conn)
|
||||
}
|
||||
}(t, tcpHandle)
|
||||
|
||||
// start GRPC server
|
||||
go func(t *testing.T) {
|
||||
list, err := net.Listen("tcp", ":15004")
|
||||
require.Nil(t, err)
|
||||
grpcServer := grpc.NewServer()
|
||||
pb.RegisterRouteGuideServer(grpcServer, &exampleGRPC{})
|
||||
require.Nil(t, grpcServer.Serve(list))
|
||||
}(t)
|
||||
|
||||
time.Sleep(15 * time.Second)
|
||||
}
|
||||
|
||||
func TestServices(t *testing.T) {
|
||||
db, err := database.OpenTester()
|
||||
require.Nil(t, err)
|
||||
|
@ -93,6 +177,9 @@ func TestServices(t *testing.T) {
|
|||
hits.SetDB(db)
|
||||
SetDB(db)
|
||||
|
||||
tlsCert := utils.Params.GetString("STATPING_DIR") + "/cert.pem"
|
||||
tlsCertKey := utils.Params.GetString("STATPING_DIR") + "/key.pem"
|
||||
|
||||
t.Run("Test Find service", func(t *testing.T) {
|
||||
item, err := Find(1)
|
||||
require.Nil(t, err)
|
||||
|
@ -102,6 +189,147 @@ func TestServices(t *testing.T) {
|
|||
assert.NotZero(t, item.LastCheck)
|
||||
})
|
||||
|
||||
t.Run("Test HTTP Check", func(t *testing.T) {
|
||||
e := &Service{
|
||||
Name: "Example HTTP",
|
||||
Domain: "http://localhost:15000",
|
||||
ExpectedStatus: 200,
|
||||
Type: "http",
|
||||
Method: "GET",
|
||||
Timeout: 5,
|
||||
VerifySSL: null.NewNullBool(false),
|
||||
}
|
||||
e, err = CheckHttp(e, false)
|
||||
require.Nil(t, err)
|
||||
assert.True(t, e.Online)
|
||||
assert.False(t, e.LastCheck.IsZero())
|
||||
assert.NotEqual(t, 0, e.PingTime)
|
||||
assert.NotEqual(t, 0, e.Latency)
|
||||
})
|
||||
|
||||
t.Run("Test Load TLS Certificates", func(t *testing.T) {
|
||||
e := &Service{
|
||||
Name: "Example TLS",
|
||||
Domain: "http://localhost:15001",
|
||||
ExpectedStatus: 200,
|
||||
Type: "http",
|
||||
Method: "GET",
|
||||
Timeout: 5,
|
||||
VerifySSL: null.NewNullBool(false),
|
||||
TLSCert: null.NewNullString(tlsCert),
|
||||
TLSCertKey: null.NewNullString(tlsCertKey),
|
||||
}
|
||||
customTLS, err := e.LoadTLSCert()
|
||||
require.Nil(t, err)
|
||||
|
||||
require.NotNil(t, customTLS)
|
||||
assert.Nil(t, customTLS.RootCAs)
|
||||
assert.NotNil(t, customTLS.Certificates)
|
||||
assert.Equal(t, 1, len(customTLS.Certificates))
|
||||
})
|
||||
|
||||
t.Run("Test TLS HTTP Check", func(t *testing.T) {
|
||||
e := &Service{
|
||||
Name: "Example TLS HTTP",
|
||||
Domain: "https://localhost:15001",
|
||||
ExpectedStatus: 200,
|
||||
Type: "http",
|
||||
Method: "GET",
|
||||
Timeout: 15,
|
||||
VerifySSL: null.NewNullBool(false),
|
||||
TLSCert: null.NewNullString(tlsCert),
|
||||
TLSCertKey: null.NewNullString(tlsCertKey),
|
||||
}
|
||||
e, err = CheckHttp(e, false)
|
||||
require.Nil(t, err)
|
||||
assert.True(t, e.Online)
|
||||
assert.False(t, e.LastCheck.IsZero())
|
||||
assert.NotEqual(t, 0, e.PingTime)
|
||||
assert.NotEqual(t, 0, e.Latency)
|
||||
})
|
||||
|
||||
t.Run("Test TCP Check", func(t *testing.T) {
|
||||
e := &Service{
|
||||
Name: "Example TCP",
|
||||
Domain: "localhost",
|
||||
Port: 15002,
|
||||
Type: "tcp",
|
||||
Timeout: 5,
|
||||
}
|
||||
e, err = CheckTcp(e, false)
|
||||
require.Nil(t, err)
|
||||
assert.True(t, e.Online)
|
||||
assert.False(t, e.LastCheck.IsZero())
|
||||
assert.NotEqual(t, 0, e.PingTime)
|
||||
assert.NotEqual(t, 0, e.Latency)
|
||||
})
|
||||
|
||||
t.Run("Test TLS TCP Check", func(t *testing.T) {
|
||||
e := &Service{
|
||||
Name: "Example TLS TCP",
|
||||
Domain: "localhost",
|
||||
Port: 15003,
|
||||
Type: "tcp",
|
||||
Timeout: 15,
|
||||
TLSCert: null.NewNullString(tlsCert),
|
||||
TLSCertKey: null.NewNullString(tlsCertKey),
|
||||
}
|
||||
e, err = CheckTcp(e, false)
|
||||
require.Nil(t, err)
|
||||
assert.True(t, e.Online)
|
||||
assert.False(t, e.LastCheck.IsZero())
|
||||
assert.NotEqual(t, 0, e.PingTime)
|
||||
assert.NotEqual(t, 0, e.Latency)
|
||||
})
|
||||
|
||||
t.Run("Test UDP Check", func(t *testing.T) {
|
||||
e := &Service{
|
||||
Name: "Example UDP",
|
||||
Domain: "localhost",
|
||||
Port: 15003,
|
||||
Type: "udp",
|
||||
Timeout: 5,
|
||||
}
|
||||
e, err = CheckTcp(e, false)
|
||||
require.Nil(t, err)
|
||||
assert.True(t, e.Online)
|
||||
assert.False(t, e.LastCheck.IsZero())
|
||||
assert.NotEqual(t, 0, e.PingTime)
|
||||
assert.NotEqual(t, 0, e.Latency)
|
||||
})
|
||||
|
||||
t.Run("Test gRPC Check", func(t *testing.T) {
|
||||
e := &Service{
|
||||
Name: "Example gRPC",
|
||||
Domain: "localhost",
|
||||
Port: 15004,
|
||||
Type: "grpc",
|
||||
Timeout: 5,
|
||||
}
|
||||
e, err = CheckGrpc(e, false)
|
||||
require.Nil(t, err)
|
||||
assert.True(t, e.Online)
|
||||
assert.False(t, e.LastCheck.IsZero())
|
||||
assert.NotEqual(t, 0, e.PingTime)
|
||||
assert.NotEqual(t, 0, e.Latency)
|
||||
})
|
||||
|
||||
t.Run("Test ICMP Check", func(t *testing.T) {
|
||||
t.SkipNow()
|
||||
e := &Service{
|
||||
Name: "Example ICMP",
|
||||
Domain: "localhost",
|
||||
Type: "icmp",
|
||||
Timeout: 5,
|
||||
}
|
||||
e, err = CheckIcmp(e, false)
|
||||
require.Nil(t, err)
|
||||
assert.True(t, e.Online)
|
||||
assert.False(t, e.LastCheck.IsZero())
|
||||
assert.NotEqual(t, 0, e.PingTime)
|
||||
assert.NotEqual(t, 0, e.Latency)
|
||||
})
|
||||
|
||||
t.Run("Test All", func(t *testing.T) {
|
||||
items := All()
|
||||
assert.Len(t, items, 1)
|
||||
|
@ -172,10 +400,10 @@ func TestServices(t *testing.T) {
|
|||
item, err := Find(1)
|
||||
require.Nil(t, err)
|
||||
|
||||
count := item.HitsSince(utils.Now().Add(-30 * time.Second))
|
||||
count := item.HitsSince(utils.Now().Add(-60 * time.Second))
|
||||
assert.Equal(t, 1, count.Count())
|
||||
|
||||
count = item.HitsSince(utils.Now().Add(-180 * time.Second))
|
||||
count = item.HitsSince(utils.Now().Add(-360 * time.Second))
|
||||
assert.Equal(t, 3, count.Count())
|
||||
})
|
||||
|
||||
|
@ -205,7 +433,7 @@ func TestServices(t *testing.T) {
|
|||
item, err := Find(1)
|
||||
require.Nil(t, err)
|
||||
|
||||
count := item.FailuresSince(utils.Now().Add(-6 * time.Second))
|
||||
count := item.FailuresSince(utils.Now().Add(-30 * time.Second))
|
||||
assert.Equal(t, 1, count.Count())
|
||||
|
||||
count = item.FailuresSince(utils.Now().Add(-180 * time.Second))
|
||||
|
|
|
@ -37,6 +37,9 @@ type Service struct {
|
|||
VerifySSL null.NullBool `gorm:"default:false;column:verify_ssl" json:"verify_ssl" scope:"user,admin" yaml:"verify_ssl"`
|
||||
Public null.NullBool `gorm:"default:true;column:public" json:"public" yaml:"public"`
|
||||
GroupId int `gorm:"default:0;column:group_id" json:"group_id" yaml:"group_id"`
|
||||
TLSCert null.NullString `gorm:"column:tls_cert" json:"tls_cert" scope:"user,admin" yaml:"tls_cert"`
|
||||
TLSCertKey null.NullString `gorm:"column:tls_cert_key" json:"tls_cert_key" scope:"user,admin" yaml:"tls_cert_key"`
|
||||
TLSCertRoot null.NullString `gorm:"column:tls_cert_root" json:"tls_cert_root" scope:"user,admin" yaml:"tls_cert_root"`
|
||||
Headers null.NullString `gorm:"column:headers" json:"headers" scope:"user,admin" yaml:"headers"`
|
||||
Permalink null.NullString `gorm:"column:permalink;unique;" json:"permalink" yaml:"permalink"`
|
||||
Redirect null.NullBool `gorm:"default:false;column:redirect" json:"redirect" scope:"user,admin" yaml:"redirect"`
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
)
|
||||
|
||||
func Samples() error {
|
||||
log.Infoln("Inserting Sample Users...")
|
||||
u2 := &User{
|
||||
Username: "testadmin",
|
||||
Password: "password123",
|
||||
|
|
|
@ -7,15 +7,16 @@ import (
|
|||
)
|
||||
|
||||
var (
|
||||
Params *viper.Viper
|
||||
Params *viper.Viper
|
||||
configLog = Log.WithField("type", "configs")
|
||||
)
|
||||
|
||||
func InitCLI() {
|
||||
Params = viper.New()
|
||||
Params.AutomaticEnv()
|
||||
setDefaults()
|
||||
Directory = Params.GetString("STATPING_DIR")
|
||||
//Params.SetEnvKeyReplacer(strings.NewReplacer("-", "_"))
|
||||
setDefaults()
|
||||
Params.SetConfigName("config")
|
||||
Params.SetConfigType("yml")
|
||||
Params.AddConfigPath(Directory)
|
||||
|
@ -30,16 +31,12 @@ func InitCLI() {
|
|||
}
|
||||
|
||||
func setDefaults() {
|
||||
if Directory == "" {
|
||||
defaultDir, err := os.Getwd()
|
||||
if err != nil {
|
||||
defaultDir = "."
|
||||
}
|
||||
Params.SetDefault("STATPING_DIR", defaultDir)
|
||||
Directory = defaultDir
|
||||
defaultDir, err := os.Getwd()
|
||||
if err != nil {
|
||||
configLog.Errorln(err)
|
||||
defaultDir = "."
|
||||
}
|
||||
Directory = Params.GetString("STATPING_DIR")
|
||||
Params.SetDefault("STATPING_DIR", Directory)
|
||||
Params.SetDefault("STATPING_DIR", defaultDir)
|
||||
Params.SetDefault("GO_ENV", "")
|
||||
Params.SetDefault("DB_CONN", "")
|
||||
Params.SetDefault("DISABLE_LOGS", false)
|
||||
|
@ -54,8 +51,12 @@ func setDefaults() {
|
|||
Params.SetDefault("USE_CDN", false)
|
||||
Params.SetDefault("ALLOW_REPORTS", false)
|
||||
Params.SetDefault("POSTGRES_SSLMODE", "disable")
|
||||
Params.SetDefault("NAME", "Statping Sample Data")
|
||||
Params.SetDefault("DOMAIN", "http://localhost:8080")
|
||||
Params.SetDefault("DESCRIPTION", "This status page has sample data included")
|
||||
Params.SetDefault("REMOVE_AFTER", 2160*time.Hour)
|
||||
Params.SetDefault("CLEANUP_INTERVAL", 1*time.Hour)
|
||||
Params.SetDefault("LANGUAGE", "en")
|
||||
|
||||
dbConn := Params.GetString("DB_CONN")
|
||||
dbInt := Params.GetInt("DB_PORT")
|
||||
|
|
|
@ -3,6 +3,7 @@ package utils
|
|||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// DeleteDirectory will attempt to delete a directory and all contents inside
|
||||
|
@ -30,6 +31,15 @@ func FolderExists(folder string) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
// FileExtension returns the file extension based on a file path
|
||||
func FileExtension(path string) string {
|
||||
s := strings.Split(path, ".")
|
||||
if len(s) == 0 {
|
||||
return ""
|
||||
}
|
||||
return s[len(s)-1]
|
||||
}
|
||||
|
||||
// FileExists returns true if a file exists
|
||||
// exists := FileExists("assets/css/base.css")
|
||||
func FileExists(name string) bool {
|
||||
|
|
|
@ -197,7 +197,7 @@ func DurationReadable(d time.Duration) string {
|
|||
// // body - The body or form data to send with HTTP request
|
||||
// // timeout - Specific duration to timeout on. time.Duration(30 * time.Seconds)
|
||||
// // You can use a HTTP Proxy if you HTTP_PROXY environment variable
|
||||
func HttpRequest(url, method string, content interface{}, headers []string, body io.Reader, timeout time.Duration, verifySSL bool) ([]byte, *http.Response, error) {
|
||||
func HttpRequest(url, method string, content interface{}, headers []string, body io.Reader, timeout time.Duration, verifySSL bool, customTLS *tls.Config) ([]byte, *http.Response, error) {
|
||||
var err error
|
||||
var req *http.Request
|
||||
t1 := Now()
|
||||
|
@ -247,6 +247,10 @@ func HttpRequest(url, method string, content interface{}, headers []string, body
|
|||
return dialer.DialContext(ctx, network, addr)
|
||||
},
|
||||
}
|
||||
if customTLS != nil {
|
||||
transport.TLSClientConfig.RootCAs = customTLS.RootCAs
|
||||
transport.TLSClientConfig.Certificates = customTLS.Certificates
|
||||
}
|
||||
client := &http.Client{
|
||||
Transport: transport,
|
||||
Timeout: timeout,
|
||||
|
|
|
@ -4,7 +4,10 @@ package utils
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
|
@ -32,3 +35,21 @@ func DirWritable(path string) (bool, error) {
|
|||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func Ping(address string, secondsTimeout int) error {
|
||||
ping, err := exec.LookPath("ping")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
out, _, err := Command(ping, address, "-c 1", fmt.Sprintf("-W %v", secondsTimeout))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if strings.Contains(out, "Unknown host") {
|
||||
return errors.New("unknown host")
|
||||
}
|
||||
if strings.Contains(out, "100.0% packet loss") {
|
||||
return errors.New("destination host unreachable")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -174,7 +174,7 @@ func TestHttpRequest(t *testing.T) {
|
|||
// Close the server when test finishes
|
||||
defer server.Close()
|
||||
|
||||
body, resp, err := HttpRequest(server.URL, "GET", "application/json", []string{"aaa=bbbb=", "ccc=ddd"}, nil, 2*time.Second, false)
|
||||
body, resp, err := HttpRequest(server.URL, "GET", "application/json", []string{"aaa=bbbb=", "ccc=ddd"}, nil, 2*time.Second, false, nil)
|
||||
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, []byte("OK"), body)
|
||||
|
|
|
@ -2,7 +2,10 @@ package utils
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func DirWritable(path string) (bool, error) {
|
||||
|
@ -21,3 +24,18 @@ func DirWritable(path string) (bool, error) {
|
|||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func Ping(address string, secondsTimeout int) error {
|
||||
ping, err := exec.LookPath("ping")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
out, _, err := Command(ping, address, "-n 1", fmt.Sprintf("-w %v", secondsTimeout*1000))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if strings.Contains(out, "Destination Host Unreachable") {
|
||||
return errors.New("destination host unreachable")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -1 +1 @@
|
|||
0.90.39
|
||||
0.90.45
|
||||
|
|
Loading…
Reference in New Issue