mirror of
https://github.com/FairwindsOps/polaris.git
synced 2026-05-11 11:47:12 +00:00
optionalize base path for dashboard (#134)
This commit is contained in:
@@ -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.
|
||||
|
||||
|
||||
48
main.go
48
main.go
@@ -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"
|
||||
@@ -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")
|
||||
@@ -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)
|
||||
|
||||
@@ -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');
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
@@ -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
|
||||
}
|
||||
@@ -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 {
|
||||
@@ -132,8 +135,62 @@ 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 {
|
||||
@@ -141,7 +198,8 @@ func MainHandler(w http.ResponseWriter, r *http.Request, auditData validator.Aud
|
||||
return
|
||||
}
|
||||
|
||||
templateData := TemplateData{
|
||||
data := templateData{
|
||||
BasePath: basePath,
|
||||
AuditData: auditData,
|
||||
JSON: template.JS(jsonData),
|
||||
}
|
||||
@@ -151,12 +209,12 @@ 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
|
||||
@@ -164,11 +222,11 @@ func EndpointHandler(w http.ResponseWriter, r *http.Request, c conf.Configuratio
|
||||
|
||||
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 {
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 */}}
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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}}
|
||||
|
||||
@@ -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 }}
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user