Skip to content

Commit

Permalink
Add support for text/html Accept header
Browse files Browse the repository at this point in the history
If accessing a route with text/html in the Accept header render a HTML
page instead of returning a JSON.
  • Loading branch information
Rickard Dybeck committed Nov 10, 2015
1 parent 656ce04 commit 39b82d8
Show file tree
Hide file tree
Showing 18 changed files with 504 additions and 8 deletions.
83 changes: 75 additions & 8 deletions handler/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ package handler
import (
"encoding/json"
"fmt"
"html/template"
"io"
"io/ioutil"
"net/http"
"strings"
"time"

log "github.com/dmuth/google-go-log4go"
Expand All @@ -27,14 +29,14 @@ func AddTask(w http.ResponseWriter, r *http.Request) {
err = json.Unmarshal(body, &request)
handleError(err, w)

taskId, err := scheduleTask(scheduler, request)
taskID, err := scheduleTask(scheduler, request)
if err != nil {
writeJSON(500, err, w)
return
}

w.Header().Set("Location", fmt.Sprintf("/task/%s", taskId))
writeJSON(http.StatusAccepted, taskId, w)
w.Header().Set("Location", fmt.Sprintf("/task/%s", taskID))
writeJSON(http.StatusAccepted, taskID, w)
}

// GetTaskInfo returns information about the given task.
Expand All @@ -44,12 +46,15 @@ func GetTaskInfo(w http.ResponseWriter, r *http.Request) {
log.Debugf("Fetching task for id: %s", id)
task := runningTasks[id]

if task == (eremeticTask{}) {
writeJSON(http.StatusNotFound, nil, w)
return
if strings.Contains(r.Header.Get("Accept"), "text/html") {
renderHTML(w, r, task, id)
} else {
if task == (eremeticTask{}) {
writeJSON(http.StatusNotFound, nil, w)
return
}
writeJSON(http.StatusOK, task, w)
}

writeJSON(http.StatusOK, task, w)
}

// Run the RequestChannel Listener
Expand Down Expand Up @@ -108,3 +113,65 @@ func writeJSON(status int, data interface{}, w http.ResponseWriter) error {
w.WriteHeader(status)
return json.NewEncoder(w).Encode(data)
}

func renderHTML(w http.ResponseWriter, r *http.Request, task eremeticTask, taskID string) {
var err error
var tpl *template.Template

data := make(map[string]interface{})
funcMap := template.FuncMap{
"Label": LabelColor,
}

if task == (eremeticTask{}) {
tpl, err = template.ParseFiles("templates/error_404.html")
data["TaskID"] = taskID
} else {
tpl, err = template.New("task.html").Funcs(funcMap).ParseFiles("templates/task.html")
data = makeMap(task)
}

if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
log.Error(err.Error())
return
}

err = tpl.Execute(w, data)
}

func makeMap(task eremeticTask) map[string]interface{} {
data := make(map[string]interface{})

data["TaskID"] = task.ID
data["CommandEnv"] = task.Command.GetEnvironment().GetVariables()
data["CommandUser"] = task.Command.GetUser()
data["Command"] = task.Command.GetValue()
// TODO: Support more than docker?
data["ContainerImage"] = task.Container.GetDocker().GetImage()
data["FrameworkID"] = task.FrameworkId
data["Hostname"] = task.Hostname
data["Name"] = task.Name
data["SlaveID"] = task.SlaveId
data["Status"] = task.Status
data["CPU"] = fmt.Sprintf("%.2f", task.TaskCPUs)
data["Memory"] = fmt.Sprintf("%.2f", task.TaskMem)

return data
}

// LabelColor is used to map a status to a label color
func LabelColor(status string) string {
switch status {
case "TASK_FAILED":
return "red"
case "TASK_LOST":
return "purple"
case "TASK_KILLED":
return "orange"
case "TASK_FINISHED":
return "green"
default:
return ""
}
}
24 changes: 24 additions & 0 deletions routes/routes.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
package routes

import (
"encoding/json"
"html/template"
"net/http"
"strings"

"github.com/alde/eremetic/handler"
"github.com/alde/eremetic/types"
"github.com/gorilla/mux"
Expand All @@ -18,9 +23,28 @@ func Create() *mux.Router {
Handler(route.HandlerFunc)
}

router.PathPrefix("/static/").
Handler(
http.StripPrefix(
"/static/", http.FileServer(http.Dir("./static/"))))

router.NotFoundHandler = http.HandlerFunc(notFound)

return router
}

func notFound(w http.ResponseWriter, r *http.Request) {
if strings.Contains(r.Header.Get("Accept"), "text/html") {
tpl, _ := template.ParseFiles("templates/error_404.html")
tpl.Execute(w, nil)
return
}

w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusNotFound)
json.NewEncoder(w).Encode(nil)
}

var routes = types.Routes{
types.Route{
Name: "AddTask",
Expand Down
11 changes: 11 additions & 0 deletions static/css/semantic.min.css

Large diffs are not rendered by default.

68 changes: 68 additions & 0 deletions static/css/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
.error_message {
float: left;
left: 35em;
top: 5em;
}

.ui.list > .item {
display: flex !important;
}

.main.container {
padding-top: 50px;
}

.container_section {
padding-top: 20px;
}

.column .header {
padding-bottom: 40px;
}

.ui.cpu.icon.svg {
background: url("/static/images/cpu.svg");
background-size: 100% 100%;
}
.ui.ram.icon.svg {
background: url("/static/images/ram.svg");
background-size: 100% 100%;
}

@font-face {
font-family: "fontcustom";
src: url("./themes/default/assets/fonts/fontcustom_cb066050d5b786186aa0e7f121427d8b.eot");
src: url("./themes/default/assets/fonts/fontcustom_cb066050d5b786186aa0e7f121427d8b.eot?#iefix") format("embedded-opentype"),
url("./themes/default/assets/fonts/fontcustom_cb066050d5b786186aa0e7f121427d8b.woff") format("woff"),
url("./themes/default/assets/fonts/fontcustom_cb066050d5b786186aa0e7f121427d8b.ttf") format("truetype"),
url("./themes/default/assets/fonts/fontcustom_cb066050d5b786186aa0e7f121427d8b.svg#fontcustom") format("svg");
font-weight: normal;
font-style: normal;
}

@media screen and (-webkit-min-device-pixel-ratio:0) {
@font-face {
font-family: "fontcustom";
src: url("./themes/default/assets/fonts/fontcustom_cb066050d5b786186aa0e7f121427d8b.svg#fontcustom") format("svg");
}
}

[data-icon]:before { content: attr(data-icon); }

[data-icon]:before,
.docker:before {
display: inline-block;
font-family: "fontcustom";
font-style: normal;
font-weight: normal;
font-variant: normal;
line-height: 1;
text-decoration: inherit;
text-rendering: optimizeLegibility;
text-transform: none;
-moz-osx-font-smoothing: grayscale;
-webkit-font-smoothing: antialiased;
font-smoothing: antialiased;
}

.docker:before { content: "\f100"; }
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Binary file not shown.
Binary file added static/css/themes/default/assets/fonts/icons.ttf
Binary file not shown.
Binary file added static/css/themes/default/assets/fonts/icons.woff
Binary file not shown.
Binary file not shown.
55 changes: 55 additions & 0 deletions static/images/cpu.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added static/images/disappointed_minion.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
63 changes: 63 additions & 0 deletions static/images/ram.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions static/js/jquery-2.1.4.min.js

Large diffs are not rendered by default.

Loading

0 comments on commit 39b82d8

Please sign in to comment.