From e9d8a76fa4b01d499e35fe4efafba49fd564ee2b Mon Sep 17 00:00:00 2001 From: Clark Laughlin Date: Thu, 14 May 2015 22:23:20 -0400 Subject: initial work on web app --- web-app/server.go | 305 ++++++++++++++++++++++++++++++++++++++++++++++ web-app/static/index.html | 3 + 2 files changed, 308 insertions(+) create mode 100644 web-app/server.go create mode 100644 web-app/static/index.html diff --git a/web-app/server.go b/web-app/server.go new file mode 100644 index 0000000..ad5bb8a --- /dev/null +++ b/web-app/server.go @@ -0,0 +1,305 @@ +package main + +import ( + "fmt" + "flag" + "github.com/gorilla/mux" + "github.com/jmcvetta/neoism" + "encoding/json" + "log" + "net/http" + "strconv" +) + + +var ( + addr = flag.String("addr", ":8081", "http service address") + log_root = flag.String("log_root", "/home/clarkl/lava_pull/logs", "log root path") + neo4j_server = flag.String("dbserver", "http://neo4j:linaro@localhost:7474/db/data/", "Neo4J server endpoint") +) + + +func Results_AllDevstack(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + + db, err := neoism.Connect(*neo4j_server) + if err != nil { + log.Println("error connecting to database: ", err) + } + + res := [] struct { + Name string `json:"n.name"` + }{} + + cq := neoism.CypherQuery{ + Statement: `MATCH (n:Devstack) RETURN n.name`, + Result: &res, + } + + err = db.Cypher(&cq) + if err != nil { + log.Println("query error: ", err) + } + + log.Printf("%#v", res) + + enc := json.NewEncoder(w) + enc.Encode(res) +} + + +func Results_AllOS(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + + db, err := neoism.Connect(*neo4j_server) + if err != nil { + log.Println("error connecting to database: ", err) + } + + res := [] struct { + Name string `json:"n.name"` + Version string `json:"n.version"` + Distro string `json:"n.distro"` + }{} + + cq := neoism.CypherQuery{ + Statement: `MATCH (n:OS) RETURN n.name, n.version, n.distro`, + Result: &res, + } + + err = db.Cypher(&cq) + if err != nil { + log.Println("query error: ", err) + } + + log.Printf("%#v", res) + + enc := json.NewEncoder(w) + enc.Encode(res) +} + + +func Results_Tempest_Summary(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + + db, err := neoism.Connect(*neo4j_server) + if err != nil { + log.Println("error connecting to database: ", err) + } + + res := [] struct { + Number_Of_Runs int32 `json:"Number_Of_Runs"` + OS_Name string `json:"OS_Name"` + Devstack_Branch string `json:"Devstack_Branch"` + Average_Pct_Failing float64 `json:"Average_Pct_Failing"` + Average_Pct_Passing float64 `json:"Average_Pct_Passing"` + Average_Pct_Skipped float64 `json:"Average_Pct_Skipped"` + }{} + + cq := neoism.CypherQuery{ + Statement: `MATCH (d:Devstack)<-[:USING]-(t:TempestRun)-[:ON]->(o:OS) + RETURN count(t) as Number_Of_Runs, o.name as OS_Name, d.name as Devstack_Branch, + ROUND(avg(toFloat(t.failing_tests)/t.tests_run) * 100) as Average_Pct_Failing, + ROUND(avg(toFloat(t.passing_tests)/t.tests_run) * 100) as Average_Pct_Passing, + ROUND(avg(toFloat(t.skipped_tests)/t.tests_run) * 100) as Average_Pct_Skipped`, + Result: &res, + } + + err = db.Cypher(&cq) + if err != nil { + log.Println("query error: ", err) + } + + log.Printf("%#v", res) + + enc := json.NewEncoder(w) + enc.Encode(res) +} + +func Results_Tempest_LastN(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + + count_param := mux.Vars(r)["count"] + count, err := strconv.Atoi(count_param) + if err != nil { + log.Println("error converting parameter from string to int: ", err) + } + + if count < 1 { + count = 1 + } + + if count > 60 { + count = 60 + } + + db, err := neoism.Connect(*neo4j_server) + if err != nil { + log.Println("error connecting to database: ", err) + } + + res := [] struct { + LAVA_Job int32 `json:"t.lava_job"` + Date string `json:"t.date"` + SHA1 string `json:"t.sha1"` + All_tests int32 `json:"t.all_tests"` + Passing_tests int32 `json:"t.passing_tests"` + Failing_tests int32 `json:"t.failing_tests"` + Tests_run int32 `json:"t.tests_run"` + Skipped_tests int32 `json:"t.skipped_tests"` + OS_Distro string `json:"o.distro"` + OS_Version string `json:"o.version"` + Devstack_Branch string `json:"d.name"` + Epoch_time int64 `json:"t.epoch_time"` + }{} + + cq := neoism.CypherQuery{ + Statement: `MATCH (d:Devstack)<-[:USING]-(t:TempestRun)-[:ON]->(o:OS) + RETURN t.lava_job, t.date, t.sha1, t.all_tests, + t.passing_tests, t.failing_tests, + t.tests_run, t.skipped_tests, + t.epoch_time, o.distro, o.version, d.name + ORDER BY t.epoch_time DESC + LIMIT {count}`, + Parameters: neoism.Props{"count": count}, + Result: &res, + } + + err = db.Cypher(&cq) + if err != nil { + log.Println("query error: ", err) + } + + log.Printf("%#v", res) + + enc := json.NewEncoder(w) + enc.Encode(res) +} + + +func Results_Tempest_Job_Summary(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + + job_param := mux.Vars(r)["job"] + job, err := strconv.Atoi(job_param) + if err != nil { + log.Println("error converting parameter from string to int: ", err) + } + + db, err := neoism.Connect(*neo4j_server) + if err != nil { + log.Println("error connecting to database: ", err) + } + + res := [] struct { + LAVA_Job int32 `json:"t.lava_job"` + Date string `json:"t.date"` + SHA1 string `json:"t.sha1"` + All_tests int32 `json:"t.all_tests"` + Passing_tests int32 `json:"t.passing_tests"` + Tests_run int32 `json:"t.tests_run"` + Skipped_tests int32 `json:"t.skipped_tests"` + Epoch_time int64 `json:"t.epoch_time"` + }{} + + cq := neoism.CypherQuery{ + Statement: `MATCH (t:TempestRun) WHERE t.lava_job = {job} + RETURN t.lava_job, t.date, t.sha1, t.all_tests, + t.passing_tests, t.failing_tests, + t.tests_run, t.skipped_tests, + t.epoch_time`, + Parameters: neoism.Props{"job": job}, + Result: &res, + } + + err = db.Cypher(&cq) + if err != nil { + log.Println("query error: ", err) + } + + log.Printf("%#v", res) + + enc := json.NewEncoder(w) + enc.Encode(res) +} + + +func Results_Tempest_OS(w http.ResponseWriter, r *http.Request) { + fmt.Fprintf(w, "URL: %s", r.URL.Path) +} + + +func Results_Tempest_OS_Summary(w http.ResponseWriter, r *http.Request) { + fmt.Fprintf(w, "URL: %s", r.URL.Path) +} + + +func Results_Tempest_Branch(w http.ResponseWriter, r *http.Request) { + fmt.Fprintf(w, "URL: %s", r.URL.Path) +} + + +func Results_Tempest_Branch_Summary(w http.ResponseWriter, r *http.Request) { + fmt.Fprintf(w, "URL: %s", r.URL.Path) +} + + +func Results_Tempest_Job_Failures(w http.ResponseWriter, r *http.Request) { + fmt.Fprintf(w, "URL: %s", r.URL.Path) +} + + +func Results_Tempest_Job_Skipped(w http.ResponseWriter, r *http.Request) { + fmt.Fprintf(w, "URL: %s", r.URL.Path) +} + + +func main() { + // + // handle routes for access to data + // + + r := mux.NewRouter() + s := r.Methods("GET").PathPrefix("/results").Subrouter() + + // global data + s.HandleFunc("/devstack-branches", Results_AllDevstack) + s.HandleFunc("/operating-systems", Results_AllOS) + + // tempest + s.HandleFunc("/tempest", Results_Tempest_LastN).Queries("count", "{count:[0-9]+}") + s.HandleFunc("/tempest", Results_Tempest_Summary) + s.HandleFunc("/tempest/operating-system/{os-distro}/{os-version}", Results_Tempest_OS).Queries("count", "{count:[0-9]+}") + s.HandleFunc("/tempest/operating-system/{os-distro}/{os-version}", Results_Tempest_OS_Summary) + s.HandleFunc("/tempest/devstack-branch/{branch}", Results_Tempest_Branch).Queries("count", "{count:[0-9]+}") + s.HandleFunc("/tempest/devstack-branch/{branch}", Results_Tempest_Branch_Summary) + s.HandleFunc("/tempest/job/{job:[0-9]+}", Results_Tempest_Job_Summary) + s.HandleFunc("/tempest/job/{job:[0-9]+}/failures", Results_Tempest_Job_Failures) + s.HandleFunc("/tempest/job/{job:[0-9]+}/skipped", Results_Tempest_Job_Skipped) + //s.HandleFunc("/tempest/test/class/{class}", Results_Tempest_Class_LastN).Queries("count", "{count:[0-9]+}") + //s.HandleFunc("/tempest/test/class/{class}", Results_Tempest_Class_Summary) + //s.HandleFunc("/tempest/test/{test}", Results_Tempest_Test_LastN).Queries("count", "{count:[0-9]+}") + //s.HandleFunc("/tempest/test/{test}", Results_Tempest_Test_Summary) + + http.Handle("/results/", r) + + // + // handle logs + // + + http.Handle("/logs", http.FileServer(http.Dir("log_root"))) + + // + // handle static content + // + + http.Handle("/", http.FileServer(http.Dir("./static/"))) + + // GO! + err := http.ListenAndServe(*addr, nil) + if err != nil { + log.Fatal("http.ListenAndServe: ", err) + } +} + + diff --git a/web-app/static/index.html b/web-app/static/index.html new file mode 100644 index 0000000..d0a1030 --- /dev/null +++ b/web-app/static/index.html @@ -0,0 +1,3 @@ + +Hello, world! + -- cgit v1.2.3