diff options
| -rw-r--r-- | .gitignore | 2 | ||||
| -rw-r--r-- | app/Makefile | 88 | ||||
| -rw-r--r-- | app/cache.go | 6 | ||||
| -rw-r--r-- | app/handler.go | 91 | ||||
| -rw-r--r-- | app/jobs.go | 2 | ||||
| -rw-r--r-- | app/main.go | 18 | ||||
| -rw-r--r-- | app/test.go | 12 | ||||
| -rw-r--r-- | app/utilities_test.go | 2 | ||||
| -rw-r--r-- | views/jobs.html | 53 | ||||
| -rw-r--r-- | views/jobs_error.html | 52 |
10 files changed, 281 insertions, 45 deletions
@@ -4,3 +4,5 @@ *.gz statuspage import.go +start.sh +_env.sh diff --git a/app/Makefile b/app/Makefile index 8624cd8..71b936c 100644 --- a/app/Makefile +++ b/app/Makefile @@ -1,5 +1,24 @@ -include env.sh +# Modify env.sh and uncomment to change config. +#include env.sh +# Start the race detector with "TEST_RACE=1 make test" on the command line. +ifdef TEST_RACE + RACE:=-race +else + RACE:= +endif + +# To be verbose while testing use TEST_VERBOSE=1. +ifdef TEST_VERBOSE + VERBOSE:=-v +else + VERBOSE:= +endif + +IMPORT_FILE:=./import.go +APP:=statuspage + +# Sanity check ifndef STATUS_DB_DRIVER export STATUS_DB_DRIVER:=sqlite3 endif @@ -22,35 +41,30 @@ ifndef STATUS_HTTP_PORT export STATUS_HTTP_PORT:=8080 endif -ifdef TEST_RACE - RACE:=-race -else - RACE:= +# Include the sqlit3 database in archiv. +ifeq ($(STATUS_DB_DRIVER), sqlite3) + STATUS_DB_DIR:=db +else + STATUS_DB_DIR:= endif -ifdef TEST_VERBOSE - VERBOSE:=-v -else - VERBOSE:= -endif - -IMPORT_FILE:=./import.go -APP:=statuspage - +# Start targets all: kill build run clean: kill @(rm $(IMPORT_FILE) 2>/dev/null && echo "Removing import file..." ) || true - @(rm $(STATUS_DB_CREDENTIALS) 2>/dev/null && echo "Removing sqlite3 database..." ) || true - @(rm ../$(APP).tar.gz 1>&2 2>/dev/null echo && "Removing tar archiv...") || true - @(rm $(APP) && echo "Removing binary ($(APP))...") || true + @(rm $(STATUS_DB_CREDENTIALS) 2>/dev/null echo && "Removing sqlite3 database..." ) || true + @(rm ../$(APP).tar.gz 1>&2 2>/dev/null && echo "Removing tar archiv...") || true + @(rm _env.sh 1>&2 2>/dev/null && echo "Removing _env.sh...") || true + @(rm $(APP) 2>/dev/null && echo "Removing binary ($(APP))...") || true + @(rm ../start.sh 1>&2 2>/dev/null && echo "Removing startup script...") || true @echo "Done." build: import go build -o statuspage -run: - ./$(APP) & +run: _test_build + ./$(APP) & kill: @echo "Killing running instances..." @@ -69,7 +83,7 @@ import: echo "import _ \"$(STATUS_DB_IMPORT_DRIVER)\"" >> $(IMPORT_FILE) ; \ fi -sqlite3: create_import +sqlite3: create_import @echo "import _ \"github.com/mattn/go-sqlite3\"" >> $(IMPORT_FILE) mysql: create_import @@ -81,10 +95,14 @@ postgresql: create_import database_all: sqlite3 mysql postgresql @echo "Created import file for all databases." -pack: +pack: gen_config @cd .. && \ - tar czf $(APP).tar.gz app/$(APP) app/env.sh app/Makefile views static db 2>/dev/null && \ - echo "../$(APP).tar.gz is ready." || \ + echo "#!/bin/sh" > start.sh && \ + echo "cd app && . ./_env.sh && ./$(APP)" >> start.sh && \ + chmod +x start.sh && \ + tar czf $(APP).tar.gz start.sh app/$(APP) app/_env.sh views static $(STATUS_DB_DIR) 2>/dev/null && \ + rm start.sh 2>/dev/null && \ + echo "\n../$(APP).tar.gz is ready." || \ (echo "Run \"make build\" first." && exit 1) test: @@ -102,3 +120,27 @@ benchmark: benchmark_dependencies: import export DB_STATUS_LOG=false go test $(VERBOSE) -bench=".*" -tags dep + +_test_build: + @if [ ! -f ./$(APP) ] || [ ! -x ./$(APP) ]; then \ + echo "No executable binary found. \nRun \"make build\" first.\n" 1>&2; \ + exit 1; \ + fi + +gen_config: _test_build + @echo "Generating config file!\n" + echo "#!/bin/sh" > _env.sh + @echo "# Database" >> _env.sh + echo "export STATUS_DB_DRIVER=$(STATUS_DB_DRIVER)" >> _env.sh + echo "export STATUS_DB_CREDENTIALS=$(STATUS_DB_CREDENTIALS)" >> _env.sh + echo "export STATUS_DB_IMPORT_DRIVER=$(STATUS_DB_IMPORT_DRIVER)" >> _env.sh + echo "export STATUS_DB_LOG=$(STATUS_DB_LOG)\n" >> _env.sh + @echo "" + @echo "# Redis" >> _env.sh + echo "export STATUS_REDIS_SERVER=$(STATUS_REDIS_SERVER)" >> _env.sh + echo "export STATUS_REDIS_PORT=$(STATUS_REDIS_PORT)\n" >> _env.sh + @echo "" + @echo "# Http" >> _env.sh + echo "export STATUS_HTTP_IP=$(STATUS_HTTP_IP)" >> _env.sh + echo "export STATUS_HTTP_PORT=$(STATUS_HTTP_PORT)" >> _env.sh + @chmod +x _env.sh diff --git a/app/cache.go b/app/cache.go index f75f317..4e8ece2 100644 --- a/app/cache.go +++ b/app/cache.go @@ -31,3 +31,9 @@ func DelCache(key string) error { _, err := c.Do("DEL", key) return err } + +func FillCache() error { + h := []Host{} + Db.Find(&h) + return CacheHosts("database", h) +} diff --git a/app/handler.go b/app/handler.go index 510514a..7dd8cc4 100644 --- a/app/handler.go +++ b/app/handler.go @@ -3,9 +3,9 @@ package main import ( "encoding/json" "fmt" - "github.com/garyburd/redigo/redis" "log" "net/http" + "net/url" ) func IndexHandler(w http.ResponseWriter, r *http.Request) { @@ -14,8 +14,8 @@ func IndexHandler(w http.ResponseWriter, r *http.Request) { c := pool.Get() defer c.Close() - j, err := redis.String(c.Do("GET", cache_prefix+"database")) - if err == nil { + j, err := GetCache(cache_prefix + "database") + if j != "" { err = json.Unmarshal([]byte(j), &hosts) if err != nil { log.Println("Error JSON decoding: ", err) @@ -23,7 +23,7 @@ func IndexHandler(w http.ResponseWriter, r *http.Request) { CacheHosts(cache_prefix+"database", hosts) } } else { - log.Println("Redis: ", err) + log.Println("Cache miss on Index page.") Db.Find(&hosts) CacheHosts(cache_prefix+"database", hosts) } @@ -32,10 +32,19 @@ func IndexHandler(w http.ResponseWriter, r *http.Request) { err = index.ExecuteTemplate(w, "index.html", hosts) if err != nil { - log.Panic(err) + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return } } +func SessionHandler(w http.ResponseWriter, r *http.Request) { + session, _ := store.Get(r, "session-name") + session.Values["foo"] = "bar" + session.Values[42] = 43 + session.Save(r, w) +} + func RegisterHandler(w http.ResponseWriter, r *http.Request) { log.Println("Processing registration!") fmt.Fprintf(w, "Processing registration! \n") @@ -48,10 +57,24 @@ func PrintRegisterHandler(w http.ResponseWriter, r *http.Request) { func PrintNewJobHandler(w http.ResponseWriter, r *http.Request) { log.Println("Printing job") + var t string - job := mainTempl.Lookup("jobs.html") - - err := job.ExecuteTemplate(w, "jobs.html", nil) + session, err := store.Get(r, "_SID") + flashes := session.Flashes("success") + if len(flashes) > 0 { + t = "jobs.html" + } else { + flashes = session.Flashes("error") + t = "jobs_error.html" + } + session.Save(r, w) + job := mainTempl.Lookup(t) + + //flashes := session.Flashes() + //flashes := session.Flashes("success") + //flashes := session.Flashes("error") + fmt.Println(flashes) + err = job.ExecuteTemplate(w, t, flashes) if err != nil { log.Panic(err) } @@ -59,21 +82,61 @@ func PrintNewJobHandler(w http.ResponseWriter, r *http.Request) { func AddNewJobHandler(w http.ResponseWriter, r *http.Request) { log.Printf("Add new job") + session, err := store.Get(r, "_SID") + if err != nil { + log.Println(err) + } - err := r.ParseForm() + err = r.ParseForm() if err != nil { log.Panic(err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return } - host := &Host{} - err = decoder.Decode(host, r.PostForm) + host := Host{} + err = decoder.Decode(&host, r.PostForm) if err != nil { - log.Panic(err) + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return } + u, err := url.Parse(host.Url) + if err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + if u.Scheme != "http" && u.Scheme != "https" { + log.Println("Scheme neither http nor https.", u.Scheme) + session.AddFlash("Unsurportted scheme. Only http:// and https:// is valid.", "error") + session.Save(r, w) + http.Redirect(w, r, "/new", 302) + // http.Error(w, "Scheme neither http nor https.", http.StatusInternalServerError) + return + } + + host.Monitored = true + log.Printf("%v", host) - fmt.Fprintf(w, "%s", host.Url) - Db.Debug().Save(host) + Db.Debug().Save(&host) + + go func() { + h := []Host{} + h = append(h, host) + h = CheckPage(h) + for k, _ := range h { + Db.Debug().Save(&h[k]) + } + }() + + session.AddFlash("Job added!", "success") + session.Save(r, w) + + http.Redirect(w, r, "/new", 302) + } func ShowJobHandler(w http.ResponseWriter, r *http.Request) { diff --git a/app/jobs.go b/app/jobs.go index 0cbfc47..5298dc3 100644 --- a/app/jobs.go +++ b/app/jobs.go @@ -1,7 +1,7 @@ package main func jobRun() { - c.AddFunc("@every 10s", healthCheck) + c.AddFunc("@every 10m", healthCheck) c.Start() } diff --git a/app/main.go b/app/main.go index 17d3157..b2c210c 100644 --- a/app/main.go +++ b/app/main.go @@ -3,26 +3,44 @@ package main import ( "github.com/gorilla/mux" "github.com/gorilla/schema" + "github.com/gorilla/sessions" "github.com/robfig/cron" "html/template" + "log" "net/http" "os" ) var decoder = schema.NewDecoder() +var store = sessions.NewCookieStore([]byte(RandomKey())) + var mainTempl = template.Must(template.New("global").ParseGlob("../views/*.html")) var c = cron.New() func main() { + decoder.IgnoreUnknownKeys(true) + store.Options = &sessions.Options{ + Path: "/", + MaxAge: 86400, + HttpOnly: true, + } checkConfig() jobRun() InitDB() insertHost() + insertAdmin() + go func() { + err := FillCache() + if err != nil { + log.Panic(err) + } + }() r := mux.NewRouter() r.HandleFunc("/", IndexHandler) + r.HandleFunc("/session", SessionHandler) r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir("./../static")))) r.HandleFunc("/register", RegisterHandler).Methods("POST") r.HandleFunc("/register", PrintRegisterHandler).Methods("GET") diff --git a/app/test.go b/app/test.go index 3181eb4..331dad5 100644 --- a/app/test.go +++ b/app/test.go @@ -1,7 +1,8 @@ package main import ( -//"encoding/json" + //"encoding/json" + "log" ) func insertHost() { @@ -21,3 +22,12 @@ func insertHost() { c.Do("SET", cache_prefix, js) */ } + +func insertAdmin() { + password, err := HashPassword("password") + if err != nil { + log.Panic(err) + } + u := User{Name: "admin", Email: "root@localhost", Password: password} + Db.Create(&u) +} diff --git a/app/utilities_test.go b/app/utilities_test.go index 22f1f5e..86ea3bf 100644 --- a/app/utilities_test.go +++ b/app/utilities_test.go @@ -48,7 +48,7 @@ func TestRandomKey(t *testing.T) { var key string for i := 0; i < 100; i++ { key = RandomKey() - t.Log(key) + //t.Log(key) // Uncomment to see every generated key. if m[key] { t.Fatal("Key not random.") } else { diff --git a/views/jobs.html b/views/jobs.html index 9fdcbf7..df54994 100644 --- a/views/jobs.html +++ b/views/jobs.html @@ -1,9 +1,52 @@ {{template "header.html"}} {{template "navbar.html"}} -<form method='post' action='/new'> - <input type='text' name='Url' placeholder='domain'> - <!--input type='text' name='name' placeholder='name'> - <input type='hidden' name='private' value='0'--> - <input type='submit'> +<div class="container"> + <div class="row"> +{{range .}} +<h4 class="col-md-4 col-md-offset-4 alert alert-success alert-dismissible" role="alert"> + <button type="button" class="close" data-dismiss="alert" aria-label="close"><span aria-hidden="true">×</span></button> + {{.}} +</h4> +{{end}} + <div class="text-center"> + </div> + </div> +</div> +<div class="container"> + <div class="row"> +<form class="form-horizontal" method='post' action='/new'> + <fieldset> + + <!-- Form Name --> + <div class="text-center"> + <legend>Add new job!</legend> + </div> + + <!-- Text input--> + <div class="form-group"> + <label class="col-md-4 control-label" for="Url">Job Url:</label> + <div class="col-md-4"> + <div class="input-group"> + <input id="Url" name="Url" placeholder="Url to monitor." class="form-control input-md" required="" type="text"> + <span class="input-group-addon"> + <input name="Private" type="checkbox"> + </span> + </div> + <span class="help-block">Check to mark this host as private.</span> + </div> + </div> + + <!-- Button --> + <div class="form-group"> + <label class="col-md-4 control-label" for="submit"></label> + <div class="col-md-4"> + <button class="btn btn-primary">Submit</button> + </div> + </div> + + </fieldset> </form> + + </div> +</div> {{template "footer.html"}} diff --git a/views/jobs_error.html b/views/jobs_error.html new file mode 100644 index 0000000..c13cbd8 --- /dev/null +++ b/views/jobs_error.html @@ -0,0 +1,52 @@ +{{template "header.html"}} +{{template "navbar.html"}} +<div class="container"> + <div class="row"> +{{range .}} +<h4 class="col-md-4 col-md-offset-4 alert alert-danger alert-dismissible" role="alert"> + <button type="button" class="close" data-dismiss="alert" aria-label="close"><span aria-hidden="true">×</span></button> + {{.}} +</h4> +{{end}} + <div class="text-center"> + </div> + </div> +</div> +<div class="container"> + <div class="row"> +<form class="form-horizontal" method='post' action='/new'> + <fieldset> + + <!-- Form Name --> + <div class="text-center"> + <legend>Add new job!</legend> + </div> + + <!-- Text input--> + <div class="form-group"> + <label class="col-md-4 control-label" for="Url">Job Url:</label> + <div class="col-md-4"> + <div class="input-group"> + <input id="Url" name="Url" placeholder="Url to monitor." class="form-control input-md" required="" type="text"> + <span class="input-group-addon"> + <input name="Private" type="checkbox"> + </span> + </div> + <span class="help-block">Check to mark this host as private.</span> + </div> + </div> + + <!-- Button --> + <div class="form-group"> + <label class="col-md-4 control-label" for="submit"></label> + <div class="col-md-4"> + <button class="btn btn-primary">Submit</button> + </div> + </div> + + </fieldset> +</form> + + </div> +</div> +{{template "footer.html"}} |
