-
Notifications
You must be signed in to change notification settings - Fork 4
/
ariel.go
155 lines (132 loc) · 4.86 KB
/
ariel.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
package qradar
import (
"context"
"fmt"
"net/http"
"time"
)
const arielSearchAPIPrefix = "api/ariel/searches"
// ArielService handles communication with the search-related methods of
// the QRadar API.
type ArielService service
// Search represent Ariel search state.
type Search struct {
CursorID *string `json:"cursor_id,omitempty"`
CompressedDataFileCount *int `json:"compressed_data_file_count,omitempty"`
CompressedDataTotalSize *int `json:"compressed_data_total_size,omitempty"`
DataFileCount *int `json:"data_file_count,omitempty"`
DataTotalSize *int `json:"data_total_size,omitempty"`
IndexFileCount *int `json:"index_file_count,omitempty"`
IndexTotalSize *int `json:"index_total_size,omitempty"`
ProcessedRecordCount *int `json:"processed_record_count,omitempty"`
ErrorMessages []ErrorMessage `json:"error_messages,omitempty"`
DesiredRetentionTimeMsec *int `json:"desired_retention_time_msec,omitempty"`
Progress *int `json:"progress,omitempty"`
ProgressDetails []int `json:"progress_details,omitempty"`
QueryExecutionTime *int `json:"query_execution_time,omitempty"`
QueryString *string `json:"query_string,omitempty"`
RecordCount *int `json:"record_count,omitempty"`
SaveResults *bool `json:"save_results,omitempty"`
Status *string `json:"status,omitempty"`
Snapshot *struct {
Events []Event `json:"events,omitempty"`
} `json:"snapshot,omitempty"`
SubsearchIds []string `json:"subsearch_ids,omitempty"`
SearchID *string `json:"search_id,omitempty"`
}
// Event represents generic event result.
type Event map[string]interface{}
// SearchResult represents search result.
type SearchResult struct {
Events []Event `json:"events,omitempty"`
}
// SearchMetadata represents search metadata.
type SearchMetadata struct {
Columns []SearchColumn `json:"columns,omitempty"`
}
// SearchColumn represents found column and it's properties.
type SearchColumn struct {
ArgumentType *string `json:"argument_type,omitempty"`
Indexable *bool `json:"indexable,omitempty"`
Name *string `json:"name,omitempty"`
Nullable *bool `json:"nullable,omitempty"`
ObjectValueType *string `json:"object_value_type,omitempty"`
ProviderName *string `json:"provider_name,omitempty"`
}
// SearchByQuery events in the QRadar API.
// It's caller responsibility to wait for results and get the final data.
func (a *ArielService) SearchByQuery(ctx context.Context, sqlQuery string) (*Search, error) {
req, err := a.client.NewRequest(http.MethodPost, arielSearchAPIPrefix, nil)
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", "text/plain")
q := req.URL.Query()
q.Add("query_expression", sqlQuery)
req.URL.RawQuery = q.Encode()
var s Search
_, err = a.client.Do(ctx, req, &s)
if err != nil {
return nil, err
}
return &s, nil
}
// SearchStatus returns a status and count of the records of the search.
func (a *ArielService) SearchStatus(ctx context.Context, searchID string) (string, int, error) {
req, err := a.client.NewRequest(http.MethodGet, fmt.Sprintf("%s/%s", arielSearchAPIPrefix, searchID), nil)
if err != nil {
return "", 0, err
}
var s Search
_, err = a.client.Do(ctx, req, &s)
if err != nil {
return "", 0, err
}
return *s.Status, *s.RecordCount, nil
}
// SearchMetadata represents a metadata retriever.
func (a *ArielService) SearchMetadata(ctx context.Context, searchID string) (*SearchMetadata, error) {
req, err := a.client.NewRequest(http.MethodGet, fmt.Sprintf("%s/%s/metadata", arielSearchAPIPrefix, searchID), nil)
if err != nil {
return nil, err
}
var s SearchMetadata
_, err = a.client.Do(ctx, req, &s)
if err != nil {
return nil, err
}
return &s, nil
}
// WaitForSearchID returns amount of records and the error.
func (a *ArielService) WaitForSearchID(ctx context.Context, searchID string, status JobStatus, seconds int) (int, error) {
ticker := time.NewTicker(time.Duration(seconds) * time.Second)
for {
select {
case <-ctx.Done():
return 0, ctx.Err()
case <-ticker.C:
s, num, err := a.SearchStatus(ctx, searchID)
if err != nil {
ticker.Stop()
return 0, err
}
if (JobStatus)(s) == status {
ticker.Stop()
return num, nil
}
}
}
}
// DeleteSearch returns a search status that has been deleted and the error.
func (a *ArielService) DeleteSearch(ctx context.Context, searchID string) (string, error) {
req, err := a.client.NewRequest(http.MethodDelete, fmt.Sprintf("%s/%s", arielSearchAPIPrefix, searchID), nil)
if err != nil {
return "", err
}
var s Search
_, err = a.client.Do(ctx, req, &s)
if err != nil {
return "", err
}
return *s.Status, nil
}