Skip to content

Commit

Permalink
refactor to move db logger into a separate dedicated package
Browse files Browse the repository at this point in the history
  • Loading branch information
Yusuf Kanchwala committed Mar 19, 2021
1 parent e1e4f4e commit 9f19b92
Show file tree
Hide file tree
Showing 6 changed files with 185 additions and 122 deletions.
78 changes: 0 additions & 78 deletions pkg/http-server/webhook-scan-logger_test.go

This file was deleted.

31 changes: 13 additions & 18 deletions pkg/http-server/webhook-scan-logs.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,10 @@ import (
"net/http"
"time"

"github.com/accurics/terrascan/pkg/k8s/dblogs"
"github.com/accurics/terrascan/pkg/results"
"github.com/gorilla/mux"
"go.uber.org/zap"

// importing sqlite driver
_ "github.com/mattn/go-sqlite3"
)

type webhookDisplayedViolation struct {
Expand Down Expand Up @@ -67,9 +65,7 @@ type webhookDisplayedShowLog struct {
func (g *APIHandler) getLogs(w http.ResponseWriter, r *http.Request) {

// Return an HTML page including all the logs history
logger := WebhookScanLogger{
test: g.test,
}
logger := dblogs.NewWebhookScanLogger()

// The templates are saved in the docker in this location
t, err := template.ParseFiles("/go/terrascan/index.html")
Expand All @@ -79,7 +75,7 @@ func (g *APIHandler) getLogs(w http.ResponseWriter, r *http.Request) {
apiErrorResponse(w, errMsg, http.StatusInternalServerError)
}

logs, err := logger.fetchLogs()
logs, err := logger.FetchLogs()
if err != nil {
errMsg := fmt.Sprintf("error reading logs from DB: '%v'", err)
zap.S().Error(errMsg)
Expand Down Expand Up @@ -107,21 +103,20 @@ func (g *APIHandler) getLogs(w http.ResponseWriter, r *http.Request) {
}

func (g *APIHandler) getLogByUID(w http.ResponseWriter, r *http.Request) {
// Return an HTML page including the selected log

params := mux.Vars(r)
// Return an HTML page including the selected log
var (
params = mux.Vars(r)
uid = params["uid"]
logger = dblogs.NewWebhookScanLogger()
)

var uid = params["uid"]
if len(uid) < 1 {
apiErrorResponse(w, "Log UID is missing", http.StatusBadRequest)
return
}

logger := WebhookScanLogger{
test: g.test,
}

log, err := logger.fetchLogByID(uid)
log, err := logger.FetchLogByID(uid)
if err != nil {
errMsg := fmt.Sprintf("error reading logs from DB: '%v'", err)
zap.S().Error(errMsg)
Expand Down Expand Up @@ -153,7 +148,7 @@ func (g *APIHandler) getLogPath(host, logUID string) string {
return fmt.Sprintf("https://%v/k8s/webhooks/logs/%v", host, logUID)
}

func (g *APIHandler) getLogStatus(log webhookScanLog) string {
func (g *APIHandler) getLogStatus(log dblogs.WebhookScanLog) string {
// Calculate a log status:
// 1. !Allowed -> Rejected
// 2. Allowed -> if there are violations -> Allowed with Warnings. Otherwise -> Allowed
Expand All @@ -174,7 +169,7 @@ func (g *APIHandler) getLogStatus(log webhookScanLog) string {
return "Allowed"
}

func (g *APIHandler) getLogReasoning(log webhookScanLog) string {
func (g *APIHandler) getLogReasoning(log dblogs.WebhookScanLog) string {
// Reasoning:
// - In case the request is denied (rejected), show the violations that cause the denial.
// - Otherwise, if there are violations, show the full violations list was found
Expand Down Expand Up @@ -221,7 +216,7 @@ func (g *APIHandler) getLogReasoning(log webhookScanLog) string {
return string(encoded)
}

func (g *APIHandler) getLogRequest(log webhookScanLog) string {
func (g *APIHandler) getLogRequest(log dblogs.WebhookScanLog) string {
var review webhookDisplayedReview

err := json.Unmarshal([]byte(log.Request), &review)
Expand Down
7 changes: 3 additions & 4 deletions pkg/http-server/webhook-scan.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"time"

admissionWebhook "github.com/accurics/terrascan/pkg/k8s/admission-webhook"
"github.com/accurics/terrascan/pkg/k8s/dblogs"
"github.com/accurics/terrascan/pkg/results"
"github.com/accurics/terrascan/pkg/runtime"
"github.com/gorilla/mux"
Expand Down Expand Up @@ -155,11 +156,9 @@ func (g *APIHandler) logWebhook(output runtime.Output,

encodedViolationsSummary, _ := json.Marshal(output.Violations.ViolationStore)

logger := WebhookScanLogger{
test: g.test,
}
logger := dblogs.NewWebhookScanLogger()

err := logger.log(webhookScanLog{
err := logger.Log(dblogs.WebhookScanLog{
UID: uid,
Request: string(bytesAdmissionReview),
Allowed: allowed,
Expand Down
9 changes: 6 additions & 3 deletions pkg/http-server/webhook-scan_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"os"
"testing"

"github.com/accurics/terrascan/pkg/k8s/dblogs"
"github.com/gorilla/mux"
v1 "k8s.io/api/admission/v1"
)
Expand Down Expand Up @@ -178,10 +179,12 @@ func TestUWebhooks(t *testing.T) {
return
}
defer jsonFile.Close()
logger := WebhookScanLogger{
test: true,

logger := dblogs.WebhookScanLogger{
Test: true,
}
defer logger.clearDbFilePath()

defer logger.ClearDbFilePath()

byteValue, _ := ioutil.ReadAll(jsonFile)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,39 @@
package httpserver
/*
Copyright (C) 2020 Accurics, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package dblogs

import (
"database/sql"
"os"
"time"

"go.uber.org/zap"

// importing sqlite driver
_ "github.com/mattn/go-sqlite3"
)

// WebhookScanLogger handles the logic to push scan logs to db
type WebhookScanLogger struct {
test bool
Test bool
}

type webhookScanLog struct {
// WebhookScanLog database model for log records
type WebhookScanLog struct {
UID string
Request string
Allowed bool
Expand All @@ -25,7 +45,13 @@ type webhookScanLog struct {
// The file name where the DB is stored. Currently we use an SQLite DB
var dbFileName = "k8s-admission-review-logs.db"

func (g *WebhookScanLogger) log(webhookScanLog webhookScanLog) error {
// NewWebhookScanLogger returns a new WebhookScanLogger struct
func NewWebhookScanLogger() *WebhookScanLogger {
return &WebhookScanLogger{}
}

// Log creates a new db record for the admission request
func (g *WebhookScanLogger) Log(WebhookScanLog WebhookScanLog) error {
// Insert a new Log record to the DB

db, err := g.getDbHandler()
Expand All @@ -42,12 +68,12 @@ func (g *WebhookScanLogger) log(webhookScanLog webhookScanLog) error {
zap.S().Errorf("failed preparing SQL statement. error: '%v'", err)
return err
}
_, err = statement.Exec(webhookScanLog.UID,
webhookScanLog.Request,
webhookScanLog.Allowed,
webhookScanLog.ViolationsSummary,
webhookScanLog.DeniableViolations,
webhookScanLog.CreatedAt)
_, err = statement.Exec(WebhookScanLog.UID,
WebhookScanLog.Request,
WebhookScanLog.Allowed,
WebhookScanLog.ViolationsSummary,
WebhookScanLog.DeniableViolations,
WebhookScanLog.CreatedAt)
if err != nil {
zap.S().Errorf("failed to insert a new log. error: '%v'", err)
return err
Expand All @@ -56,7 +82,8 @@ func (g *WebhookScanLogger) log(webhookScanLog webhookScanLog) error {
return nil
}

func (g *WebhookScanLogger) fetchLogs() ([]webhookScanLog, error) {
// FetchLogs retrieves all the logs from the database
func (g *WebhookScanLogger) FetchLogs() ([]WebhookScanLog, error) {
// Fetch the entire logs in the DB, ordered by created_at DESC (the most updated will be at the top)

db, err := g.getDbHandler()
Expand All @@ -71,7 +98,7 @@ func (g *WebhookScanLogger) fetchLogs() ([]webhookScanLog, error) {
return nil, err
}

var result []webhookScanLog
var result []WebhookScanLog
defer row.Close()
for row.Next() {
var id int
Expand All @@ -83,7 +110,7 @@ func (g *WebhookScanLogger) fetchLogs() ([]webhookScanLog, error) {
var createdAt time.Time
row.Scan(&id, &uid, &request, &allowed, &violationsSummary, &deniableViolations, &createdAt)

result = append(result, webhookScanLog{
result = append(result, WebhookScanLog{
UID: uid,
Request: request,
Allowed: allowed,
Expand All @@ -96,7 +123,8 @@ func (g *WebhookScanLogger) fetchLogs() ([]webhookScanLog, error) {
return result, nil
}

func (g *WebhookScanLogger) fetchLogByID(logUID string) (*webhookScanLog, error) {
// FetchLogByID retreives a single record based on request ID from the database
func (g *WebhookScanLogger) FetchLogByID(logUID string) (*WebhookScanLog, error) {
// Fetch a specific log by its request UID

db, err := g.getDbHandler()
Expand All @@ -122,7 +150,7 @@ func (g *WebhookScanLogger) fetchLogByID(logUID string) (*webhookScanLog, error)
var createdAt time.Time
row.Scan(&id, &uid, &request, &allowed, &violationsSummary, &deniableViolations, &createdAt)

return &webhookScanLog{
return &WebhookScanLog{
UID: uid,
Request: request,
Allowed: allowed,
Expand All @@ -132,7 +160,7 @@ func (g *WebhookScanLogger) fetchLogByID(logUID string) (*webhookScanLog, error)
}, nil
}

return &webhookScanLog{}, nil
return &WebhookScanLog{}, nil
}

func (g *WebhookScanLogger) initDBIfNeeded() error {
Expand Down Expand Up @@ -184,14 +212,14 @@ func (g *WebhookScanLogger) getDbHandler() (*sql.DB, error) {
}

func (g *WebhookScanLogger) dbFilePath() string {
if g.test {
if g.Test {
return "./" + dbFileName
}
// This is where the DB file should be located in the container (It is going to be saved in the host machine volume)
return "/data/k8s-admission-review-logs.db"
}

// Used for Tests only - clear the DB file after the tests are done
func (g *WebhookScanLogger) clearDbFilePath() {
// ClearDbFilePath used for Tests only - clear the DB file after the tests are done
func (g *WebhookScanLogger) ClearDbFilePath() {
os.Remove(g.dbFilePath())
}
Loading

0 comments on commit 9f19b92

Please sign in to comment.