summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClark Laughlin <clark.laughlin@linaro.org>2015-05-14 22:23:20 -0400
committerClark Laughlin <clark.laughlin@linaro.org>2015-05-14 22:23:20 -0400
commite9d8a76fa4b01d499e35fe4efafba49fd564ee2b (patch)
treeebaa9651b281ba69c1077db1d448cd30b1e1f4c3
parentb70df566780a2c9ea94c0756246679c683189253 (diff)
initial work on web app
-rw-r--r--web-app/server.go305
-rw-r--r--web-app/static/index.html3
2 files changed, 308 insertions, 0 deletions
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 @@
+<html>
+<body>Hello, world!</body>
+</html>