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

Migrate old db_object_import_rule preset to new preset #47683

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
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
19 changes: 19 additions & 0 deletions lib/auth/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -1131,6 +1131,25 @@ func createPresetDatabaseObjectImportRule(ctx context.Context, rules services.Da
return trace.Wrap(err, "failed listing available database object import rules")
}
if len(importRules) > 0 {
// If the single rule is the old preset, we assume the user hasn't used
// DB DAC feature yet since the old preset alone is usually not enough
// to make things work. Replace it with the new preset.
//
// Creating and updating the database object import rule is handled on
// a best-effort basis, so it’s not included in backend migrations.
//
// TODO(greedy52) DELETE in 18.0
if len(importRules) == 1 && databaseobjectimportrule.IsOldImportAllObjectsRulePreset(importRules[0]) {
rule := databaseobjectimportrule.NewPresetImportAllObjectsRule()
if rule == nil {
return nil
}

_, err = rules.UpsertDatabaseObjectImportRule(ctx, rule)
if err != nil {
return trace.Wrap(err, "failed to update the default database object import rule")
}
}
return nil
}

Expand Down
108 changes: 108 additions & 0 deletions lib/auth/init_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,14 @@ import (
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
"golang.org/x/crypto/ssh"
"google.golang.org/protobuf/proto"
kyaml "k8s.io/apimachinery/pkg/util/yaml"

"github.com/gravitational/teleport"
"github.com/gravitational/teleport/api/constants"
dbobjectimportrulev1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/dbobjectimportrule/v1"
"github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/api/types/label"
apisshutils "github.com/gravitational/teleport/api/utils/sshutils"
"github.com/gravitational/teleport/entitlements"
"github.com/gravitational/teleport/lib"
Expand All @@ -58,6 +61,7 @@ import (
"github.com/gravitational/teleport/lib/observability/tracing"
"github.com/gravitational/teleport/lib/services"
"github.com/gravitational/teleport/lib/services/suite"
"github.com/gravitational/teleport/lib/srv/db/common/databaseobjectimportrule"
"github.com/gravitational/teleport/lib/sshutils"
"github.com/gravitational/teleport/lib/utils"
"github.com/gravitational/teleport/lib/utils/proxy"
Expand Down Expand Up @@ -2098,3 +2102,107 @@ func TestTeleportProcessAuthVersionUpgradeCheck(t *testing.T) {
})
}
}

type mockDatabaseObjectImportRules struct {
services.DatabaseObjectImportRules
listRules []*dbobjectimportrulev1.DatabaseObjectImportRule
created *dbobjectimportrulev1.DatabaseObjectImportRule
upserted *dbobjectimportrulev1.DatabaseObjectImportRule
}

func (m *mockDatabaseObjectImportRules) ListDatabaseObjectImportRules(context.Context, int, string) ([]*dbobjectimportrulev1.DatabaseObjectImportRule, string, error) {
return m.listRules, "", nil
}
func (m *mockDatabaseObjectImportRules) CreateDatabaseObjectImportRule(ctx context.Context, rule *dbobjectimportrulev1.DatabaseObjectImportRule) (*dbobjectimportrulev1.DatabaseObjectImportRule, error) {
m.created = rule
return rule, nil
}
func (m *mockDatabaseObjectImportRules) UpsertDatabaseObjectImportRule(ctx context.Context, rule *dbobjectimportrulev1.DatabaseObjectImportRule) (*dbobjectimportrulev1.DatabaseObjectImportRule, error) {
m.upserted = rule
return rule, nil
}

func Test_createPresetDatabaseObjectImportRule(t *testing.T) {
presetRule := databaseobjectimportrule.NewPresetImportAllObjectsRule()
require.NotNil(t, presetRule)

customRule, err := databaseobjectimportrule.NewDatabaseObjectImportRule("dev_rule", &dbobjectimportrulev1.DatabaseObjectImportRuleSpec{
Priority: 100,
DatabaseLabels: label.FromMap(map[string][]string{"env": {"dev"}}),
Mappings: []*dbobjectimportrulev1.DatabaseObjectImportRuleMapping{{
Match: &dbobjectimportrulev1.DatabaseObjectImportMatch{
TableNames: []string{"*"},
},
AddLabels: map[string]string{
"env": "dev",
},
Scope: &dbobjectimportrulev1.DatabaseObjectImportScope{
SchemaNames: []string{"public"},
},
}},
})
require.NoError(t, err)

oldPresetRule, err := databaseobjectimportrule.NewDatabaseObjectImportRule("import_all_objects", &dbobjectimportrulev1.DatabaseObjectImportRuleSpec{
DatabaseLabels: label.FromMap(map[string][]string{"*": {"*"}}),
Mappings: []*dbobjectimportrulev1.DatabaseObjectImportRuleMapping{
{
Match: &dbobjectimportrulev1.DatabaseObjectImportMatch{TableNames: []string{"*"}},
AddLabels: map[string]string{"kind": "table"},
},
{
Match: &dbobjectimportrulev1.DatabaseObjectImportMatch{ViewNames: []string{"*"}},
AddLabels: map[string]string{"kind": "view"},
},
{
Match: &dbobjectimportrulev1.DatabaseObjectImportMatch{ProcedureNames: []string{"*"}},
AddLabels: map[string]string{"kind": "procedure"},
},
},
})
require.NoError(t, err)

tests := []struct {
name string
existingRules []*dbobjectimportrulev1.DatabaseObjectImportRule
expectCreate *dbobjectimportrulev1.DatabaseObjectImportRule
expectUpsert *dbobjectimportrulev1.DatabaseObjectImportRule
}{
{
name: "create preset in new cluster",
expectCreate: presetRule,
},
{
name: "no action with custom rule",
existingRules: []*dbobjectimportrulev1.DatabaseObjectImportRule{customRule},
},
{
name: "no action with old preset and custom rule",
existingRules: []*dbobjectimportrulev1.DatabaseObjectImportRule{oldPresetRule, customRule},
},
{
name: "no action with preset rule",
existingRules: []*dbobjectimportrulev1.DatabaseObjectImportRule{presetRule},
},
{
name: "migrate old preset to new",
existingRules: []*dbobjectimportrulev1.DatabaseObjectImportRule{oldPresetRule},
expectUpsert: presetRule,
},
}

for _, test := range tests {
test := test
t.Run(test.name, func(t *testing.T) {
t.Parallel()
m := &mockDatabaseObjectImportRules{
listRules: test.existingRules,
}

err := createPresetDatabaseObjectImportRule(context.Background(), m)
require.NoError(t, err)
require.True(t, proto.Equal(test.expectCreate, m.created))
require.True(t, proto.Equal(test.expectUpsert, m.upserted))
})
}
}
46 changes: 44 additions & 2 deletions lib/srv/db/common/databaseobjectimportrule/preset.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@
package databaseobjectimportrule

import (
log "github.com/sirupsen/logrus"
"context"
"log/slog"

"google.golang.org/protobuf/proto"

dbobjectimportrulev1pb "github.com/gravitational/teleport/api/gen/proto/go/teleport/dbobjectimportrule/v1"
"github.com/gravitational/teleport/api/types/label"
Expand Down Expand Up @@ -49,8 +52,47 @@ func NewPresetImportAllObjectsRule() *dbobjectimportrulev1pb.DatabaseObjectImpor
})

if err != nil {
log.WithError(err).Warn("failed to create import_all_objects database object import rule")
slog.WarnContext(context.Background(), "failed to create import_all_objects database object import rule", "error", err)
return nil
}
return rule
}

// IsOldImportAllObjectsRulePreset checks if the provided rule is the "old" preset.
// TODO(greedy52) DELETE in 18.0
func IsOldImportAllObjectsRulePreset(cur *dbobjectimportrulev1pb.DatabaseObjectImportRule) bool {
// Skip no-zero expires.
if cur.Metadata.Expires != nil && !cur.Metadata.Expires.AsTime().IsZero() {
return false
}

// Make the old preset from https://github.com/gravitational/teleport/pull/37808
old, err := NewDatabaseObjectImportRule("import_all_objects", &dbobjectimportrulev1pb.DatabaseObjectImportRuleSpec{
Priority: 0,
DatabaseLabels: label.FromMap(map[string][]string{"*": {"*"}}),
Mappings: []*dbobjectimportrulev1pb.DatabaseObjectImportRuleMapping{
{
Match: &dbobjectimportrulev1pb.DatabaseObjectImportMatch{TableNames: []string{"*"}},
AddLabels: map[string]string{"kind": ObjectKindTable},
},
{
Match: &dbobjectimportrulev1pb.DatabaseObjectImportMatch{ViewNames: []string{"*"}},
AddLabels: map[string]string{"kind": ObjectKindView},
},
{
Match: &dbobjectimportrulev1pb.DatabaseObjectImportMatch{ProcedureNames: []string{"*"}},
AddLabels: map[string]string{"kind": ObjectKindProcedure},
},
},
})
if err != nil {
slog.WarnContext(context.Background(), "failed to create old import_all_objects database object import rule", "error", err)
return false
}

// Ignore these fields.
old.Metadata.Revision = cur.Metadata.Revision
old.Metadata.Namespace = cur.Metadata.Namespace
old.Metadata.Expires = cur.Metadata.Expires
return proto.Equal(old, cur)
}
Loading