Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use creds in alternator tests #4034

Merged
merged 4 commits into from
Sep 17, 2024
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
24 changes: 13 additions & 11 deletions pkg/ping/dynamoping/dynamoping.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@ import (
type Config struct {
Addr string
RequiresAuthentication bool
Username string
Password string
Timeout time.Duration
TLSConfig *tls.Config
}
Expand Down Expand Up @@ -71,10 +69,19 @@ var unauthorisedMessage = []string{
"The security token included in the request is invalid.",
}

// ErrAlternatorQueryPingNotSupported is returned when alternator query ping is executed,
// but managed cluster enforces alternator authentication.
// See #4036 for more details.
var ErrAlternatorQueryPingNotSupported = errors.New("ScyllaDB Manager does not support alternator query ping when authentication is enforced")

// QueryPing checks if host is available, it returns RTT and error. Special errors
// are ErrTimeout and ErrUnauthorised. Ping is based on executing
// a real query.
func QueryPing(ctx context.Context, config Config) (rtt time.Duration, err error) {
if config.RequiresAuthentication {
return 0, ErrAlternatorQueryPingNotSupported
}

t := timeutc.Now()
defer func() {
rtt = timeutc.Since(t)
Expand All @@ -92,18 +99,13 @@ func QueryPing(ctx context.Context, config Config) (rtt time.Duration, err error

sess := session.Must(session.NewSessionWithOptions(session.Options{
Config: aws.Config{
Endpoint: aws.String(config.Addr),
Region: aws.String("scylla"),
HTTPClient: httpClient(config),
Endpoint: aws.String(config.Addr),
Region: aws.String("scylla"),
HTTPClient: httpClient(config),
Credentials: credentials.AnonymousCredentials,
},
}))

if config.RequiresAuthentication && config.Username != "" && config.Password != "" {
sess.Config.Credentials = credentials.NewStaticCredentials(config.Username, config.Password, "")
} else {
sess.Config.Credentials = credentials.AnonymousCredentials
}

svc := dynamodb.New(sess)

ctx, cancel := context.WithDeadline(ctx, t.Add(config.Timeout))
Expand Down
12 changes: 9 additions & 3 deletions pkg/ping/dynamoping/dynamoping_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,20 @@ package dynamoping

import (
"context"
"github.com/scylladb/scylla-manager/v3/pkg/testutils/testconfig"
"testing"
"time"

"github.com/pkg/errors"
"github.com/scylladb/scylla-manager/v3/pkg/testutils/testconfig"

_ "github.com/scylladb/scylla-manager/v3/pkg/testutils"
)

func TestPingIntegration(t *testing.T) {
config := Config{
Addr: "http://" + testconfig.ManagedClusterHost() + ":8000",
Timeout: 250 * time.Millisecond,
Addr: "http://" + testconfig.ManagedClusterHost() + ":8000",
Timeout: 250 * time.Millisecond,
RequiresAuthentication: true,
}

t.Run("simple", func(t *testing.T) {
Expand All @@ -31,6 +34,9 @@ func TestPingIntegration(t *testing.T) {
t.Run("query", func(t *testing.T) {
d, err := QueryPing(context.Background(), config)
if err != nil {
if errors.Is(err, ErrAlternatorQueryPingNotSupported) {
t.Skip(ErrAlternatorQueryPingNotSupported)
}
t.Error(err)
}
t.Logf("QueryPing() = %s", d)
Expand Down
6 changes: 4 additions & 2 deletions pkg/service/backup/service_backup_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2402,8 +2402,10 @@ func TestBackupAlternatorIntegration(t *testing.T) {
clusterSession = CreateSessionAndDropAllKeyspaces(t, h.Client)
)

CreateAlternatorTable(t, ManagedClusterHost(), alternatorPort, testTable)
FillAlternatorTableWithOneRow(t, ManagedClusterHost(), alternatorPort, testTable)
accessKeyID, secretAccessKey := CreateAlternatorUser(t, clusterSession, "")
svc := CreateDynamoDBService(t, ManagedClusterHost(), alternatorPort, accessKeyID, secretAccessKey)
CreateAlternatorTable(t, svc, testTable)
FillAlternatorTableWithOneRow(t, svc, testTable)

Print("When: validate data insertion")
selectStmt := fmt.Sprintf("SELECT COUNT(*) FROM %q.%q WHERE key='test'", testKeyspace, testTable)
Expand Down
17 changes: 10 additions & 7 deletions pkg/service/healthcheck/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -300,15 +300,18 @@ func (s *Service) pingAlternator(ctx context.Context, _ uuid.UUID, host string,
return 0, nil
}

pingFunc := dynamoping.SimplePing
if queryPing, err := ni.SupportsAlternatorQuery(); err == nil && queryPing {
pingFunc = dynamoping.QueryPing
}

addr := ni.AlternatorAddr(host)
config := dynamoping.Config{
Addr: addr,
Timeout: timeout,
Addr: addr,
Timeout: timeout,
RequiresAuthentication: ni.AlternatorEnforceAuthorization,
}

pingFunc := dynamoping.SimplePing
if !config.RequiresAuthentication {
if queryPing, err := ni.SupportsAlternatorQuery(); err == nil && queryPing {
pingFunc = dynamoping.QueryPing
}
}

tlsConfig := ni.AlternatorTLSConfig()
Expand Down
7 changes: 5 additions & 2 deletions pkg/service/repair/service_repair_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2042,8 +2042,11 @@ func TestServiceRepairIntegration(t *testing.T) {
)

Print("When: create alternator table with 1 row")
CreateAlternatorTable(t, ManagedClusterHost(), alternatorPort, testTable)
FillAlternatorTableWithOneRow(t, ManagedClusterHost(), alternatorPort, testTable)

accessKeyID, secretAccessKey := CreateAlternatorUser(t, clusterSession, "")
svc := CreateDynamoDBService(t, ManagedClusterHost(), alternatorPort, accessKeyID, secretAccessKey)
CreateAlternatorTable(t, svc, testTable)
FillAlternatorTableWithOneRow(t, svc, testTable)
defer dropKeyspace(t, clusterSession, testKeyspace)

h := newRepairTestHelper(t, session, defaultConfig())
Expand Down
6 changes: 4 additions & 2 deletions pkg/service/restore/service_restore_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1461,8 +1461,10 @@ func restoreAlternator(t *testing.T, schemaTarget, tablesTarget Target, testKeys
createUser(t, dstSession, user, "pass")
dstH = newRestoreTestHelper(t, mgrSession, cfg, schemaTarget.Location[0], nil, user, "pass")

CreateAlternatorTable(t, ManagedSecondClusterHosts()[0], alternatorPort, testTable)
FillAlternatorTableWithOneRow(t, ManagedSecondClusterHosts()[0], alternatorPort, testTable)
accessKeyID, secretAccessKey := CreateAlternatorUser(t, srcSession, "")
svc := CreateDynamoDBService(t, ManagedSecondClusterHosts()[0], alternatorPort, accessKeyID, secretAccessKey)
CreateAlternatorTable(t, svc, testTable)
FillAlternatorTableWithOneRow(t, svc, testTable)

schemaTarget.SnapshotTag = srcH.simpleBackup(schemaTarget.Location[0])

Expand Down
42 changes: 35 additions & 7 deletions pkg/testutils/db/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"github.com/scylladb/gocqlx/v2"
"github.com/scylladb/gocqlx/v2/migrate"
"github.com/scylladb/gocqlx/v2/qb"
"go.uber.org/multierr"

"github.com/scylladb/scylla-manager/v3/pkg/schema/nopmigrate"
"github.com/scylladb/scylla-manager/v3/pkg/scyllaclient"
Expand Down Expand Up @@ -316,11 +317,39 @@ func WaitForViews(t *testing.T, session gocqlx.Session) {
}
}

// CreateAlternatorUser creates a regular role via CQL and
// returns its credentials used for authenticating alternator queries.
// Empty username results in returning credentials for "cassandra" superuser.
// See https://opensource.docs.scylladb.com/stable/alternator/compatibility.html#authorization for more details.
func CreateAlternatorUser(t *testing.T, s gocqlx.Session, role string) (accessKeyID, secretAccessKey string) {
t.Helper()

if role != "" {
ExecStmt(t, s, fmt.Sprintf("CREATE ROLE %q WITH PASSWORD = '%s' AND SUPERUSER = false AND LOGIN = true", role, role))
} else {
role = "cassandra"
}
accessKeyID = role

// Roles table is kept in different keyspaces depending on Scylla version
rolesKeyspaces := []string{"system", "system_auth"}
var retErr error
for _, ks := range rolesKeyspaces {
q := s.Query(fmt.Sprintf("SELECT salted_hash FROM %s.roles WHERE role = '%s'", ks, role), nil)
if err := q.Scan(&secretAccessKey); err != nil {
retErr = multierr.Append(retErr, err)
} else {
return
}
}
t.Fatal("Couldn't get salted_hash from roles table", retErr)
return
}

// CreateAlternatorTable creates "alternator_{table}.{table}" table via alternator API.
func CreateAlternatorTable(t *testing.T, host string, alternatorPort int, table string) {
func CreateAlternatorTable(t *testing.T, svc *dynamodb.DynamoDB, table string) {
t.Helper()

svc := CreateDynamoDBService(t, host, alternatorPort)
createTable := &dynamodb.CreateTableInput{
AttributeDefinitions: []*dynamodb.AttributeDefinition{
{
Expand All @@ -345,10 +374,9 @@ func CreateAlternatorTable(t *testing.T, host string, alternatorPort int, table
}

// FillAlternatorTableWithOneRow inserts 1 row into "alternator_{table}.{table}" table via alternator API.
func FillAlternatorTableWithOneRow(t *testing.T, host string, alternatorPort int, table string) {
func FillAlternatorTableWithOneRow(t *testing.T, svc *dynamodb.DynamoDB, table string) {
t.Helper()

svc := CreateDynamoDBService(t, host, alternatorPort)
insertData := &dynamodb.BatchWriteItemInput{
RequestItems: map[string][]*dynamodb.WriteRequest{
table: {
Expand All @@ -372,14 +400,14 @@ func FillAlternatorTableWithOneRow(t *testing.T, host string, alternatorPort int
}

// CreateDynamoDBService returns DynamoDB service.
func CreateDynamoDBService(t *testing.T, host string, alternatorPort int) *dynamodb.DynamoDB {
func CreateDynamoDBService(t *testing.T, host string, alternatorPort int, accessKeyID, secretAccessKey string) *dynamodb.DynamoDB {
t.Helper()

awsCfg := &aws.Config{
Endpoint: aws.String("http://" + net.JoinHostPort(host, fmt.Sprint(alternatorPort))),
Credentials: credentials.NewStaticCredentialsFromCreds(credentials.Value{
AccessKeyID: "None",
SecretAccessKey: "None",
AccessKeyID: accessKeyID,
SecretAccessKey: secretAccessKey,
}),
Region: aws.String("None"),
}
Expand Down
1 change: 1 addition & 0 deletions testing/scylla/config/scylla.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -644,6 +644,7 @@ api_ui_dir: /usr/lib/scylla/swagger-ui/dist/
api_doc_dir: /usr/lib/scylla/api/api-doc/
alternator_port: 8000
alternator_write_isolation: only_rmw_uses_lwt
alternator_enforce_authorization: true
enable_ipv6_dns_lookup: true

uuid_sstable_identifiers_enabled: false
Loading