Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 38 additions & 21 deletions cmd/bench.go
Original file line number Diff line number Diff line change
@@ -1,26 +1,30 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright (C) 2023 The Falco Authors.
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.
*/
// Copyright (C) 2026 The Falco Authors
//
// 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 cmd

import (
"errors"
"fmt"
"time"

"github.com/go-logr/logr"
logger "github.com/sirupsen/logrus"
"github.com/spf13/cobra"

"github.com/falcosecurity/event-generator/cmd/internal/alertretriever"
"github.com/falcosecurity/event-generator/pkg/counter"
"github.com/falcosecurity/event-generator/pkg/runner"
)
Expand All @@ -41,7 +45,7 @@ If the "--loop" option is set, the sleeping duration is halved on each round.
The "--pid" option can be used to monitor the Falco process.

N.B.:
- the Falco gRPC Output must be enabled to use this command
- the Falco HTTP Output must be enabled to use this command
- "outputs.rate" and "outputs.max_burst" values within the Falco configuration must be increased,
otherwise EPS will be rate-limited by the throttling mechanism
- since not all actions can be used for benchmarking,
Expand All @@ -62,18 +66,22 @@ One commmon way to use this command is as following:
flags.IntVar(&pid, "pid", 0, "A process PID to monitor while benchmarking (e.g. the falco process)")
var roundDuration time.Duration
flags.DurationVar(&roundDuration, "round-duration", time.Second*5, "Duration of a benchmark round")
var pollingTimeout time.Duration
flags.DurationVar(&pollingTimeout, "polling-interval", time.Millisecond*100, "Duration of gRPC APIs polling timeout")
var humanize bool
flags.BoolVar(&humanize, "humanize", true, "Humanize values when printing statistics")
var dryRun bool
flags.BoolVar(&dryRun, "dry-run", false, "Do not connect to Falco gRPC API")
flags.BoolVar(&dryRun, "dry-run", false, "Do not expose an HTTP server for Falco HTTP Output")

grpcCfg := grpcFlags(flags)
alertRetrieverConfig := alertretriever.Config{}
alertRetrieverConfig.InitCommandFlags(c)

l := logger.StandardLogger()
counterLogger := logger.StandardLogger()

c.RunE = func(c *cobra.Command, args []string) error {
ctx := c.Context()
mainLogger, err := logr.FromContext(ctx)
if err != nil {
panic(fmt.Sprintf("logger unconfigured: %v", err))
}

evts, err := parseEventsArg(args[0])
if err != nil {
Expand All @@ -94,20 +102,29 @@ One commmon way to use this command is as following:
return errRoundDurationMustBeLongerThanSleep
}

alertRetriever, err := alertRetrieverConfig.Build(mainLogger)
if err != nil {
return fmt.Errorf("error building alert retriever: %w", err)
}

alertCh, err := alertRetriever.AlertStream(ctx)
if err != nil {
return fmt.Errorf("error creating alert stream: %w", err)
}

opts := append([]counter.Option(nil),
counter.WithActions(evts),
counter.WithLogger(l),
counter.WithLogger(counterLogger),
counter.WithLoop(loop),
counter.WithSleep(sleep),
counter.WithRoundDuration(roundDuration),
counter.WithPollingTimeout(pollingTimeout),
counter.WithHumanize(humanize),
counter.WithDryRun(dryRun),
)
if pid != 0 {
opts = append(opts, counter.WithPid(pid))
}
p, err := counter.New(c.Context(), grpcCfg, opts...)
p, err := counter.New(ctx, alertCh, opts...)
if err != nil {
return err
}
Expand Down
39 changes: 13 additions & 26 deletions cmd/common.go
Original file line number Diff line number Diff line change
@@ -1,26 +1,24 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright (C) 2023 The Falco Authors.
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.
*/
// Copyright (C) 2026 The Falco Authors
//
// 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 cmd

import (
"fmt"
"regexp"

"github.com/falcosecurity/client-go/pkg/client"
"github.com/spf13/pflag"

"github.com/falcosecurity/event-generator/events"
)

Expand All @@ -37,14 +35,3 @@ func parseEventsArg(arg string) (map[string]events.Action, error) {

return evts, nil
}

func grpcFlags(flags *pflag.FlagSet) *client.Config {
grpcCfg := &client.Config{}
flags.StringVar(&grpcCfg.UnixSocketPath, "grpc-unix-socket", "unix:///run/falco/falco.sock", "Unix socket path for connecting to a Falco gRPC server")
flags.StringVar(&grpcCfg.Hostname, "grpc-hostname", "localhost", "Hostname for connecting to a Falco gRPC server")
flags.Uint16Var(&grpcCfg.Port, "grpc-port", 5060, "Port for connecting to a Falco gRPC server")
flags.StringVar(&grpcCfg.CertFile, "grpc-cert", "/etc/falco/certs/client.crt", "Cert file path for connecting to a Falco gRPC server")
flags.StringVar(&grpcCfg.KeyFile, "grpc-key", "/etc/falco/certs/client.key", "Key file path for connecting to a Falco gRPC server")
flags.StringVar(&grpcCfg.CARootFile, "grpc-ca", "/etc/falco/certs/ca.crt", "CA root file path for connecting to a Falco gRPC server")
return grpcCfg
}
102 changes: 102 additions & 0 deletions cmd/internal/alertretriever/alertretriever.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright (C) 2026 The Falco Authors
//
// 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 alertretriever

import (
"fmt"

"github.com/go-logr/logr"
"github.com/spf13/cobra"
"github.com/thediveo/enumflag"

"github.com/falcosecurity/event-generator/pkg/alert"
"github.com/falcosecurity/event-generator/pkg/alert/retriever/httpretriever"
)

// securityMode defines the types of security mode used by the HTTP alert retriever.
type securityMode int

const (
// securityModeInsecure specifies that the HTTP alert retriever shouldn't use any form of security.
securityModeInsecure securityMode = iota
// securityModeTLS specifies that the HTTP alert retriever should use TLS.
securityModeTLS
// securityModeMutualTLS specifies that the HTTP alert retriever should use mTLS.
securityModeMutualTLS
)

var securityModes = map[securityMode][]string{
securityModeInsecure: {"insecure"},
securityModeTLS: {"tls"},
securityModeMutualTLS: {"mtls"},
}

// Config holds the HTTP alert retriever configuration and builds an alert.Retriever from it.
type Config struct {
address string
securityMode securityMode
certFile string
keyFile string
caRootFile string
}

// InitCommandFlags initializes the provided command's flags and uses the config instance to store the flag bound
// values.
func (c *Config) InitCommandFlags(cmd *cobra.Command) {
flags := cmd.Flags()
flags.StringVar(&c.address, "http-server-address", "localhost:8080",
"The address the alert retriever HTTP server must be bound to")
flags.Var(
enumflag.New(&c.securityMode, "http-server-security-mode", securityModes, enumflag.EnumCaseInsensitive),
"http-server-security-mode",
"The security mode the alert retriever HTTP server must use; can be 'insecure', 'tls' or 'mtls'")
flags.StringVar(&c.certFile, "http-server-cert", "/etc/falco/certs/server.crt",
"The path of the server certificate to be used for TLS against the Falco HTTP client (to be used together "+
"with --http-server-security-mode=(tls|mtls))")
flags.StringVar(&c.keyFile, "http-server-key", "/etc/falco/certs/server.key",
"The path of the server private key to be used for TLS against the Falco HTTP client (to be used together "+
"with --http-server-security-mode=(tls|mtls))")
flags.StringVar(&c.caRootFile, "http-client-ca", "/etc/falco/certs/ca.crt",
"The path of the CA root certificate used for Falco HTTP client's certificate validation (to be used together "+
"with --http-server-security-mode=mtls)")
}

// Build builds an alert.Retriever from the current configuration.
func (c *Config) Build(logger logr.Logger) (alert.Retriever, error) {
securityMode := decodeSecurityMode(c.securityMode)
httpRetrieverOptions := []httpretriever.Option{
httpretriever.WithAddress(c.address),
httpretriever.WithSecurityMode(securityMode),
httpretriever.WithCertFile(c.certFile),
httpretriever.WithKeyFile(c.keyFile),
httpretriever.WithCARootFile(c.caRootFile),
}
return httpretriever.New(logger.WithName("alert-retriever"), httpRetrieverOptions...)
}

// decodeSecurityMode decodes the provided security mode into something suitable for the HTTP retriever.
func decodeSecurityMode(securityMode securityMode) httpretriever.SecurityMode {
switch securityMode {
case securityModeInsecure:
return httpretriever.SecurityModeInsecure
case securityModeTLS:
return httpretriever.SecurityModeTLS
case securityModeMutualTLS:
return httpretriever.SecurityModeMutualTLS
default:
panic(fmt.Sprintf("unsupported security mode %v", securityMode))
}
}
18 changes: 18 additions & 0 deletions cmd/internal/alertretriever/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright (C) 2026 The Falco Authors
//
// 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 alertretriever defines a Config object that allows to store the configuration for an HTTP alert retriever and
// build it.
package alertretriever
2 changes: 1 addition & 1 deletion cmd/suite/test/doc.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright (C) 2025 The Falco Authors
// Copyright (C) 2026 The Falco Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand Down
48 changes: 10 additions & 38 deletions cmd/suite/test/test.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright (C) 2025 The Falco Authors
// Copyright (C) 2026 The Falco Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -31,8 +31,8 @@ import (
"github.com/spf13/pflag"
"github.com/thediveo/enumflag"

"github.com/falcosecurity/event-generator/cmd/internal/alertretriever"
"github.com/falcosecurity/event-generator/cmd/suite/config"
"github.com/falcosecurity/event-generator/pkg/alert/retriever/grpcretriever"
"github.com/falcosecurity/event-generator/pkg/baggage"
containerbuilder "github.com/falcosecurity/event-generator/pkg/container/builder"
processbuilder "github.com/falcosecurity/event-generator/pkg/process/builder"
Expand Down Expand Up @@ -62,7 +62,7 @@ const (
const (
longDescriptionPrefaceTemplate = `%s.
It is possible to provide the YAML description in multiple ways. The order of evaluation is the following:
1) If the --%s=<file_path> flag is provided the description is read from the file at <file_path>
1) If --%s=<file_path> and/or --%s=<dir_path> flags are/is provided, the description is read from the file at <file_path>
2) If the --%s=<description> flag is provided, the description is read from the <description> string
3) Otherwise, it is read from standard input`
longDescriptionHeading = "Run test(s) specified via a YAML description and verify that they produce the expected outcomes"
Expand All @@ -73,7 +73,7 @@ It is possible to provide the YAML description in multiple ways. The order of ev

var (
longDescriptionPreface = fmt.Sprintf(longDescriptionPrefaceTemplate, longDescriptionHeading,
config.DescriptionFileFlagName, config.DescriptionFlagName)
config.DescriptionFileFlagName, config.DescriptionDirFlagName, config.DescriptionFlagName)
longDescription = fmt.Sprintf("%s\n\n%s", longDescriptionPreface, warningMessage)
)

Expand All @@ -100,13 +100,7 @@ type CommandWrapper struct {
*config.Config
Command *cobra.Command
skipOutcomeVerification bool
unixSocketPath string
hostname string
port uint16
certFile string
keyFile string
caRootFile string
pollingTimeout time.Duration
AlertRetrieverConfig alertretriever.Config
reportFormat reportFormat
}

Expand Down Expand Up @@ -142,21 +136,8 @@ func (cw *CommandWrapper) initFlags(c *cobra.Command) {
flags := c.Flags()

flags.BoolVar(&cw.skipOutcomeVerification, "skip-outcome-verification", false,
"Skip verification of the expected outcome. If this option is enabled, grpc- flags are ignored")
flags.StringVar(&cw.unixSocketPath, "grpc-unix-socket", "",
"The unix socket path of the local Falco instance (use only if you want to connect to Falco through a "+
"unix socket)")
flags.StringVar(&cw.hostname, "grpc-hostname", "localhost",
"The Falco gRPC server hostname")
flags.Uint16Var(&cw.port, "grpc-port", 5060, "The Falco gRPC server port")
flags.StringVar(&cw.certFile, "grpc-cert", "/etc/falco/certs/client.crt",
"The path of the client certificate to be used for mutual TLS against the Falco gRPC server")
flags.StringVar(&cw.keyFile, "grpc-key", "/etc/falco/certs/client.key",
"The path of the client private key to be used for mutual TLS against the Falco gRPC server")
flags.StringVar(&cw.caRootFile, "grpc-ca", "/etc/falco/certs/ca.crt",
"The path of the CA root certificate used for Falco gRPC server's certificate validation")
flags.DurationVar(&cw.pollingTimeout, "grpc-poll-timeout", 100*time.Millisecond,
"The frequency of the watch operation on the gRPC Falco Outputs API stream")
"Skip verification of the expected outcome. If this option is enabled, http- flags are ignored")
cw.AlertRetrieverConfig.InitCommandFlags(c)
flags.Var(
enumflag.New(&cw.reportFormat, "report-format", reportFormats, enumflag.EnumCaseInsensitive),
"report-format", "The format of the test suites report; can be 'text', 'json' or 'yaml'")
Expand Down Expand Up @@ -502,21 +483,12 @@ func (cw *CommandWrapper) createRunnerBuilder() (runner.Builder, error) {

// createTester creates a new tester.
func (cw *CommandWrapper) createTester(logger logr.Logger) (tester.Tester, error) {
gRPCRetrieverOptions := []grpcretriever.Option{
grpcretriever.WithUnixSocketPath(cw.unixSocketPath),
grpcretriever.WithHostname(cw.hostname),
grpcretriever.WithPort(cw.port),
grpcretriever.WithCertFile(cw.certFile),
grpcretriever.WithKeyFile(cw.keyFile),
grpcretriever.WithCARootFile(cw.caRootFile),
grpcretriever.WithPollingTimeout(cw.pollingTimeout),
}
grpcRetriever, err := grpcretriever.New(logger.WithName("alert-retriever"), gRPCRetrieverOptions...)
httpRetriever, err := cw.AlertRetrieverConfig.Build(logger.WithName("alert-retriever"))
if err != nil {
return nil, fmt.Errorf("error creating gRPC retriever: %w", err)
return nil, fmt.Errorf("error creating HTTP retriever: %w", err)
}

t := testerimpl.New(grpcRetriever, cw.TestIDEnvKey, testIDIgnorePrefix)
t := testerimpl.New(httpRetriever, cw.TestIDEnvKey, testIDIgnorePrefix)
return t, nil
}

Expand Down
Loading
Loading