Skip to content

Commit

Permalink
Wl/stored audits (#188)
Browse files Browse the repository at this point in the history
* added ability to run dashboard from a stored audit result file.

* added ability to run dashboard from a stored audit result file.

* more changes

* debugging

* de

* all working as anticipated locally

* .

* updated way of decoding YAML/JSON files.

* remmoved unneded code

* renamed fn names, moved logic around and cleaned up main.go

* deleted output files from weird places.

* deleted test file
  • Loading branch information
willfairwinds committed Aug 14, 2019
1 parent 15b1455 commit b8422a9
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 25 deletions.
11 changes: 8 additions & 3 deletions main.go
Expand Up @@ -59,6 +59,7 @@ func main() {
auditOutputURL := flag.String("output-url", "", "Destination URL to send audit results")
auditOutputFile := flag.String("output-file", "", "Destination file for audit results")
auditOutputFormat := flag.String("output-format", "json", "Output format for results - json, yaml, or score")
loadAuditFile := flag.String("load-audit-file", "", "Runs the dashboard with data saved from a past audit.")
displayName := flag.String("display-name", "", "An optional identifier for the audit")
configPath := flag.String("config", "", "Location of Polaris configuration file")
logLevel := flag.String("log-level", logrus.InfoLevel.String(), "Logrus log level")
Expand Down Expand Up @@ -103,7 +104,7 @@ func main() {
if *webhook {
startWebhookServer(c, *disableWebhookConfigInstaller, *webhookPort)
} else if *dashboard {
startDashboardServer(c, *auditPath, *dashboardPort, *dashboardBasePath)
startDashboardServer(c, *auditPath, *loadAuditFile, *dashboardPort, *dashboardBasePath)
} else if *audit {
auditData := runAndReportAudit(c, *auditPath, *auditOutputFile, *auditOutputURL, *auditOutputFormat)

Expand All @@ -118,8 +119,12 @@ func main() {
}
}

func startDashboardServer(c conf.Configuration, auditPath string, port int, basePath string) {
router := dashboard.GetRouter(c, auditPath, port, basePath)
func startDashboardServer(c conf.Configuration, auditPath string, loadAuditFile string, port int, basePath string) {
var auditData validator.AuditData
if loadAuditFile != "" {
auditData = validator.ReadAuditFromFile(loadAuditFile)
}
router := dashboard.GetRouter(c, auditPath, port, basePath, &auditData)
router.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("OK"))
})
Expand Down
55 changes: 33 additions & 22 deletions pkg/dashboard/dashboard.go
Expand Up @@ -21,11 +21,11 @@ import (
"net/http"
"strings"

packr "github.com/gobuffalo/packr/v2"
"github.com/gorilla/mux"
conf "github.com/fairwindsops/polaris/pkg/config"
"github.com/fairwindsops/polaris/pkg/kube"
"github.com/fairwindsops/polaris/pkg/validator"
packr "github.com/gobuffalo/packr/v2"
"github.com/gorilla/mux"
"github.com/sirupsen/logrus"
"gitlab.com/golang-commonmark/markdown"
)
Expand Down Expand Up @@ -136,7 +136,7 @@ func writeTemplate(tmpl *template.Template, data *templateData, w http.ResponseW
}

// 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 {
func GetRouter(c conf.Configuration, auditPath string, port int, basePath string, auditData *validator.AuditData) *mux.Router {
router := mux.NewRouter()
router.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("OK"))
Expand All @@ -151,13 +151,24 @@ func GetRouter(c conf.Configuration, auditPath string, port int, basePath string
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
if auditData == nil {
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
}

auditDataObj, err := validator.RunAudit(c, k)
if err != nil {
http.Error(w, "Error Fetching Deployments", http.StatusInternalServerError)
return
}
auditData = &auditDataObj
}
JSONHandler(w, r, c, k)

JSONHandler(w, r, auditData)

})
router.HandleFunc("/details/{category}", func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
Expand All @@ -178,13 +189,19 @@ func GetRouter(c conf.Configuration, auditPath string, port int, basePath string
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
if auditData == nil {
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)
} else {
MainHandler(w, r, *auditData, basePath)
}
MainHandler(w, r, auditData, basePath)

})
return router
}
Expand Down Expand Up @@ -213,13 +230,7 @@ func MainHandler(w http.ResponseWriter, r *http.Request, auditData validator.Aud
}

// 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
}

func JSONHandler(w http.ResponseWriter, r *http.Request, auditData *validator.AuditData) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(auditData)
Expand Down
38 changes: 38 additions & 0 deletions pkg/validator/types.go
Expand Up @@ -15,11 +15,18 @@
package validator

import (
"bytes"
"fmt"
"io"
"io/ioutil"
"os"

"github.com/sirupsen/logrus"

"github.com/fairwindsops/polaris/pkg/config"
conf "github.com/fairwindsops/polaris/pkg/config"
corev1 "k8s.io/api/core/v1"
apiMachineryYAML "k8s.io/apimachinery/pkg/util/yaml"
)

// MessageType represents the type of Message
Expand Down Expand Up @@ -197,3 +204,34 @@ type ResultMessage struct {
Type MessageType
Category string
}

// ReadAuditFromFile reads the data from a past audit stored in a JSON or YAML file.
func ReadAuditFromFile(fileName string) AuditData {
auditData := AuditData{}
oldFileBytes, err := ioutil.ReadFile(fileName)
if err != nil {
logrus.Errorf("Unable to read contents of loaded file: %v", err)
os.Exit(1)
}
auditData, err = ParseAudit(oldFileBytes)
if err != nil {
logrus.Errorf("Error parsing file contents into auditData: %v", err)
os.Exit(1)
}
return auditData
}

// ParseAudit decodes either a YAML or JSON file and returns AuditData.
func ParseAudit(oldFileBytes []byte) (AuditData, error) {
reader := bytes.NewReader(oldFileBytes)
conf := AuditData{}
d := apiMachineryYAML.NewYAMLOrJSONDecoder(reader, 4096)
for {
if err := d.Decode(&conf); err != nil {
if err == io.EOF {
return conf, nil
}
return conf, fmt.Errorf("Decoding config failed: %v", err)
}
}
}

0 comments on commit b8422a9

Please sign in to comment.