Skip to content

Commit

Permalink
optionalize base path for dashboard (#134)
Browse files Browse the repository at this point in the history
  • Loading branch information
rbren authored Jun 4, 2019
1 parent 12e10f9 commit 2494dd0
Show file tree
Hide file tree
Showing 8 changed files with 101 additions and 78 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,10 @@ Polaris validation checks fall into several different categories:

* `config`: Specify a location for the Polaris config
* `dashboard`: Runs the webserver for Polaris dashboard.
* `dashboard-port`: Port for the dashboard webserver (default 8080)
* `dashboard-port`: Port for the dashboard webserver (default `8080`)
* `dashboard-base-path`: Path on which the dashboard is being served (default `/`)
* `webhook`: Runs the webhook webserver.
* `webhook-port`: Port for the webhook webserver (default 9876)
* `webhook-port`: Port for the webhook webserver (default `9876`)
* `disable-webhook-config-installer`: disable the installer in the webhook server, so it won't install webhook configuration resources during bootstrapping
* `kubeconfig`: Paths to a kubeconfig. Only required if out-of-cluster.

Expand Down
48 changes: 4 additions & 44 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,7 @@ import (
"io/ioutil"
"net/http"
"os"
"strings"

"github.com/gorilla/mux"
conf "github.com/reactiveops/polaris/pkg/config"
"github.com/reactiveops/polaris/pkg/dashboard"
"github.com/reactiveops/polaris/pkg/kube"
Expand Down Expand Up @@ -53,6 +51,7 @@ func main() {
audit := flag.Bool("audit", false, "Runs a one-time audit.")
auditPath := flag.String("audit-path", "", "If specified, audits one or more YAML files instead of a cluster")
dashboardPort := flag.Int("dashboard-port", 8080, "Port for the dashboard webserver")
dashboardBasePath := flag.String("dashboard-base-path", "/", "Path on which the dashboard is served")
webhookPort := flag.Int("webhook-port", 9876, "Port for the webhook webserver")
auditOutputURL := flag.String("output-url", "", "Destination URL to send audit results")
auditOutputFile := flag.String("output-file", "", "Destination file for audit results")
Expand Down Expand Up @@ -89,56 +88,17 @@ func main() {
if *webhook {
startWebhookServer(c, *disableWebhookConfigInstaller, *webhookPort)
} else if *dashboard {
startDashboardServer(c, *auditPath, *dashboardPort)
startDashboardServer(c, *auditPath, *dashboardPort, *dashboardBasePath)
} else if *audit {
runAudit(c, *auditPath, *auditOutputFile, *auditOutputURL)
}
}

func startDashboardServer(c conf.Configuration, auditPath string, port int) {
router := mux.NewRouter()
func startDashboardServer(c conf.Configuration, auditPath string, port int, basePath string) {
router := dashboard.GetRouter(c, auditPath, port, basePath)
router.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("OK"))
})
router.HandleFunc("/results.json", func(w http.ResponseWriter, r *http.Request) {
k, err := kube.CreateResourceProvider(auditPath)
if err != nil {
logrus.Errorf("Error fetching Kubernetes resources %v", err)
http.Error(w, "Error fetching Kubernetes resources", http.StatusInternalServerError)
return
}
dashboard.EndpointHandler(w, r, c, k)
})
router.HandleFunc("/favicon.ico", func(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, "pkg/dashboard/assets/favicon-32x32.png")
})
router.HandleFunc("/details/{category}", func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
category := vars["category"]
category = strings.Replace(category, ".md", "", -1)
dashboard.DetailsHandler(w, r, category)
})
fileServer := http.FileServer(dashboard.GetAssetBox())
router.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/" {
http.NotFound(w, r)
return
}
k, err := kube.CreateResourceProvider(auditPath)
if err != nil {
logrus.Errorf("Error fetching Kubernetes resources %v", err)
http.Error(w, "Error fetching Kubernetes resources", http.StatusInternalServerError)
return
}
auditData, err := validator.RunAudit(c, k)
if err != nil {
logrus.Errorf("Error getting audit data: %v", err)
http.Error(w, "Error running audit", 500)
return
}
dashboard.MainHandler(w, r, auditData)
})
http.Handle("/static/", http.StripPrefix("/static/", fileServer))
http.Handle("/", router)

logrus.Infof("Starting Polaris dashboard server on port %d", port)
Expand Down
6 changes: 3 additions & 3 deletions pkg/dashboard/assets/css/Muli.css
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,17 @@
font-family: 'Muli';
font-style: normal;
font-weight: 300;
src: local('Muli Light'), local('Muli-Light'), url(/static/webfonts/Muli-Light.tff) format('truetype');
src: local('Muli Light'), local('Muli-Light'), url(../webfonts/Muli-Light.tff) format('truetype');
}
@font-face {
font-family: 'Muli';
font-style: normal;
font-weight: 400;
src: local('Muli Regular'), local('Muli-Regular'), url(/static/webfonts/Muli-Regular.tff) format('truetype');
src: local('Muli Regular'), local('Muli-Regular'), url(../webfonts/Muli-Regular.tff) format('truetype');
}
@font-face {
font-family: 'Muli';
font-style: normal;
font-weight: 700;
src: local('Muli Bold'), local('Muli-Bold'), url(/static/webfonts/Muli-Bold.tff) format('truetype');
src: local('Muli Bold'), local('Muli-Bold'), url(../webfonts/Muli-Bold.tff) format('truetype');
}
85 changes: 73 additions & 12 deletions pkg/dashboard/dashboard.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@ import (
"encoding/json"
"html/template"
"net/http"
"strings"

packr "github.com/gobuffalo/packr/v2"
"github.com/gorilla/mux"
conf "github.com/reactiveops/polaris/pkg/config"
"github.com/reactiveops/polaris/pkg/kube"
"github.com/reactiveops/polaris/pkg/validator"
Expand Down Expand Up @@ -75,8 +77,9 @@ func GetMarkdownBox() *packr.Box {
return markdownBox
}

// TemplateData is passed to the dashboard HTML template
type TemplateData struct {
// templateData is passed to the dashboard HTML template
type templateData struct {
BasePath string
AuditData validator.AuditData
JSON template.JS
}
Expand Down Expand Up @@ -122,7 +125,7 @@ func parseTemplateFiles(tmpl *template.Template, templateFileNames []string) (*t
return tmpl, nil
}

func writeTemplate(tmpl *template.Template, data *TemplateData, w http.ResponseWriter) {
func writeTemplate(tmpl *template.Template, data *templateData, w http.ResponseWriter) {
buf := &bytes.Buffer{}
err := tmpl.Execute(buf, data)
if err != nil {
Expand All @@ -132,16 +135,71 @@ func writeTemplate(tmpl *template.Template, data *TemplateData, w http.ResponseW
buf.WriteTo(w)
}

// GetRouter returns a mux router serving all routes necessary for the dashboard
func GetRouter(c conf.Configuration, auditPath string, port int, basePath string) *mux.Router {
router := mux.NewRouter()
router.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("OK"))
})
router.HandleFunc("/favicon.ico", func(w http.ResponseWriter, r *http.Request) {
favicon, err := GetAssetBox().Find("favicon-32x32.png")
if err != nil {
logrus.Errorf("Error getting favicon: %v", err)
http.Error(w, "Error getting favicon", http.StatusInternalServerError)
return
}
w.Write(favicon)
})
router.HandleFunc("/results.json", func(w http.ResponseWriter, r *http.Request) {
k, err := kube.CreateResourceProvider(auditPath)
if err != nil {
logrus.Errorf("Error fetching Kubernetes resources %v", err)
http.Error(w, "Error fetching Kubernetes resources", http.StatusInternalServerError)
return
}
JSONHandler(w, r, c, k)
})
router.HandleFunc("/details/{category}", func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
category := vars["category"]
category = strings.Replace(category, ".md", "", -1)
DetailsHandler(w, r, category, basePath)
})
fileServer := http.FileServer(GetAssetBox())
router.PathPrefix("/static/").Handler(http.StripPrefix("/static/", fileServer))
router.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/" {
http.NotFound(w, r)
return
}
k, err := kube.CreateResourceProvider(auditPath)
if err != nil {
logrus.Errorf("Error fetching Kubernetes resources %v", err)
http.Error(w, "Error fetching Kubernetes resources", http.StatusInternalServerError)
return
}
auditData, err := validator.RunAudit(c, k)
if err != nil {
logrus.Errorf("Error getting audit data: %v", err)
http.Error(w, "Error running audit", 500)
return
}
MainHandler(w, r, auditData, basePath)
})
return router
}

// MainHandler gets template data and renders the dashboard with it.
func MainHandler(w http.ResponseWriter, r *http.Request, auditData validator.AuditData) {
func MainHandler(w http.ResponseWriter, r *http.Request, auditData validator.AuditData, basePath string) {
jsonData, err := json.Marshal(auditData)

if err != nil {
http.Error(w, "Error serializing audit data", 500)
return
}

templateData := TemplateData{
data := templateData{
BasePath: basePath,
AuditData: auditData,
JSON: template.JS(jsonData),
}
Expand All @@ -151,24 +209,24 @@ func MainHandler(w http.ResponseWriter, r *http.Request, auditData validator.Aud
http.Error(w, "Error getting template data", 500)
return
}
writeTemplate(tmpl, &templateData, w)
writeTemplate(tmpl, &data, w)
}

// EndpointHandler gets template data and renders json with it.
func EndpointHandler(w http.ResponseWriter, r *http.Request, c conf.Configuration, kubeResources *kube.ResourceProvider) {
templateData, err := validator.RunAudit(c, kubeResources)
// JSONHandler gets template data and renders json with it.
func JSONHandler(w http.ResponseWriter, r *http.Request, c conf.Configuration, kubeResources *kube.ResourceProvider) {
auditData, err := validator.RunAudit(c, kubeResources)
if err != nil {
http.Error(w, "Error Fetching Deployments", http.StatusInternalServerError)
return
}

w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(templateData)
json.NewEncoder(w).Encode(auditData)
}

// DetailsHandler returns details for a given error type
func DetailsHandler(w http.ResponseWriter, r *http.Request, category string) {
func DetailsHandler(w http.ResponseWriter, r *http.Request, category string, basePath string) {
box := GetMarkdownBox()
contents, err := box.Find(category + ".md")
if err != nil {
Expand All @@ -192,5 +250,8 @@ func DetailsHandler(w http.ResponseWriter, r *http.Request, category string) {
return
}
tmpl.Parse(detailsHTML)
writeTemplate(tmpl, nil, w)
data := templateData{
BasePath: basePath,
}
writeTemplate(tmpl, &data, w)
}
2 changes: 1 addition & 1 deletion pkg/dashboard/templates/check-details.gohtml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

<head>
{{ template "head" . }}
<link rel="stylesheet" href="/static/css/check-details.css">
<link rel="stylesheet" href="static/css/check-details.css">
</head>

<body>
Expand Down
8 changes: 4 additions & 4 deletions pkg/dashboard/templates/dashboard.gohtml
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
</div>
<div class="name"><span class="caret-expander"></span>{{ $category }}<span class="category-score">Score: <strong>{{ getScore $summary }}%</strong></span></div>
<div class="result-messages expandable-content">
<p class="category-info">{{ getCategoryInfo $category }} Refer to the <a href="/details/{{ getCategoryLink $category }}">Polaris documentation about {{ $category }}</a> for more information.</p>
<p class="category-info">{{ getCategoryInfo $category }} Refer to the <a href="details/{{ getCategoryLink $category }}">Polaris documentation about {{ $category }}</a> for more information.</p>
</div>
</div>
{{ end }} {{/* end range categories */}}
Expand Down Expand Up @@ -93,7 +93,7 @@
<li class="{{ .Type }}">
<i class="message-icon {{ getIcon $message }}"></i>
<span class="message">{{ .Message }}</span>
<a class="more-info" href="/details/{{ getCategoryLink .Category }}">
<a class="more-info" href="details/{{ getCategoryLink .Category }}">
<i class="far fa-question-circle"></i>
</a>
</li>
Expand All @@ -108,7 +108,7 @@
<li class="{{ .Type }}">
<i class="message-icon {{ getIcon $message }}"></i>
<span class="message">{{ .Message }}</span>
<a class="more-info" href="/details/{{ getCategoryLink .Category }}">
<a class="more-info" href="details/{{ getCategoryLink .Category }}">
<i class="far fa-question-circle"></i>
</a>
</li>
Expand All @@ -121,6 +121,6 @@
</div>
</div>
{{ end }} {{/* end range .AuditData.NamespacedResults */}}
<script src="/static/js/charts.js">
<script src="static/js/charts.js">
</script>
{{end}}
21 changes: 11 additions & 10 deletions pkg/dashboard/templates/head.gohtml
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
{{ define "head" }}
<base href="{{ .BasePath }}">
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<title>ReactiveOps Polaris</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">

<link rel="icon" type="image/png" href="/static/favicon-32x32.png" sizes="32x32" />
<link rel="icon" type="image/png" href="/static/favicon-16x16.png" sizes="16x16" />
<link href="/static/css/Muli.css" rel="stylesheet">
<link rel="stylesheet" href="/static/css/normalize.css">
<link rel="stylesheet" href="/static/css/main.css">
<link rel="stylesheet" href="/static/css/fontawesome-5.7.2.css">
<link rel="stylesheet" href="/static/css/dashboard.css">
<script type="text/javascript" src="/static/js/Chart-2.7.2.min.js"></script>
<script type="text/javascript" src="/static/js/cash-4.1.2.min.js"></script>
<script type="text/javascript" src="/static/js/main.js"></script>
<link rel="icon" type="image/png" href="static/favicon-32x32.png" sizes="32x32" />
<link rel="icon" type="image/png" href="static/favicon-16x16.png" sizes="16x16" />
<link href="static/css/Muli.css" rel="stylesheet">
<link rel="stylesheet" href="static/css/normalize.css">
<link rel="stylesheet" href="static/css/main.css">
<link rel="stylesheet" href="static/css/fontawesome-5.7.2.css">
<link rel="stylesheet" href="static/css/dashboard.css">
<script type="text/javascript" src="static/js/Chart-2.7.2.min.js"></script>
<script type="text/javascript" src="static/js/cash-4.1.2.min.js"></script>
<script type="text/javascript" src="static/js/main.js"></script>
{{ end }}
4 changes: 2 additions & 2 deletions pkg/dashboard/templates/navbar.gohtml
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
<div class="navbar">
<div class="navbar-content">
<a href="/">
<img class="logo" src="/static/images/polaris-logo.png" alt="Polaris" />
<img class="logo" src="static/images/polaris-logo.png" alt="Polaris" />
</a>
<div class="navbar-right">
<a href="https://reactiveops.com?source=polaris" target="_blank">
<span class="oss-text">An Open Source Project By</span>
<img class="ro-logo" src="/static/images/ro-logo.png" alt="ReactiveOps" />
<img class="ro-logo" src="static/images/ro-logo.png" alt="ReactiveOps" />
</a>
</div>
</div>
Expand Down

0 comments on commit 2494dd0

Please sign in to comment.