Skip to content

Commit bd822be

Browse files
authored
feat(output): New http output (#110)
* base HTTP output structure * more work around HTTP output * HTTP output tests, registration and polishing * HTTP output config and validation schema
1 parent b0e7a88 commit bd822be

18 files changed

Lines changed: 873 additions & 19 deletions

File tree

cmd/fibratus/app/control_service_windows.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,20 +20,22 @@ package app
2020

2121
import (
2222
"fmt"
23+
"time"
24+
2325
"github.com/rabbitstack/fibratus/cmd/fibratus/common"
2426
"github.com/rabbitstack/fibratus/pkg/aggregator"
2527
"github.com/rabbitstack/fibratus/pkg/api"
2628
"github.com/rabbitstack/fibratus/pkg/config"
2729
"github.com/rabbitstack/fibratus/pkg/handle"
2830
"github.com/rabbitstack/fibratus/pkg/kstream"
2931
"github.com/rabbitstack/fibratus/pkg/ps"
32+
ver "github.com/rabbitstack/fibratus/pkg/util/version"
3033
"github.com/spf13/cobra"
3134
"golang.org/x/sys/windows"
3235
"golang.org/x/sys/windows/svc"
3336
"golang.org/x/sys/windows/svc/debug"
3437
"golang.org/x/sys/windows/svc/eventlog"
3538
"golang.org/x/sys/windows/svc/mgr"
36-
"time"
3739
)
3840

3941
var startSvcCmd = &cobra.Command{
@@ -216,7 +218,7 @@ func (s *fsvc) run() error {
216218
if err := common.Init(svcConfig, true); err != nil {
217219
return err
218220
}
219-
221+
ver.Set(version)
220222
ctrl = kstream.NewKtraceController(svcConfig.Kstream)
221223
err := ctrl.StartKtrace()
222224
if err != nil {

cmd/fibratus/app/replay_windows.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,15 @@ package app
2020

2121
import (
2222
"context"
23+
2324
"github.com/rabbitstack/fibratus/cmd/fibratus/common"
2425
"github.com/rabbitstack/fibratus/pkg/aggregator"
2526
"github.com/rabbitstack/fibratus/pkg/api"
2627
"github.com/rabbitstack/fibratus/pkg/config"
2728
"github.com/rabbitstack/fibratus/pkg/filament"
2829
"github.com/rabbitstack/fibratus/pkg/filter"
2930
"github.com/rabbitstack/fibratus/pkg/kcap"
31+
ver "github.com/rabbitstack/fibratus/pkg/util/version"
3032
"github.com/spf13/cobra"
3133
)
3234

@@ -50,7 +52,7 @@ func replay(cmd *cobra.Command, args []string) error {
5052
if err := common.Init(replayConfig, false); err != nil {
5153
return err
5254
}
53-
55+
ver.Set(version)
5456
// set up the signals
5557
stopCh := common.Signals()
5658

cmd/fibratus/app/run_windows.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ package app
2121
import (
2222
"os"
2323

24+
ver "github.com/rabbitstack/fibratus/pkg/util/version"
25+
2426
"github.com/rabbitstack/fibratus/cmd/fibratus/common"
2527
"github.com/rabbitstack/fibratus/pkg/aggregator"
2628
"github.com/rabbitstack/fibratus/pkg/alertsender"
@@ -71,7 +73,7 @@ func run(cmd *cobra.Command, args []string) error {
7173
if err := common.Init(cfg, true); err != nil {
7274
return err
7375
}
74-
76+
ver.Set(version)
7577
// set up the signals
7678
stopCh := common.Signals()
7779

configs/fibratus.yml

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,55 @@ output:
359359
# Indicates if the chain and host verification stage is skipped
360360
#tls-insecure-skip-verify: false
361361

362+
# HTTP output sends event batches to HTTP servers.
363+
http:
364+
# Indicates if the HTTP output is enabled
365+
enabled: false
366+
367+
# List of endpoints to which the events are sent
368+
#endpoints:
369+
# - http://localhost:8081
370+
371+
# Represents the timeout for the HTTP requests
372+
#timeout: 5s
373+
374+
# Specifies the HTTP proxy URL. It overrides the HTTP proxy URL as indicated by the environment variables
375+
#proxy-url: ""
376+
377+
# The username for HTTP proxy authentication
378+
#proxy-username: ""
379+
380+
# The password for HTTP proxy authentication
381+
#proxy-password: ""
382+
383+
# Determines the HTTP verb to use in requests
384+
#method: POST
385+
386+
# Username for the basic HTTP authentication
387+
#username: ""
388+
389+
# Password for the basic HTTP authentication
390+
#password: ""
391+
392+
# If enabled, the HTTP body is compressed with gzip compression
393+
#enable-gzip: false
394+
395+
# List of arbitrary headers to include in HTTP requests
396+
#headers:
397+
# api-key: ""
398+
399+
# Path to the public/private key file
400+
#tls-key:
401+
402+
# Path to certificate file
403+
#tls-cert:
404+
405+
# Represents the path of the certificate file that is associated with the Certification Authority (CA)
406+
#tls-ca:
407+
408+
# Indicates if the chain and host verification stage is skipped
409+
#tls-insecure-skip-verify: false
410+
362411
# =============================== Portable Executable (PE) =============================
363412

364413
# Tweaks for controlling the fetching of the PE (Portable Executable) metadata from the process' binary image.

pkg/aggregator/aggregator.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,20 +21,25 @@ package aggregator
2121
import (
2222
"errors"
2323
"expvar"
24+
"time"
25+
2426
"github.com/rabbitstack/fibratus/pkg/aggregator/transformers"
2527
"github.com/rabbitstack/fibratus/pkg/alertsender"
2628
"github.com/rabbitstack/fibratus/pkg/kevent"
2729
"github.com/rabbitstack/fibratus/pkg/outputs"
2830
log "github.com/sirupsen/logrus"
29-
"time"
31+
3032
// initialize outputs
3133
_ "github.com/rabbitstack/fibratus/pkg/outputs/amqp"
3234
_ "github.com/rabbitstack/fibratus/pkg/outputs/console"
3335
_ "github.com/rabbitstack/fibratus/pkg/outputs/elasticsearch"
36+
_ "github.com/rabbitstack/fibratus/pkg/outputs/http"
3437
_ "github.com/rabbitstack/fibratus/pkg/outputs/null"
38+
3539
// initialize alert senders
3640
_ "github.com/rabbitstack/fibratus/pkg/alertsender/mail"
3741
_ "github.com/rabbitstack/fibratus/pkg/alertsender/slack"
42+
3843
// initialize transformers
3944
_ "github.com/rabbitstack/fibratus/pkg/aggregator/transformers/remove"
4045
_ "github.com/rabbitstack/fibratus/pkg/aggregator/transformers/rename"

pkg/config/_fixtures/fibratus.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,12 @@ output:
162162
exchange-type: topic
163163
routing-key: fibratus
164164
vhost: /
165+
http:
166+
enabled: false
167+
endpoints:
168+
- http://localhost:8081
169+
timeout: 5s
170+
method: POST
165171

166172
# =============================== Portable Executable (PE) =============================
167173

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
kstream:
2+
max-buffers: 10
3+
min-buffers: 8
4+
flush-interval: 1s
5+
blacklist:
6+
events:
7+
- CreateThread
8+
9+
filament: top_hives_io
10+
11+
output:
12+
console:
13+
enabled: false
14+
format: pretty
15+
elasticsearch:
16+
http:
17+
enabled: true
18+
endpoints:
19+
- http://localhost:8081
20+
- http://localhost:8082
21+
timeout: 2s
22+
proxy-url: http://192.168.1.8:3123
23+
proxy-username: bunny
24+
proxy-password: bunny
25+
username: basic
26+
password: basic
27+
enable-gzip: true
28+
headers:
29+
api-Key: kkvvkk
30+
header2: value2

pkg/config/config_windows.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ import (
2424
"io/ioutil"
2525
"time"
2626

27+
"github.com/rabbitstack/fibratus/pkg/outputs/http"
28+
2729
"github.com/rabbitstack/fibratus/pkg/aggregator"
2830
"github.com/rabbitstack/fibratus/pkg/aggregator/transformers"
2931
removet "github.com/rabbitstack/fibratus/pkg/aggregator/transformers/remove"
@@ -185,6 +187,7 @@ func NewWithOpts(options ...Option) *Config {
185187
console.AddFlags(flagSet)
186188
amqp.AddFlags(flagSet)
187189
elasticsearch.AddFlags(flagSet)
190+
http.AddFlags(flagSet)
188191
removet.AddFlags(flagSet)
189192
replacet.AddFlags(flagSet)
190193
renamet.AddFlags(flagSet)

pkg/config/output.go

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,17 @@ package config
2121
import (
2222
"errors"
2323
"fmt"
24+
"reflect"
25+
"strconv"
26+
2427
"github.com/rabbitstack/fibratus/pkg/outputs"
2528
"github.com/rabbitstack/fibratus/pkg/outputs/amqp"
2629
"github.com/rabbitstack/fibratus/pkg/outputs/console"
2730
"github.com/rabbitstack/fibratus/pkg/outputs/elasticsearch"
31+
"github.com/rabbitstack/fibratus/pkg/outputs/http"
2832
"github.com/rabbitstack/fibratus/pkg/outputs/null"
2933
log "github.com/sirupsen/logrus"
3034
"golang.org/x/sys/windows/svc"
31-
"reflect"
32-
"strconv"
3335
)
3436

3537
var errNoOutputSection = errors.New("no output section in config")
@@ -71,8 +73,8 @@ func (c *Config) tryLoadOutput() error {
7173
}
7274

7375
for typ, config := range mapping {
74-
switch typ {
75-
case "console":
76+
switch outputs.TypeFromString(typ) {
77+
case outputs.Console:
7678
var consoleConfig console.Config
7779
if err := decode(config, &consoleConfig); err != nil {
7880
return errOutputConfig(typ, err)
@@ -82,7 +84,7 @@ func (c *Config) tryLoadOutput() error {
8284
}
8385
c.Output.Type, c.Output.Output = outputs.Console, consoleConfig
8486

85-
case "amqp":
87+
case outputs.AMQP:
8688
var amqpConfig amqp.Config
8789
if err := decode(config, &amqpConfig); err != nil {
8890
return errOutputConfig(typ, err)
@@ -92,7 +94,7 @@ func (c *Config) tryLoadOutput() error {
9294
}
9395
c.Output.Type, c.Output.Output = outputs.AMQP, amqpConfig
9496

95-
case "elasticsearch":
97+
case outputs.Elasticsearch:
9698
var esConfig elasticsearch.Config
9799
if err := decode(config, &esConfig); err != nil {
98100
return errOutputConfig(typ, err)
@@ -101,13 +103,22 @@ func (c *Config) tryLoadOutput() error {
101103
continue
102104
}
103105
c.Output.Type, c.Output.Output = outputs.Elasticsearch, esConfig
106+
107+
case outputs.HTTP:
108+
var httpConfig http.Config
109+
if err := decode(config, &httpConfig); err != nil {
110+
return errOutputConfig(typ, err)
111+
}
112+
if !httpConfig.Enabled {
113+
continue
114+
}
115+
c.Output.Type, c.Output.Output = outputs.HTTP, httpConfig
104116
}
105117
}
106118

107119
// if it is not an interactive session but the console output is enabled
108120
// we default to null output and warn about that
109-
in, err := svc.IsAnInteractiveSession()
110-
if err == nil && !in && c.Output.Output != nil {
121+
if isWindowsService() && c.Output.Output != nil {
111122
if c.Output.Type == outputs.Console {
112123
log.Warn("running in non-interactive session with console output. " +
113124
"Please configure a different output type. Defaulting to null output")
@@ -135,3 +146,12 @@ func findActiveOutputs(outputs map[string]interface{}) []string {
135146
}
136147
return outputTypes
137148
}
149+
150+
// isWindowsService returns true if the process is running inside Windows Service.
151+
func isWindowsService() bool {
152+
interactive, err := svc.IsAnInteractiveSession()
153+
if err != nil {
154+
return false
155+
}
156+
return !interactive
157+
}

pkg/config/output_test.go

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,16 @@
1919
package config
2020

2121
import (
22+
"testing"
23+
"time"
24+
2225
"github.com/rabbitstack/fibratus/pkg/outputs/amqp"
26+
"github.com/rabbitstack/fibratus/pkg/outputs/http"
2327
"github.com/stretchr/testify/assert"
2428
"github.com/stretchr/testify/require"
25-
"testing"
26-
"time"
2729
)
2830

29-
func TestOutput(t *testing.T) {
31+
func TestAMQPOutput(t *testing.T) {
3032
c := NewWithOpts(WithRun())
3133

3234
err := c.flags.Parse([]string{"--config-file=_fixtures/output.yml"})
@@ -47,3 +49,31 @@ func TestOutput(t *testing.T) {
4749
assert.Equal(t, "fibratus", amqpConfig.RoutingKey)
4850
assert.Equal(t, "/", amqpConfig.Vhost)
4951
}
52+
53+
func TestHTTPOutput(t *testing.T) {
54+
c := NewWithOpts(WithRun())
55+
56+
err := c.flags.Parse([]string{"--config-file=_fixtures/http-output.yml"})
57+
require.NoError(t, c.viper.BindPFlags(c.flags))
58+
require.NoError(t, err)
59+
require.NoError(t, c.TryLoadFile(c.GetConfigFile()))
60+
61+
require.NoError(t, c.Init())
62+
63+
require.NotNil(t, c.Output)
64+
require.IsType(t, http.Config{}, c.Output.Output)
65+
66+
httpConfig := c.Output.Output.(http.Config)
67+
assert.True(t, httpConfig.Enabled)
68+
assert.Len(t, httpConfig.Endpoints, 2)
69+
assert.Contains(t, httpConfig.Endpoints, "http://localhost:8081")
70+
assert.Equal(t, time.Second*2, httpConfig.Timeout)
71+
assert.Equal(t, "http://192.168.1.8:3123", httpConfig.ProxyURL)
72+
assert.Equal(t, "bunny", httpConfig.ProxyUsername)
73+
assert.Equal(t, "bunny", httpConfig.ProxyPassword)
74+
assert.True(t, httpConfig.EnableGzip)
75+
assert.Equal(t, "basic", httpConfig.Username)
76+
assert.Equal(t, "basic", httpConfig.Password)
77+
assert.Len(t, httpConfig.Headers, 2)
78+
assert.Equal(t, "kkvvkk", httpConfig.Headers["api-key"])
79+
}

0 commit comments

Comments
 (0)