diff --git a/exporter/cassandraexporter/README.md b/exporter/cassandraexporter/README.md index b4b6524..3795554 100644 --- a/exporter/cassandraexporter/README.md +++ b/exporter/cassandraexporter/README.md @@ -25,6 +25,7 @@ The following settings can be optionally configured: - `replication` (default = class: SimpleStrategy, replication_factor: 1): The strategy of replication. https://cassandra.apache.org/doc/4.1/cassandra/architecture/dynamo.html#replication-strategy - `compression` (default = LZ4Compressor): https://cassandra.apache.org/doc/latest/cassandra/operating/compression.html +- `auth` (default = username: "", password: "") Authorization for the Cassandra. ## Example @@ -41,4 +42,7 @@ exporters: replication_factor: 1 compression: algorithm: "ZstdCompressor" + auth: + username: "your-username" + password: "your-password" ``` diff --git a/exporter/cassandraexporter/config.go b/exporter/cassandraexporter/config.go index 2a2c6ff..97885c9 100644 --- a/exporter/cassandraexporter/config.go +++ b/exporter/cassandraexporter/config.go @@ -2,7 +2,11 @@ // SPDX-License-Identifier: Apache-2.0 package cassandraexporter // import "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/cassandraexporter" -import "time" +import ( + "time" + + "go.opentelemetry.io/collector/config/configopaque" +) type Config struct { DSN string `mapstructure:"dsn"` @@ -13,6 +17,7 @@ type Config struct { LogsTable string `mapstructure:"logs_table"` Replication Replication `mapstructure:"replication"` Compression Compression `mapstructure:"compression"` + Auth Auth `mapstructure:"auth"` } type Replication struct { @@ -23,3 +28,8 @@ type Replication struct { type Compression struct { Algorithm string `mapstructure:"algorithm"` } + +type Auth struct { + UserName string `mapstructure:"username"` + Password configopaque.String `mapstructure:"password"` +} diff --git a/exporter/cassandraexporter/exporter_logs.go b/exporter/cassandraexporter/exporter_logs.go index c37a796..78481c1 100644 --- a/exporter/cassandraexporter/exporter_logs.go +++ b/exporter/cassandraexporter/exporter_logs.go @@ -6,6 +6,7 @@ package cassandraexporter // import "github.com/open-telemetry/opentelemetry-col import ( "context" "encoding/json" + "errors" "fmt" "time" @@ -24,13 +25,16 @@ type logsExporter struct { } func newLogsExporter(logger *zap.Logger, cfg *Config) (*logsExporter, error) { - cluster := gocql.NewCluster(cfg.DSN) - session, err := cluster.CreateSession() + cluster, err := newCluster(cfg) + if err != nil { + return nil, err + } cluster.Keyspace = cfg.Keyspace cluster.Consistency = gocql.Quorum cluster.Port = cfg.Port cluster.Timeout = cfg.Timeout + session, err := cluster.CreateSession() if err != nil { return nil, err } @@ -40,7 +44,10 @@ func newLogsExporter(logger *zap.Logger, cfg *Config) (*logsExporter, error) { func initializeLogKernel(cfg *Config) error { ctx := context.Background() - cluster := gocql.NewCluster(cfg.DSN) + cluster, err := newCluster(cfg) + if err != nil { + return err + } cluster.Consistency = gocql.Quorum cluster.Port = cfg.Port cluster.Timeout = cfg.Timeout @@ -64,6 +71,25 @@ func initializeLogKernel(cfg *Config) error { return nil } +func newCluster(cfg *Config) (*gocql.ClusterConfig, error) { + cluster := gocql.NewCluster(cfg.DSN) + if cfg.Auth.UserName != "" && cfg.Auth.Password == "" { + return nil, errors.New("empty auth.password") + } + if cfg.Auth.Password != "" && cfg.Auth.UserName == "" { + return nil, errors.New("empty auth.username") + } + if cfg.Auth.UserName != "" && cfg.Auth.Password != "" { + cluster.Authenticator = gocql.PasswordAuthenticator{ + Username: cfg.Auth.UserName, + Password: string(cfg.Auth.Password), + } + } + cluster.Consistency = gocql.Quorum + cluster.Port = cfg.Port + return cluster, nil +} + func (e *logsExporter) Start(_ context.Context, _ component.Host) error { initializeErr := initializeLogKernel(e.cfg) return initializeErr diff --git a/exporter/cassandraexporter/exporter_logs_test.go b/exporter/cassandraexporter/exporter_logs_test.go new file mode 100644 index 0000000..017b14f --- /dev/null +++ b/exporter/cassandraexporter/exporter_logs_test.go @@ -0,0 +1,66 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package cassandraexporter + +import ( + "errors" + "testing" + + "github.com/gocql/gocql" + "github.com/stretchr/testify/require" +) + +func TestNewCluster(t *testing.T) { + testCases := map[string]struct { + cfg *Config + expectedAuthenticator gocql.Authenticator + expectedErr error + }{ + "empty_auth": { + cfg: withDefaultConfig(), + expectedAuthenticator: nil, + }, + "empty_username": { + cfg: withDefaultConfig(func(config *Config) { + config.Auth.Password = "pass" + }), + expectedAuthenticator: nil, + expectedErr: errors.New("empty auth.username"), + }, + "empty_password": { + cfg: withDefaultConfig(func(config *Config) { + config.Auth.UserName = "user" + }), + expectedAuthenticator: nil, + expectedErr: errors.New("empty auth.password"), + }, + "success_auth": { + cfg: withDefaultConfig(func(config *Config) { + config.Auth.UserName = "user" + config.Auth.Password = "pass" + }), + expectedAuthenticator: gocql.PasswordAuthenticator{ + Username: "user", + Password: "pass", + }, + }, + } + for name, test := range testCases { + t.Run(name, func(t *testing.T) { + c, err := newCluster(test.cfg) + if err == nil { + require.Equal(t, test.expectedAuthenticator, c.Authenticator) + } + require.Equal(t, test.expectedErr, err) + }) + } +} + +func withDefaultConfig(fns ...func(*Config)) *Config { + cfg := createDefaultConfig().(*Config) + for _, fn := range fns { + fn(cfg) + } + return cfg +} diff --git a/exporter/cassandraexporter/exporter_traces.go b/exporter/cassandraexporter/exporter_traces.go index 314aa28..b6fe091 100644 --- a/exporter/cassandraexporter/exporter_traces.go +++ b/exporter/cassandraexporter/exporter_traces.go @@ -23,13 +23,16 @@ type tracesExporter struct { } func newTracesExporter(logger *zap.Logger, cfg *Config) (*tracesExporter, error) { - cluster := gocql.NewCluster(cfg.DSN) - session, err := cluster.CreateSession() + cluster, err := newCluster(cfg) + if err != nil { + return nil, err + } cluster.Keyspace = cfg.Keyspace cluster.Consistency = gocql.Quorum cluster.Port = cfg.Port cluster.Timeout = cfg.Timeout + session, err := cluster.CreateSession() if err != nil { return nil, err } @@ -39,7 +42,10 @@ func newTracesExporter(logger *zap.Logger, cfg *Config) (*tracesExporter, error) func initializeTraceKernel(cfg *Config) error { ctx := context.Background() - cluster := gocql.NewCluster(cfg.DSN) + cluster, err := newCluster(cfg) + if err != nil { + return err + } cluster.Consistency = gocql.Quorum cluster.Port = cfg.Port cluster.Timeout = cfg.Timeout diff --git a/exporter/cassandraexporter/go.mod b/exporter/cassandraexporter/go.mod index 4e022a1..c149496 100644 --- a/exporter/cassandraexporter/go.mod +++ b/exporter/cassandraexporter/go.mod @@ -7,6 +7,7 @@ require ( github.com/open-telemetry/opentelemetry-collector-contrib/internal/coreinternal v0.92.0 github.com/stretchr/testify v1.8.4 go.opentelemetry.io/collector/component v0.92.1-0.20240112172857-83d463ceba06 + go.opentelemetry.io/collector/config/configopaque v0.92.1-0.20240112172857-83d463ceba06 go.opentelemetry.io/collector/confmap v0.92.1-0.20240112172857-83d463ceba06 go.opentelemetry.io/collector/exporter v0.92.1-0.20240112172857-83d463ceba06 go.opentelemetry.io/collector/pdata v1.0.2-0.20240112172857-83d463ceba06 diff --git a/exporter/cassandraexporter/go.sum b/exporter/cassandraexporter/go.sum index 00a3712..7cef378 100644 --- a/exporter/cassandraexporter/go.sum +++ b/exporter/cassandraexporter/go.sum @@ -279,6 +279,8 @@ go.opentelemetry.io/collector v0.92.1-0.20240112172857-83d463ceba06 h1:305NltdJC go.opentelemetry.io/collector v0.92.1-0.20240112172857-83d463ceba06/go.mod h1:3MM6b+3rjdLMf3grxk4l9Mu4udi4C2kObyaT+Z+KuoI= go.opentelemetry.io/collector/component v0.92.1-0.20240112172857-83d463ceba06 h1:2bkhiQn7O1UGsXlgxPQ3zf2pX+A4AGCxWs0SjZk1BXE= go.opentelemetry.io/collector/component v0.92.1-0.20240112172857-83d463ceba06/go.mod h1:J5ZAcv/ONu5Cdid/UzqF2T87k8ui8Z+c6n8s+640Vc8= +go.opentelemetry.io/collector/config/configopaque v0.92.1-0.20240112172857-83d463ceba06 h1:M1FjOD4ms4Mpzg9/r6ryjxNDz6dVK/2Y2yPu5syGKZo= +go.opentelemetry.io/collector/config/configopaque v0.92.1-0.20240112172857-83d463ceba06/go.mod h1:dQK8eUXjIGKaw1RB7UIg2nqx56AueNxeKFCdB0P1ypg= go.opentelemetry.io/collector/config/configretry v0.92.1-0.20240112172857-83d463ceba06 h1:o56gyZ9o4lAbcd3jP7MC3DqhIYo11qyLL0w5KB949XY= go.opentelemetry.io/collector/config/configretry v0.92.1-0.20240112172857-83d463ceba06/go.mod h1:gt1HRYyMxcMca9lbDLPbivQzsUCjVjkPAn/3S6fiD14= go.opentelemetry.io/collector/config/configtelemetry v0.92.1-0.20240112172857-83d463ceba06 h1:FqiK9txeD9sIn5edjyYXj/RB9/YVle10QR43PyhVt6o=