Skip to content

Commit b68962a

Browse files
authored
Merge pull request #1971 from dubek/exporters-secadvisor-encode-as-json-object
contrib/exporters/secadvisor: Encode flows in a JSON object
2 parents 3d25ea1 + 83263a7 commit b68962a

File tree

9 files changed

+187
-23
lines changed

9 files changed

+187
-23
lines changed

contrib/exporters/allinone/allinone.yml.default

+2-2
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ pipeline:
1414
# - internal
1515
# - other
1616
transform:
17-
type: sa
18-
sa:
17+
type: secadvisor
18+
secadvisor:
1919
# exclude_started_flows: true
2020
store:
2121
type: buffered

contrib/exporters/allinone/main.go

+4-3
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,15 @@ package main
2020
import (
2121
aws "github.com/skydive-project/skydive/contrib/exporters/awsflowlogs/mod"
2222
"github.com/skydive-project/skydive/contrib/exporters/core"
23-
sa "github.com/skydive-project/skydive/contrib/exporters/secadvisor/mod"
23+
secadvisor "github.com/skydive-project/skydive/contrib/exporters/secadvisor/mod"
2424
)
2525

2626
func main() {
27-
core.Main("/etc/skydive/uber.yml")
27+
core.Main("/etc/skydive/allinone.yml")
2828
}
2929

3030
func init() {
31+
core.EncoderHandlers.Register("secadvisor", secadvisor.NewEncode, false)
3132
core.TransformerHandlers.Register("awsflowlogs", aws.NewTransform, false)
32-
core.TransformerHandlers.Register("vpclogs", sa.NewTransform, false)
33+
core.TransformerHandlers.Register("vpclogs", secadvisor.NewTransform, false)
3334
}

contrib/exporters/core/encode.go

+12-10
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,13 @@ import (
2525
"github.com/spf13/viper"
2626
)
2727

28-
type encodeJSON struct {
28+
// EncodeJSON encoder encodes flows as a JSON array
29+
type EncodeJSON struct {
2930
pretty bool
3031
}
3132

32-
// Encode explements Encounter interface
33-
func (e *encodeJSON) Encode(in interface{}) ([]byte, error) {
33+
// Encode implements Encoder interface
34+
func (e *EncodeJSON) Encode(in interface{}) ([]byte, error) {
3435
buf := new(bytes.Buffer)
3536
encoder := json.NewEncoder(buf)
3637

@@ -45,22 +46,23 @@ func (e *encodeJSON) Encode(in interface{}) ([]byte, error) {
4546
return buf.Bytes(), nil
4647
}
4748

48-
// NewEncodeJSON create an encode object
49+
// NewEncodeJSON creates an encode object
4950
func NewEncodeJSON(cfg *viper.Viper) (interface{}, error) {
50-
return &encodeJSON{
51+
return &EncodeJSON{
5152
pretty: cfg.GetBool(CfgRoot + "encode.json.pretty"),
5253
}, nil
5354
}
5455

55-
type encodeCSV struct {
56+
// EncodeCSV encoder encodes flows as CSV rows
57+
type EncodeCSV struct {
5658
}
5759

58-
// Encode explements Encounter interface
59-
func (e *encodeCSV) Encode(in interface{}) ([]byte, error) {
60+
// Encode implements Encoder interface
61+
func (e *EncodeCSV) Encode(in interface{}) ([]byte, error) {
6062
return gocsv.MarshalBytes(in)
6163
}
6264

63-
// NewEncodeCSV create an encode object
65+
// NewEncodeCSV creates an encode object
6466
func NewEncodeCSV(cfg *viper.Viper) (interface{}, error) {
65-
return &encodeCSV{}, nil
67+
return &EncodeCSV{}, nil
6668
}

contrib/exporters/secadvisor/main.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -27,5 +27,6 @@ func main() {
2727
}
2828

2929
func init() {
30-
core.TransformerHandlers.Register("sa", mod.NewTransform, false)
30+
core.EncoderHandlers.Register("secadvisor", mod.NewEncode, true)
31+
core.TransformerHandlers.Register("secadvisor", mod.NewTransform, true)
3132
}
+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*
2+
* Copyright (C) 2019 IBM, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy ofthe License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specificlanguage governing permissions and
14+
* limitations under the License.
15+
*
16+
*/
17+
18+
package mod
19+
20+
import (
21+
"github.com/spf13/viper"
22+
23+
"github.com/skydive-project/skydive/contrib/exporters/core"
24+
)
25+
26+
type encode struct {
27+
*core.EncodeJSON
28+
}
29+
30+
type topLevelObject struct {
31+
Data []interface{} `json:"data"`
32+
}
33+
34+
// Encode the incoming flows array as a JSON object with key "data" whose value
35+
// holds the array
36+
func (e *encode) Encode(in interface{}) ([]byte, error) {
37+
return e.EncodeJSON.Encode(topLevelObject{Data: in.([]interface{})})
38+
}
39+
40+
// NewEncode creates an encode object for Secadvisor format
41+
func NewEncode(cfg *viper.Viper) (interface{}, error) {
42+
jsonEncoder, err := core.NewEncodeJSON(cfg)
43+
if err != nil {
44+
return nil, err
45+
}
46+
return &encode{jsonEncoder.(*core.EncodeJSON)}, nil
47+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
/*
2+
* Copyright (C) 2019 IBM, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy ofthe License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specificlanguage governing permissions and
14+
* limitations under the License.
15+
*
16+
*/
17+
18+
package mod
19+
20+
import (
21+
"encoding/json"
22+
"reflect"
23+
"testing"
24+
25+
"github.com/spf13/viper"
26+
27+
"github.com/skydive-project/skydive/contrib/exporters/core"
28+
)
29+
30+
func areEqualJSON(buf1, buf2 []byte) (bool, error) {
31+
var o1 interface{}
32+
var o2 interface{}
33+
34+
var err error
35+
err = json.Unmarshal(buf1, &o1)
36+
if err != nil {
37+
return false, err
38+
}
39+
err = json.Unmarshal(buf2, &o2)
40+
if err != nil {
41+
return false, err
42+
}
43+
return reflect.DeepEqual(o1, o2), nil
44+
}
45+
46+
func getEncoder(t *testing.T) core.Encoder {
47+
cfg := viper.New()
48+
encoder, err := NewEncode(cfg)
49+
if err != nil {
50+
t.Fatalf("NewEncode returned unexpected error: %v", err)
51+
}
52+
return encoder.(core.Encoder)
53+
}
54+
55+
func Test_Encode_empty_flows_array(t *testing.T) {
56+
in := make([]interface{}, 0)
57+
result, err := getEncoder(t).Encode(in)
58+
if err != nil {
59+
t.Fatalf("Encode returned unexpected error: %v", err)
60+
}
61+
expected := []byte(
62+
`{
63+
"data": []
64+
}`)
65+
equal, err := areEqualJSON(expected, result)
66+
if err != nil {
67+
t.Fatalf("Error parsing JSON: %v", err)
68+
}
69+
if !equal {
70+
t.Fatalf("Objects not identical")
71+
}
72+
}
73+
74+
func Test_Encode_flows_array_with_objects(t *testing.T) {
75+
in := []interface{}{
76+
&SecurityAdvisorFlow{
77+
Status: "STARTED",
78+
Start: 1234,
79+
},
80+
&SecurityAdvisorFlow{
81+
Status: "ENDED",
82+
Last: 5678,
83+
},
84+
}
85+
result, err := getEncoder(t).Encode(in)
86+
if err != nil {
87+
t.Fatalf("Encode returned unexpected error: %v", err)
88+
}
89+
expected := []byte(
90+
`{
91+
"data": [
92+
{
93+
"Status": "STARTED",
94+
"Start": 1234,
95+
"Last": 0,
96+
"UpdateCount": 0
97+
},
98+
{
99+
"Status": "ENDED",
100+
"Start": 0,
101+
"Last": 5678,
102+
"UpdateCount": 0
103+
}
104+
]
105+
}`)
106+
equal, err := areEqualJSON(expected, result)
107+
if err != nil {
108+
t.Fatalf("Error parsing JSON: %v", err)
109+
}
110+
if !equal {
111+
t.Fatalf("Objects not identical")
112+
}
113+
}

contrib/exporters/secadvisor/mod/transform.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ import (
3131

3232
// NewTransform creates a new flow transformer based on a name string
3333
func NewTransform(cfg *viper.Viper) (interface{}, error) {
34-
excludeStartedFlows := cfg.GetBool(core.CfgRoot + "transform.sa.exclude_started_flows")
34+
excludeStartedFlows := cfg.GetBool(core.CfgRoot + "transform.secadvisor.exclude_started_flows")
3535

3636
resolver := NewResolveRunc(cfg)
3737
resolver = NewResolveMulti(resolver)

contrib/exporters/secadvisor/secadvisor.yml.default

+4-4
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,13 @@ pipeline:
2525
# exclude the following classified tags
2626
excluded_tags:
2727
- other
28-
# transform to sa record structure
28+
# transform to secadvisor record structure
2929
transform:
30-
type: sa
31-
sa:
30+
type: secadvisor
31+
secadvisor:
3232
exclude_started_flows: true
3333
encode:
34-
type: json
34+
type: secadvisor
3535
json:
3636
pretty: true
3737
compress:

contrib/exporters/vpclogs/main.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,13 @@ package main
1919

2020
import (
2121
"github.com/skydive-project/skydive/contrib/exporters/core"
22-
sa "github.com/skydive-project/skydive/contrib/exporters/secadvisor/mod"
22+
secadvisor "github.com/skydive-project/skydive/contrib/exporters/secadvisor/mod"
2323
)
2424

2525
func main() {
2626
core.Main("/etc/skydive/vpclogs.yml")
2727
}
2828

2929
func init() {
30-
core.TransformerHandlers.Register("vpclogs", sa.NewTransform, false)
30+
core.TransformerHandlers.Register("vpclogs", secadvisor.NewTransform, false)
3131
}

0 commit comments

Comments
 (0)