Compare commits
No commits in common. "master" and "master" have entirely different histories.
@ -1,68 +0,0 @@
|
|||||||
kind: pipeline
|
|
||||||
name: Build Application
|
|
||||||
steps:
|
|
||||||
- name: Build
|
|
||||||
image: golang:1.14
|
|
||||||
commands:
|
|
||||||
- go build ./...
|
|
||||||
volumes:
|
|
||||||
- name: deps
|
|
||||||
path: /go
|
|
||||||
- name: Test
|
|
||||||
image: golang:1.14
|
|
||||||
commands:
|
|
||||||
- go test ./...
|
|
||||||
volumes:
|
|
||||||
- name: deps
|
|
||||||
path: /go
|
|
||||||
- name: Lint
|
|
||||||
image: golangci/golangci-lint:v1.25.0
|
|
||||||
commands:
|
|
||||||
- golangci-lint run -v
|
|
||||||
volumes:
|
|
||||||
- name: deps
|
|
||||||
path: /go
|
|
||||||
|
|
||||||
volumes:
|
|
||||||
- name: deps
|
|
||||||
temp: {}
|
|
||||||
|
|
||||||
---
|
|
||||||
kind: pipeline
|
|
||||||
name: Build Docker Image
|
|
||||||
steps:
|
|
||||||
- name: Build Docker Image
|
|
||||||
image: plugins/docker
|
|
||||||
settings:
|
|
||||||
registry: docker.teamortix.com
|
|
||||||
username: droneci
|
|
||||||
password:
|
|
||||||
from_secret: docker_password
|
|
||||||
repo: docker.teamortix.com/teamortix/status
|
|
||||||
tags: test
|
|
||||||
purge: true
|
|
||||||
trigger:
|
|
||||||
event:
|
|
||||||
exclude:
|
|
||||||
- tag
|
|
||||||
depends_on:
|
|
||||||
- Build Application
|
|
||||||
|
|
||||||
---
|
|
||||||
kind: pipeline
|
|
||||||
name: Continuous Deployment
|
|
||||||
steps:
|
|
||||||
- name: Deploy Docker Image
|
|
||||||
image: plugins/docker
|
|
||||||
settings:
|
|
||||||
registry: docker.teamortix.com
|
|
||||||
username: droneci
|
|
||||||
password:
|
|
||||||
from_secret: docker_password
|
|
||||||
repo: docker.teamortix.com/teamortix/status
|
|
||||||
auto_tag: true
|
|
||||||
trigger:
|
|
||||||
event:
|
|
||||||
- tag
|
|
||||||
depends_on:
|
|
||||||
- Build Application
|
|
@ -1,10 +0,0 @@
|
|||||||
FROM golang:1.14.2 AS build
|
|
||||||
WORKDIR /root/
|
|
||||||
COPY . .
|
|
||||||
RUN go build -o Status .
|
|
||||||
|
|
||||||
FROM golang:1.14.2
|
|
||||||
WORKDIR /root/
|
|
||||||
COPY --from=build /root/Status .
|
|
||||||
EXPOSE 8080
|
|
||||||
CMD ["./Status"]
|
|
@ -1,18 +1,9 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
|
||||||
"status/server"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
cfg, err := ReadConfig("config.json")
|
cfg, err := ReadConfig("config.json")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
go checkLoop(cfg.Targets)
|
checkLoop(cfg.Targets)
|
||||||
validServices := make([]string, 0, len(cfg.Targets))
|
|
||||||
for _, v := range cfg.Targets {
|
|
||||||
validServices = append(validServices, v.ServiceName)
|
|
||||||
}
|
|
||||||
server.StartServer(cfg.Port, validServices)
|
|
||||||
}
|
}
|
||||||
|
@ -1,102 +0,0 @@
|
|||||||
package server
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"net/http"
|
|
||||||
"strconv"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"status/db"
|
|
||||||
)
|
|
||||||
|
|
||||||
func writeJSON(w http.ResponseWriter, a interface{}) {
|
|
||||||
bytes, err := json.Marshal(a)
|
|
||||||
if err != nil {
|
|
||||||
http.Error(w, "500 Internal Server Error", http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
|
||||||
_, err = w.Write(bytes)
|
|
||||||
if err != nil {
|
|
||||||
http.Error(w, "500 Internal Server Error", http.StatusInternalServerError)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func allStatus(w http.ResponseWriter, req *http.Request) {
|
|
||||||
status := getStatus()
|
|
||||||
writeJSON(w, status)
|
|
||||||
}
|
|
||||||
|
|
||||||
func dayHistory(w http.ResponseWriter, req *http.Request) {
|
|
||||||
keys, ok := req.URL.Query()["service_name"]
|
|
||||||
if !ok || len(keys) == 0 || len(keys[0]) < 1 {
|
|
||||||
http.Error(w, "`service_name` not provided", http.StatusBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if len(keys) >= 2 {
|
|
||||||
http.Error(w, "Only one `service_name` allowed", http.StatusBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
service_name := keys[0]
|
|
||||||
if !validTarget[service_name] {
|
|
||||||
http.Error(w, "Invalid `service_name` requested", http.StatusBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
keys, ok = req.URL.Query()["interval"]
|
|
||||||
var interval = 5
|
|
||||||
if len(keys) >= 2 {
|
|
||||||
http.Error(w, "Only one `interval` allowed", http.StatusBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if ok && len(keys) == 1 && len(keys[0]) >= 1 {
|
|
||||||
var err error
|
|
||||||
interval, err = strconv.Atoi(keys[0])
|
|
||||||
if err != nil || interval < 1 || interval > 1440 {
|
|
||||||
http.Error(w, "Invalid `interval` provided. Must be integer in [1, 1440]", http.StatusBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if service_name == "all" {
|
|
||||||
service_name = ""
|
|
||||||
}
|
|
||||||
entries := db.GetFromDB(service_name, time.Now().Add(time.Duration(-24)*time.Hour), time.Now())
|
|
||||||
if interval == 1 {
|
|
||||||
writeJSON(w, entries)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
filteredEntries := make([]db.PingEntry, 0, len(entries)/interval)
|
|
||||||
for i := 0; i < len(entries); i += interval {
|
|
||||||
filteredEntries = append(filteredEntries, entries[i])
|
|
||||||
}
|
|
||||||
writeJSON(w, filteredEntries)
|
|
||||||
}
|
|
||||||
|
|
||||||
func weekHistory(w http.ResponseWriter, req *http.Request) {
|
|
||||||
history(w, req, 7)
|
|
||||||
}
|
|
||||||
|
|
||||||
func monthHistory(w http.ResponseWriter, req *http.Request) {
|
|
||||||
history(w, req, 31)
|
|
||||||
}
|
|
||||||
|
|
||||||
func yearHistory(w http.ResponseWriter, req *http.Request) {
|
|
||||||
history(w, req, 366)
|
|
||||||
}
|
|
||||||
|
|
||||||
func history(w http.ResponseWriter, req *http.Request, dayCount int) {
|
|
||||||
keys, ok := req.URL.Query()["service_name"]
|
|
||||||
if !ok || len(keys) == 0 || len(keys[0]) < 1 {
|
|
||||||
http.Error(w, "`service_name` not provided", http.StatusBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if len(keys) >= 2 {
|
|
||||||
http.Error(w, "Only one `service_name` allowed", http.StatusBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if !validTarget[keys[0]] {
|
|
||||||
http.Error(w, "Invalid `service_name` requested", http.StatusBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
entries := getHistoryDay(keys[0], dayCount)
|
|
||||||
writeJSON(w, entries)
|
|
||||||
}
|
|
@ -1,60 +0,0 @@
|
|||||||
package server
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"status/check"
|
|
||||||
"status/db"
|
|
||||||
)
|
|
||||||
|
|
||||||
type stat struct {
|
|
||||||
StartTime time.Time `json:"start_time"`
|
|
||||||
TotalPing int64 `json:"total_ping"`
|
|
||||||
SampleCount int `json:"sample_count"`
|
|
||||||
SuccessCount int `json:"success_count"`
|
|
||||||
FailCount int `json:"fail_count"`
|
|
||||||
Summary check.Result `json:"summary"`
|
|
||||||
}
|
|
||||||
|
|
||||||
var dayAggregation = make(map[string]map[time.Time]stat)
|
|
||||||
|
|
||||||
func convertToResult(successCount, totalCount int) check.Result {
|
|
||||||
if successCount >= totalCount*99/100 {
|
|
||||||
return check.Online
|
|
||||||
}
|
|
||||||
if successCount >= totalCount*9/10 {
|
|
||||||
return check.Unstable
|
|
||||||
}
|
|
||||||
return check.Offline
|
|
||||||
}
|
|
||||||
|
|
||||||
func getDay(serviceName string, day time.Time) stat {
|
|
||||||
if _, ok := dayAggregation[serviceName]; !ok {
|
|
||||||
dayAggregation[serviceName] = make(map[time.Time]stat)
|
|
||||||
}
|
|
||||||
if cached, ok := dayAggregation[serviceName][day]; ok {
|
|
||||||
return cached
|
|
||||||
}
|
|
||||||
entries := db.GetFromDB(serviceName, day.AddDate(0, 0, -1), day)
|
|
||||||
result := stat{
|
|
||||||
StartTime: day,
|
|
||||||
}
|
|
||||||
for _, v := range entries {
|
|
||||||
result.SampleCount++
|
|
||||||
result.TotalPing += v.Ping
|
|
||||||
switch v.Status {
|
|
||||||
case check.Online:
|
|
||||||
result.SuccessCount++
|
|
||||||
case check.Offline:
|
|
||||||
result.FailCount++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result.Summary = convertToResult(result.SuccessCount, result.SampleCount)
|
|
||||||
dayAggregation[serviceName][day] = result
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
func today() time.Time {
|
|
||||||
now := time.Now()
|
|
||||||
return time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.UTC)
|
|
||||||
}
|
|
@ -1,33 +0,0 @@
|
|||||||
package server
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"status/db"
|
|
||||||
)
|
|
||||||
|
|
||||||
func getStatus() map[string]db.PingEntry {
|
|
||||||
entries := db.GetFromDB("", time.Now().Add(time.Duration(-2)*time.Minute), time.Now())
|
|
||||||
result := make(map[string]db.PingEntry)
|
|
||||||
for _, v := range entries {
|
|
||||||
if v.Time.Before(result[v.ServiceName].Time) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
result[v.ServiceName] = v
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
func getHistoryDay(serviceName string, dayCount int) []stat {
|
|
||||||
currentDay := today()
|
|
||||||
result := make([]stat, 0)
|
|
||||||
for i := 0; i >= -dayCount+1; i-- {
|
|
||||||
dayData := getDay(serviceName, currentDay.AddDate(0, 0, i))
|
|
||||||
if dayData.SampleCount > 0 {
|
|
||||||
result = append(result, dayData)
|
|
||||||
} else {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
@ -1,30 +0,0 @@
|
|||||||
package server
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"strconv"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
validTarget = make(map[string]bool)
|
|
||||||
)
|
|
||||||
|
|
||||||
func apiEndpoints() {
|
|
||||||
http.HandleFunc("/api/latest", allStatus)
|
|
||||||
http.HandleFunc("/api/history/day", dayHistory)
|
|
||||||
http.HandleFunc("/api/history/week", weekHistory)
|
|
||||||
http.HandleFunc("/api/history/month", monthHistory)
|
|
||||||
http.HandleFunc("/api/history/year", yearHistory)
|
|
||||||
}
|
|
||||||
|
|
||||||
func StartServer(port int, validTargets []string) {
|
|
||||||
for _, v := range validTargets {
|
|
||||||
validTarget[v] = true
|
|
||||||
}
|
|
||||||
apiEndpoints()
|
|
||||||
err := http.ListenAndServe(":"+strconv.Itoa(port), nil)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("ListenAndServe returned an error: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue