mirror of
https://github.com/paralus/paralus.git
synced 2026-05-09 09:56:45 +00:00
215 lines
5.1 KiB
Go
215 lines
5.1 KiB
Go
package service
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"fmt"
|
|
"strings"
|
|
|
|
v1 "github.com/RafayLabs/rcloud-base/proto/rpc/audit"
|
|
"google.golang.org/protobuf/types/known/structpb"
|
|
)
|
|
|
|
type AuditLogService struct {
|
|
auditQuery *ElasticSearchQuery
|
|
}
|
|
|
|
func NewAuditLogService(url string, auditPattern string, logPrefix string) (*AuditLogService, error) {
|
|
auditQuery, err := NewElasticSearchQuery(url, auditPattern, logPrefix)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &AuditLogService{auditQuery: auditQuery}, nil
|
|
}
|
|
|
|
func (a *AuditLogService) GetAuditLog(req *v1.AuditLogSearchRequest) (res *v1.AuditLogSearchResponse, err error) {
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
projectID, err := getPrjectIdFromUrlScope(req.GetMetadata().UrlScope)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
req.Filter.ProjectIds = []string{projectID}
|
|
return a.GetAuditLogByProjects(req)
|
|
}
|
|
|
|
func validateQueryString(queryString string) error {
|
|
if strings.Contains(queryString, "*") {
|
|
return fmt.Errorf("Sorry. '*' is not supported in search query")
|
|
}
|
|
if len(queryString) > 0 && len(queryString) < 3 {
|
|
return fmt.Errorf("Search string has to be atleast 3 characters")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func getPrjectIdFromUrlScope(urlScope string) (string, error) {
|
|
s := strings.Split(urlScope, "/")
|
|
if len(s) != 2 {
|
|
_log.Errorw("Unable to retrieve projectID from urlScope", "urlScope", urlScope)
|
|
return "", fmt.Errorf("Unable to retrieve projectID from urlScope")
|
|
}
|
|
return s[1], nil
|
|
}
|
|
|
|
func (a *AuditLogService) GetAuditLogByProjects(req *v1.AuditLogSearchRequest) (res *v1.AuditLogSearchResponse, err error) {
|
|
// No embedding in golang/protoc (https://github.com/golang/protobuf/issues/192)
|
|
err = validateQueryString(req.GetFilter().QueryString)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
res = &v1.AuditLogSearchResponse{
|
|
Result: &structpb.Struct{},
|
|
}
|
|
var buf bytes.Buffer
|
|
var r map[string]interface{}
|
|
query := map[string]interface{}{
|
|
"_source": true,
|
|
"size": 500,
|
|
"query": map[string]interface{}{
|
|
"bool": map[string]interface{}{
|
|
"must": []map[string]interface{}{
|
|
// Add org and partner filter once we have to support multi-org
|
|
{
|
|
"term": map[string]interface{}{
|
|
"category": "AUDIT",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
"sort": map[string]interface{}{
|
|
"timestamp": map[string]interface{}{
|
|
"order": "desc",
|
|
},
|
|
},
|
|
"aggs": map[string]interface{}{
|
|
"group_by_username": map[string]interface{}{
|
|
"terms": map[string]interface{}{
|
|
"field": "actor.account.username",
|
|
},
|
|
},
|
|
"group_by_type": map[string]interface{}{
|
|
"terms": map[string]interface{}{
|
|
"field": "type",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
//aggregations
|
|
agg, _ := query["aggs"].(map[string]interface{})
|
|
if req.GetFilter().DashboardData {
|
|
agg["group_by_project"] = map[string]interface{}{
|
|
"terms": map[string]interface{}{
|
|
"field": "project_id",
|
|
"size": 1000,
|
|
},
|
|
"aggs": map[string]interface{}{
|
|
"group_by_username": map[string]interface{}{
|
|
"terms": map[string]interface{}{
|
|
"field": "actor.account.username",
|
|
"size": 1000,
|
|
},
|
|
},
|
|
"group_by_type": map[string]interface{}{
|
|
"terms": map[string]interface{}{
|
|
"field": "type",
|
|
"size": 1000,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
// Filters
|
|
q, _ := query["query"].(map[string]interface{})
|
|
b, _ := q["bool"].(map[string]interface{})
|
|
m, _ := b["must"].([]map[string]interface{})
|
|
|
|
//Results not required in case of dashboard - only aggregations required
|
|
if req.GetFilter().DashboardData {
|
|
query["size"] = 0
|
|
}
|
|
// Add timefrom filter
|
|
if req.GetFilter().Timefrom != "" {
|
|
b["filter"] = map[string]interface{}{
|
|
"range": map[string]interface{}{
|
|
"timestamp": map[string]interface{}{
|
|
"gte": req.GetFilter().Timefrom,
|
|
"lt": "now",
|
|
},
|
|
},
|
|
}
|
|
}
|
|
// Add type
|
|
if req.GetFilter().Type != "" {
|
|
t := map[string]interface{}{
|
|
"term": map[string]interface{}{
|
|
"type": req.GetFilter().Type,
|
|
},
|
|
}
|
|
m = append(m, t)
|
|
}
|
|
// Add user
|
|
if req.GetFilter().User != "" {
|
|
t := map[string]interface{}{
|
|
"term": map[string]interface{}{
|
|
"actor.account.username": req.GetFilter().User,
|
|
},
|
|
}
|
|
m = append(m, t)
|
|
}
|
|
// Add user
|
|
if req.GetFilter().Client != "" {
|
|
t := map[string]interface{}{
|
|
"term": map[string]interface{}{
|
|
"client.type": req.GetFilter().Client,
|
|
},
|
|
}
|
|
m = append(m, t)
|
|
}
|
|
// ProjectIds
|
|
if len(req.GetFilter().ProjectIds) > 0 {
|
|
t := map[string]interface{}{
|
|
"terms": map[string]interface{}{
|
|
"project_id": req.GetFilter().ProjectIds,
|
|
},
|
|
}
|
|
m = append(m, t)
|
|
}
|
|
// query string
|
|
if req.GetFilter().QueryString != "" {
|
|
q := map[string]interface{}{
|
|
"query_string": map[string]interface{}{
|
|
"query": req.GetFilter().QueryString,
|
|
},
|
|
}
|
|
m = append(m, q)
|
|
}
|
|
b["must"] = m
|
|
if err := json.NewEncoder(&buf).Encode(query); err != nil {
|
|
_log.Errorw("Error encoding query:", " err", err)
|
|
return res, err
|
|
}
|
|
_log.Debug("Executing Query: ", q)
|
|
r, err = a.auditQuery.Handle(buf)
|
|
if err != nil {
|
|
return res, err
|
|
}
|
|
if r == nil {
|
|
return res, nil
|
|
}
|
|
// raw, err := json.Marshal(r)
|
|
// if err != nil {
|
|
// return res, err
|
|
// }
|
|
raw, err := structpb.NewStruct(r)
|
|
if err != nil {
|
|
return res, err
|
|
}
|
|
res = &v1.AuditLogSearchResponse{Result: raw}
|
|
return res, nil
|
|
}
|