mirror of https://github.com/statping/statping
checkins - installer shell script
parent
9a6c91a997
commit
ddb2a10a7c
|
@ -20,6 +20,7 @@ import (
|
||||||
"github.com/ararog/timeago"
|
"github.com/ararog/timeago"
|
||||||
"github.com/hunterlong/statup/types"
|
"github.com/hunterlong/statup/types"
|
||||||
"github.com/hunterlong/statup/utils"
|
"github.com/hunterlong/statup/utils"
|
||||||
|
"github.com/jinzhu/gorm"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -49,17 +50,17 @@ func SelectCheckin(api string) *Checkin {
|
||||||
return &checkin
|
return &checkin
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u Checkin) Period() time.Duration {
|
func (u *Checkin) Period() time.Duration {
|
||||||
duration, _ := time.ParseDuration(fmt.Sprintf("%vs", u.Interval))
|
duration, _ := time.ParseDuration(fmt.Sprintf("%vs", u.Interval))
|
||||||
return duration
|
return duration
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u Checkin) Grace() time.Duration {
|
func (u *Checkin) Grace() time.Duration {
|
||||||
duration, _ := time.ParseDuration(fmt.Sprintf("%vs", u.GracePeriod))
|
duration, _ := time.ParseDuration(fmt.Sprintf("%vs", u.GracePeriod))
|
||||||
return duration
|
return duration
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u Checkin) Expected() time.Duration {
|
func (u *Checkin) Expected() time.Duration {
|
||||||
last := u.Last().CreatedAt
|
last := u.Last().CreatedAt
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
lastDir := now.Sub(last)
|
lastDir := now.Sub(last)
|
||||||
|
@ -67,7 +68,7 @@ func (u Checkin) Expected() time.Duration {
|
||||||
return sub
|
return sub
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u Checkin) Last() CheckinHit {
|
func (u *Checkin) Last() CheckinHit {
|
||||||
var hit CheckinHit
|
var hit CheckinHit
|
||||||
checkinHitsDB().Where("checkin = ?", u.Id).Last(&hit)
|
checkinHitsDB().Where("checkin = ?", u.Id).Last(&hit)
|
||||||
return hit
|
return hit
|
||||||
|
@ -79,13 +80,18 @@ func (u *Checkin) Hits() []CheckinHit {
|
||||||
return checkins
|
return checkins
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *Checkin) Create() (int64, error) {
|
func (u *Checkin) Update() (int64, error) {
|
||||||
if u.CreatedAt.IsZero() {
|
fmt.Println("updating: ", u.Id, u.ApiKey)
|
||||||
u.CreatedAt = time.Now()
|
exists := checkinDB().Find(&u).RecordNotFound()
|
||||||
|
var row *gorm.DB
|
||||||
|
if !exists {
|
||||||
|
row = checkinDB().Update(&u)
|
||||||
|
} else {
|
||||||
|
u.ApiKey = utils.RandomString(7)
|
||||||
|
row = checkinDB().Create(&u)
|
||||||
}
|
}
|
||||||
u.ApiKey = utils.NewSHA1Hash(7)
|
fmt.Println("found: ", exists, u.Id, u.Service, u.Interval, u.GracePeriod, u.ApiKey)
|
||||||
row := checkinDB().Create(u)
|
if row.Error != nil {
|
||||||
if row.Error == nil {
|
|
||||||
utils.Log(2, row.Error)
|
utils.Log(2, row.Error)
|
||||||
return 0, row.Error
|
return 0, row.Error
|
||||||
}
|
}
|
||||||
|
|
|
@ -126,27 +126,37 @@ func (u *Hit) BeforeCreate() (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *Failure) BeforeCreate() (err error) {
|
func (u *Failure) BeforeCreate() (err error) {
|
||||||
u.CreatedAt = time.Now().UTC()
|
if u.CreatedAt.IsZero() {
|
||||||
|
u.CreatedAt = time.Now().UTC()
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *User) BeforeCreate() (err error) {
|
func (u *User) BeforeCreate() (err error) {
|
||||||
u.CreatedAt = time.Now().UTC()
|
if u.CreatedAt.IsZero() {
|
||||||
|
u.CreatedAt = time.Now().UTC()
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *Service) BeforeCreate() (err error) {
|
func (u *Service) BeforeCreate() (err error) {
|
||||||
u.CreatedAt = time.Now().UTC()
|
if u.CreatedAt.IsZero() {
|
||||||
|
u.CreatedAt = time.Now().UTC()
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *Checkin) BeforeCreate() (err error) {
|
func (u *Checkin) BeforeCreate() (err error) {
|
||||||
u.CreatedAt = time.Now().UTC()
|
if u.CreatedAt.IsZero() {
|
||||||
|
u.CreatedAt = time.Now().UTC()
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *CheckinHit) BeforeCreate() (err error) {
|
func (u *CheckinHit) BeforeCreate() (err error) {
|
||||||
u.CreatedAt = time.Now().UTC()
|
if u.CreatedAt.IsZero() {
|
||||||
|
u.CreatedAt = time.Now().UTC()
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -89,14 +89,14 @@ func InsertSampleData() error {
|
||||||
Interval: 300,
|
Interval: 300,
|
||||||
GracePeriod: 300,
|
GracePeriod: 300,
|
||||||
})
|
})
|
||||||
checkin1.Create()
|
checkin1.Update()
|
||||||
|
|
||||||
checkin2 := ReturnCheckin(&types.Checkin{
|
checkin2 := ReturnCheckin(&types.Checkin{
|
||||||
Service: s2.Id,
|
Service: s2.Id,
|
||||||
Interval: 900,
|
Interval: 900,
|
||||||
GracePeriod: 300,
|
GracePeriod: 300,
|
||||||
})
|
})
|
||||||
checkin2.Create()
|
checkin2.Update()
|
||||||
|
|
||||||
checkTime := time.Now().Add(-24 * time.Hour)
|
checkTime := time.Now().Add(-24 * time.Hour)
|
||||||
for i := 0; i <= 60; i++ {
|
for i := 0; i <= 60; i++ {
|
||||||
|
|
|
@ -49,10 +49,10 @@ func SelectService(id int64) *Service {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) Checkin() Checkin {
|
func (s *Service) Checkin() *Checkin {
|
||||||
var hits Checkin
|
var checkin types.Checkin
|
||||||
servicesDB().Where("service = ?", s.Id).First(&hits)
|
checkinDB().Find(&checkin, "service = ?", s.Id)
|
||||||
return hits
|
return &Checkin{&checkin}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SelectAllServices returns a slice of *core.Service to be store on []*core.Services, should only be called once on startup.
|
// SelectAllServices returns a slice of *core.Service to be store on []*core.Services, should only be called once on startup.
|
||||||
|
|
|
@ -0,0 +1,246 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
VERSION="3.4.0"
|
||||||
|
VERBOSE=false
|
||||||
|
SSLOPTION=false
|
||||||
|
AWSREGION="us-west-2"
|
||||||
|
US_W_1="ami-7be8a103"
|
||||||
|
US_W_2="ami-7be8a103"
|
||||||
|
US_E_1="ami-7be8a103"
|
||||||
|
US_E_2="ami-7be8a103"
|
||||||
|
AWS_CLI=$(which aws)
|
||||||
|
AWS_ECS="$AWS_CLI --output json"
|
||||||
|
|
||||||
|
function usage() {
|
||||||
|
cat <<EOM
|
||||||
|
##### Statup Installer #####
|
||||||
|
A simple shell script that will help you install Statup on your local machine, AWS, or Docker.
|
||||||
|
|
||||||
|
Commands:
|
||||||
|
aws Create a new EC2 instance running Statup
|
||||||
|
docker Start the latest Statup Docker image
|
||||||
|
docker-compose Create Statup with a Postgres database
|
||||||
|
|
||||||
|
Available Flags:
|
||||||
|
-k | --aws-access-key AWS Access Key ID. May also be set as environment variable AWS_ACCESS_KEY_ID
|
||||||
|
-s | --aws-secret-key AWS Secret Access Key. May also be set as environment variable AWS_SECRET_ACCESS_KEY
|
||||||
|
-r | --region AWS Region Name. May also be set as environment variable AWS_DEFAULT_REGION
|
||||||
|
-v | --version Print out the current version of this tool
|
||||||
|
-x | --verbose Verbose output
|
||||||
|
Visit the github repo at: https://github.com/hunterlong/statup
|
||||||
|
EOM
|
||||||
|
exit 3
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check requirements
|
||||||
|
function require() {
|
||||||
|
command -v "$1" > /dev/null 2>&1 || {
|
||||||
|
echo "Some of the required software is not installed:"
|
||||||
|
echo " please install $1" >&2;
|
||||||
|
exit 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setAWSPresets {
|
||||||
|
if [ -z ${AWS_DEFAULT_REGION+x} ];
|
||||||
|
then unset AWS_DEFAULT_REGION
|
||||||
|
else
|
||||||
|
AWS_ECS="$AWS_ECS --region $AWS_DEFAULT_REGION"
|
||||||
|
fi
|
||||||
|
if [ -z ${AWS_PROFILE+x} ];
|
||||||
|
then unset AWS_PROFILE
|
||||||
|
else
|
||||||
|
AWS_ECS="$AWS_ECS --profile $AWS_PROFILE"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function awsAskRegion {
|
||||||
|
if [ -z ${AWS_DEFAULT_REGION+x} ]; then
|
||||||
|
read -p "Enter the AWS Region: " AWSREGION
|
||||||
|
else
|
||||||
|
AWSREGION=$AWS_DEFAULT_REGION
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function askEC2Name {
|
||||||
|
read -p "Enter the Name for EC2 Instance: " SERVERNAME
|
||||||
|
}
|
||||||
|
|
||||||
|
function askSSLOption {
|
||||||
|
read -p "Do you want to install a SSL certificate? (y/N):" SSLOPTION
|
||||||
|
}
|
||||||
|
|
||||||
|
function askSSLDomain {
|
||||||
|
read -p "Enter the Domain to attach the SSL certificate on: " SSLDOMAIN
|
||||||
|
}
|
||||||
|
|
||||||
|
function askSSLEmail {
|
||||||
|
read -p "Enter the Email for Lets Encrypt: " SSLEMAIL
|
||||||
|
}
|
||||||
|
|
||||||
|
function askEC2KeyName {
|
||||||
|
read -p "Enter the Keypair for EC2 Instance: " EC2KEYNAME
|
||||||
|
}
|
||||||
|
|
||||||
|
function askSecurityName {
|
||||||
|
read -p "Enter a name for the new Security Group: " EC2SECGROUP
|
||||||
|
}
|
||||||
|
|
||||||
|
function awsSecurityGroup {
|
||||||
|
echo "Running task: Creating Security Group";
|
||||||
|
GROUPID=`$AWS_ECS ec2 create-security-group --group-name "$EC2SECGROUP" --description "Statup HTTP Server on port 80 and 443" | jq -r .GroupId`
|
||||||
|
echo "Created new security group: $GROUPID";
|
||||||
|
awsAuthSecurityGroup
|
||||||
|
}
|
||||||
|
|
||||||
|
function awsAuthSecurityGroup {
|
||||||
|
$AWS_ECS ec2 authorize-security-group-ingress --group-id $GROUPID --protocol tcp --port 80 --cidr 0.0.0.0/0
|
||||||
|
$AWS_ECS ec2 authorize-security-group-ingress --group-id $GROUPID --protocol tcp --port 443 --cidr 0.0.0.0/0
|
||||||
|
echo "Authorize security group to be open on ports 80 and 443";
|
||||||
|
}
|
||||||
|
|
||||||
|
function awsCreateEC2 {
|
||||||
|
NEW_SRV=`$AWS_ECS ec2 run-instances --image-id $US_W_2 --count 1 --instance-type t2.nano --key-name $EC2KEYNAME --security-group-ids $GROUPID`
|
||||||
|
INSTANCE_ID=`echo $NEW_SRV | jq .Instances[0].InstanceId`
|
||||||
|
EC2_STATUS=`echo $NEW_SRV | .Instances[0].StateReason.Message`
|
||||||
|
echo "New EC2 instance created: $INSTANCE_ID with status $EC2_STATUS";
|
||||||
|
}
|
||||||
|
|
||||||
|
function ec2TaskComplete {
|
||||||
|
echo "New EC2 instance is ready! $INSTANCE_ID with status $EC2_STATUS";
|
||||||
|
echo "Instance ID: $INSTANCE_ID with status $EC2_STATUS";
|
||||||
|
echo "Public DNS: $EC2_DNS";
|
||||||
|
if [ $SSLOPTION == "y" ]; then
|
||||||
|
echo "Now you have to add a CNAME DNS record on $SSLDOMAIN pointing to $EC2_DNS"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkEC2Instance {
|
||||||
|
SRV_INFO=`$AWS_ECS ec2 describe-instances --instance-ids $INSTANCE_ID`
|
||||||
|
EC2_STATUS=$(echo "${SRV_INFO}" | jq .Reservations[0].Instances[0].State.Name)
|
||||||
|
EC2_DNS=$(echo "${SRV_INFO}" | jq .Reservations[0].Instances[0].PublicDnsName)
|
||||||
|
EC2_STATUS=$(echo "${SRV_INFO}" | jq .Reservations[0].Instances[0].State.Name)
|
||||||
|
if [ $EC2_STATUS == '"pending"' ]; then
|
||||||
|
echo "EC2 instance is still being created: $INSTANCE_ID";
|
||||||
|
sleep 3
|
||||||
|
checkEC2Instance
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function awsTest {
|
||||||
|
INSTANCE_ID="i-0768e3d5ba00897af"
|
||||||
|
checkEC2Instance
|
||||||
|
ec2TaskComplete
|
||||||
|
}
|
||||||
|
|
||||||
|
function awsTask {
|
||||||
|
setAWSPresets
|
||||||
|
askEC2Name
|
||||||
|
awsAskRegion
|
||||||
|
askSecurityName
|
||||||
|
askEC2KeyName
|
||||||
|
askSSLOption
|
||||||
|
if [ $SSLOPTION == "y" ]; then
|
||||||
|
askSSLDomain
|
||||||
|
askSSLEmail
|
||||||
|
fi
|
||||||
|
awsSecurityGroup
|
||||||
|
awsCreateEC2
|
||||||
|
checkEC2Instance
|
||||||
|
ec2TaskComplete
|
||||||
|
}
|
||||||
|
|
||||||
|
function localTask {
|
||||||
|
echo "installing locally"
|
||||||
|
}
|
||||||
|
|
||||||
|
function dockerTask {
|
||||||
|
echo "installing docker"
|
||||||
|
}
|
||||||
|
|
||||||
|
function dockerComposeTask {
|
||||||
|
echo "installing docker compose"
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ "$BASH_SOURCE" == "$0" ]; then
|
||||||
|
set -o errexit
|
||||||
|
set -o pipefail
|
||||||
|
set -u
|
||||||
|
set -e
|
||||||
|
# If no args are provided, display usage information
|
||||||
|
if [ $# == 0 ]; then usage; fi
|
||||||
|
|
||||||
|
COMMD=$1
|
||||||
|
|
||||||
|
# Loop through arguments, two at a time for key and value
|
||||||
|
while [[ $# -gt 0 ]]
|
||||||
|
do
|
||||||
|
key="$1"
|
||||||
|
|
||||||
|
case $key in
|
||||||
|
-k|--aws-access-key)
|
||||||
|
AWS_ACCESS_KEY_ID="$2"
|
||||||
|
shift # past argument
|
||||||
|
;;
|
||||||
|
-s|--aws-secret-key)
|
||||||
|
AWS_SECRET_ACCESS_KEY="$2"
|
||||||
|
shift # past argument
|
||||||
|
;;
|
||||||
|
-r|--region)
|
||||||
|
AWS_DEFAULT_REGION="$2"
|
||||||
|
shift # past argument
|
||||||
|
;;
|
||||||
|
-x|--verbose)
|
||||||
|
VERBOSE=true
|
||||||
|
;;
|
||||||
|
-v|--version)
|
||||||
|
echo ${VERSION}
|
||||||
|
echo "$2"
|
||||||
|
usage
|
||||||
|
exit 2
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
shift # past argument or value
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ $VERBOSE == true ]; then
|
||||||
|
set -x
|
||||||
|
fi
|
||||||
|
|
||||||
|
case $COMMD in
|
||||||
|
aws)
|
||||||
|
require aws
|
||||||
|
require jq
|
||||||
|
awsTask
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
awstest)
|
||||||
|
require aws
|
||||||
|
require jq
|
||||||
|
awsTest
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
docker)
|
||||||
|
require docker
|
||||||
|
dockerTask
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
docker-compose)
|
||||||
|
require docker-compose
|
||||||
|
dockerComposeTask
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
local)
|
||||||
|
localTask
|
||||||
|
shift # past argument
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
shift # past argument or value
|
||||||
|
fi
|
||||||
|
exit 0
|
||||||
|
|
||||||
|
fi
|
|
@ -141,20 +141,8 @@ var handlerFuncs = func(w http.ResponseWriter, r *http.Request) template.FuncMap
|
||||||
return utils.Timestamp(t).Ago()
|
return utils.Timestamp(t).Ago()
|
||||||
},
|
},
|
||||||
"Duration": func(t time.Duration) string {
|
"Duration": func(t time.Duration) string {
|
||||||
var out string
|
|
||||||
duration, _ := time.ParseDuration(fmt.Sprintf("%vs", t.Seconds()))
|
duration, _ := time.ParseDuration(fmt.Sprintf("%vs", t.Seconds()))
|
||||||
if duration.Minutes() < 1 {
|
return utils.FormatDuration(duration)
|
||||||
out = fmt.Sprintf("%0.0f second", duration.Seconds())
|
|
||||||
if duration.Seconds() >= 2 {
|
|
||||||
out += "s"
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
out = fmt.Sprintf("%0.0f minute", duration.Minutes())
|
|
||||||
if duration.Minutes() >= 2 {
|
|
||||||
out += "s"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return out
|
|
||||||
},
|
},
|
||||||
"ToUnix": func(t time.Time) int64 {
|
"ToUnix": func(t time.Time) int64 {
|
||||||
return t.UTC().Unix()
|
return t.UTC().Unix()
|
||||||
|
|
|
@ -53,7 +53,6 @@ func Router() *mux.Router {
|
||||||
r.Handle("/dashboard", http.HandlerFunc(dashboardHandler)).Methods("GET")
|
r.Handle("/dashboard", http.HandlerFunc(dashboardHandler)).Methods("GET")
|
||||||
r.Handle("/dashboard", http.HandlerFunc(loginHandler)).Methods("POST")
|
r.Handle("/dashboard", http.HandlerFunc(loginHandler)).Methods("POST")
|
||||||
r.Handle("/logout", http.HandlerFunc(logoutHandler))
|
r.Handle("/logout", http.HandlerFunc(logoutHandler))
|
||||||
r.Handle("/checkin/{id}", http.HandlerFunc(checkinUpdateHandler))
|
|
||||||
r.Handle("/plugins/download/{name}", http.HandlerFunc(pluginsDownloadHandler))
|
r.Handle("/plugins/download/{name}", http.HandlerFunc(pluginsDownloadHandler))
|
||||||
r.Handle("/plugins/{name}/save", http.HandlerFunc(pluginSavedHandler)).Methods("POST")
|
r.Handle("/plugins/{name}/save", http.HandlerFunc(pluginSavedHandler)).Methods("POST")
|
||||||
r.Handle("/help", http.HandlerFunc(helpHandler))
|
r.Handle("/help", http.HandlerFunc(helpHandler))
|
||||||
|
@ -87,6 +86,7 @@ func Router() *mux.Router {
|
||||||
r.Handle("/service/{id}/delete", http.HandlerFunc(servicesDeleteHandler))
|
r.Handle("/service/{id}/delete", http.HandlerFunc(servicesDeleteHandler))
|
||||||
r.Handle("/service/{id}/delete_failures", http.HandlerFunc(servicesDeleteFailuresHandler)).Methods("GET")
|
r.Handle("/service/{id}/delete_failures", http.HandlerFunc(servicesDeleteFailuresHandler)).Methods("GET")
|
||||||
r.Handle("/service/{id}/checkin", http.HandlerFunc(checkinCreateUpdateHandler)).Methods("POST")
|
r.Handle("/service/{id}/checkin", http.HandlerFunc(checkinCreateUpdateHandler)).Methods("POST")
|
||||||
|
r.Handle("/checkin/{id}", http.HandlerFunc(checkinUpdateHandler))
|
||||||
|
|
||||||
// API SERVICE Routes
|
// API SERVICE Routes
|
||||||
r.Handle("/api/services", http.HandlerFunc(apiAllServicesHandler)).Methods("GET")
|
r.Handle("/api/services", http.HandlerFunc(apiAllServicesHandler)).Methods("GET")
|
||||||
|
|
|
@ -261,15 +261,12 @@ func checkinCreateUpdateHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
service := core.SelectService(utils.StringInt(vars["id"]))
|
service := core.SelectService(utils.StringInt(vars["id"]))
|
||||||
|
checkin := service.Checkin()
|
||||||
interval := utils.StringInt(r.PostForm.Get("interval"))
|
interval := utils.StringInt(r.PostForm.Get("interval"))
|
||||||
grace := utils.StringInt(r.PostForm.Get("grace"))
|
grace := utils.StringInt(r.PostForm.Get("grace"))
|
||||||
checkin := core.ReturnCheckin(&types.Checkin{
|
checkin.Interval = interval
|
||||||
Service: service.Id,
|
checkin.GracePeriod = grace
|
||||||
Interval: interval,
|
checkin.Update()
|
||||||
GracePeriod: grace,
|
|
||||||
})
|
|
||||||
checkin.Create()
|
|
||||||
executeResponse(w, r, "service.html", service, fmt.Sprintf("/service/%v", service.Id))
|
executeResponse(w, r, "service.html", service, fmt.Sprintf("/service/%v", service.Id))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,17 +1,16 @@
|
||||||
{{define "form_checkin"}}
|
{{define "form_checkin"}}
|
||||||
<form action="/service/{{.Id}}/checkin" method="POST">
|
<form action="/checkin/{{.Id}}" method="POST">
|
||||||
<div class="form-group row">
|
<div class="form-group row">
|
||||||
<div class="col-md-12 col-sm-12">
|
<div class="col-md-4 col-sm-4">
|
||||||
<label for="checkin_interval" class="col-sm-4 col-form-label">Check Interval (in seconds)</label>
|
<label for="checkin_interval" class="col-form-label">Check Interval (in seconds)</label>
|
||||||
<input type="number" name="interval" class="form-control" id="checkin_interval" value="30" placeholder="60">
|
<input type="number" name="interval" class="form-control" id="checkin_interval" value="{{.Interval}}" placeholder="60">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-12 col-sm-12">
|
<div class="col-md-4 col-sm-4">
|
||||||
<label for="grace_period" class="col-sm-4 col-form-label">Grace Period </label>
|
<label for="grace_period" class="col-form-label">Grace Period</label>
|
||||||
<input type="number" name="grace" class="form-control" id="grace_period" value="30" placeholder="60">
|
<input type="number" name="grace" class="form-control" id="grace_period" value="{{.GracePeriod}}" placeholder="60">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="col-md-4 col-sm-4">
|
||||||
<div class="form-group row">
|
<label for="checkin_interval" class="col-form-label"></label>
|
||||||
<div class="col-sm-10">
|
|
||||||
<button type="submit" class="btn btn-success d-block">Save Checkin</button>
|
<button type="submit" class="btn btn-success d-block">Save Checkin</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -77,15 +77,7 @@
|
||||||
|
|
||||||
{{if Auth}}
|
{{if Auth}}
|
||||||
|
|
||||||
<div class="col-12 mt-4">
|
<div class="col-12 mt-4{{if ne $s.Type "http"}} d-none{{end}}">
|
||||||
|
|
||||||
<h3>Edit Service</h3>
|
|
||||||
|
|
||||||
{{template "form_service" $s}}
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-12 mt-4{{if eq $s.Type "tcp"}} d-none{{end}}">
|
|
||||||
<h3>Last Response</h3>
|
<h3>Last Response</h3>
|
||||||
<textarea rows="8" class="form-control" readonly>{{ $s.LastResponse }}</textarea>
|
<textarea rows="8" class="form-control" readonly>{{ $s.LastResponse }}</textarea>
|
||||||
<div class="form-group row mt-2">
|
<div class="form-group row mt-2">
|
||||||
|
@ -96,28 +88,33 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="col-12 mt-4">
|
||||||
|
<h3>Edit Service</h3>
|
||||||
|
{{template "form_service" $s}}
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="col-12 mt-4">
|
<div class="col-12 mt-4">
|
||||||
<h3>Service Checkin</h3>
|
<h3>Service Checkin</h3>
|
||||||
<table class="table">
|
<table class="table">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="col">Checkin</th>
|
<th scope="col">Checkin</th>
|
||||||
<th scope="col">Report Period<br>Grace Period</th>
|
<th scope="col">Report Period<br>Grace Period</th>
|
||||||
<th scope="col">Last Seen</th>
|
<th scope="col">Last Seen</th>
|
||||||
<th scope="col">Expected</th>
|
<th scope="col">Expected</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{{$ch := $s.Checkin}}
|
{{$ch := $s.Checkin}}
|
||||||
<tr>
|
<tr class="{{ if lt $ch.Expected 0}}bg-danger text-white{{else}}bg-light{{end}}">
|
||||||
<td>{{CoreApp.Domain}}/checkin/{{$ch.ApiKey}}</td>
|
<td>{{CoreApp.Domain}}/checkin/{{$ch.ApiKey}}</td>
|
||||||
<td>every {{Duration $ch.Period}}<br>{{Duration $ch.Grace}} grace period</td>
|
<td>every {{Duration $ch.Period}}<br>after {{Duration $ch.Grace}}</td>
|
||||||
<td>{{Ago $ch.Last.CreatedAt}}</td>
|
<td>{{Ago $ch.Last.CreatedAt}}</td>
|
||||||
<td>{{ if lt $ch.Expected 0}}{{Duration $ch.Expected}} ago{{else}}in {{Duration $ch.Expected}}{{end}}</td>
|
<td>{{ if lt $ch.Expected 0}}{{Duration $ch.Expected}} ago{{else}}in {{Duration $ch.Expected}}{{end}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
{{template "form_checkin" $s}}
|
{{template "form_checkin" $ch}}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -46,7 +46,6 @@ type Service struct {
|
||||||
LastStatusCode int `gorm:"-" json:"status_code"`
|
LastStatusCode int `gorm:"-" json:"status_code"`
|
||||||
LastOnline time.Time `gorm:"-" json:"last_online"`
|
LastOnline time.Time `gorm:"-" json:"last_online"`
|
||||||
Failures []interface{} `gorm:"-" json:"failures,omitempty"`
|
Failures []interface{} `gorm:"-" json:"failures,omitempty"`
|
||||||
//Checkins []*Checkin `gorm:"-" json:"checkins,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type ServiceInterface interface {
|
type ServiceInterface interface {
|
||||||
|
|
|
@ -0,0 +1,78 @@
|
||||||
|
// Statup
|
||||||
|
// Copyright (C) 2018. Hunter Long and the project contributors
|
||||||
|
// Written by Hunter Long <info@socialeck.com> and the project contributors
|
||||||
|
//
|
||||||
|
// https://github.com/hunterlong/statup
|
||||||
|
//
|
||||||
|
// The licenses for most software and other practical works are designed
|
||||||
|
// to take away your freedom to share and change the works. By contrast,
|
||||||
|
// the GNU General Public License is intended to guarantee your freedom to
|
||||||
|
// share and change all versions of a program--to make sure it remains free
|
||||||
|
// software for all its users.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func FormatDuration(d time.Duration) string {
|
||||||
|
var out string
|
||||||
|
if d.Hours() >= 24 {
|
||||||
|
out = fmt.Sprintf("%0.0f day", d.Hours()/24)
|
||||||
|
if (d.Hours() / 24) >= 2 {
|
||||||
|
out += "s"
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
} else if d.Hours() >= 1 {
|
||||||
|
out = fmt.Sprintf("%0.0f hour", d.Hours())
|
||||||
|
if d.Hours() >= 2 {
|
||||||
|
out += "s"
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
} else if d.Minutes() >= 1 {
|
||||||
|
out = fmt.Sprintf("%0.0f minute", d.Minutes())
|
||||||
|
if d.Minutes() >= 2 {
|
||||||
|
out += "s"
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
} else if d.Seconds() >= 1 {
|
||||||
|
out = fmt.Sprintf("%0.0f second", d.Seconds())
|
||||||
|
if d.Seconds() >= 2 {
|
||||||
|
out += "s"
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
} else if rev(d.Hours()) >= 24 {
|
||||||
|
out = fmt.Sprintf("%0.0f day", rev(d.Hours()/24))
|
||||||
|
if rev(d.Hours()/24) >= 2 {
|
||||||
|
out += "s"
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
} else if rev(d.Hours()) >= 1 {
|
||||||
|
out = fmt.Sprintf("%0.0f hour", rev(d.Hours()))
|
||||||
|
if rev(d.Hours()) >= 2 {
|
||||||
|
out += "s"
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
} else if rev(d.Minutes()) >= 1 {
|
||||||
|
out = fmt.Sprintf("%0.0f minute", rev(d.Minutes()))
|
||||||
|
if rev(d.Minutes()) >= 2 {
|
||||||
|
out += "s"
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
} else {
|
||||||
|
out = fmt.Sprintf("%0.0f second", rev(d.Seconds()))
|
||||||
|
if rev(d.Seconds()) >= 2 {
|
||||||
|
out += "s"
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func rev(f float64) float64 {
|
||||||
|
return f * -1
|
||||||
|
}
|
Loading…
Reference in New Issue