fix: v2 setup sequence (#3437)

* add/register human command done

* validations

* crypto

* move clientid

* keys

* fix: clientID

* remove v2 package

* tests

* tests running

* fix: add init instance to eventstore

* fix: mig

* test(eventstore): create instance

* revert old code

* instance domain from ctx

* chore: rename zitadel app ids

* comments

* fix: test

* fix: mock

* fix: test
This commit is contained in:
Silvan 2022-04-13 07:42:48 +02:00 committed by GitHub
parent 375a57377d
commit db554536a1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 137 additions and 81 deletions

View File

@ -28,7 +28,7 @@ Prereqesits:
Run: func(cmd *cobra.Command, args []string) {
config := MustNewConfig(viper.New())
err := initialise(config, VerifyGrant(config.Database.Database, config.Database.User.Username))
err := initialise(config, VerifyGrant(config.Database.Database, config.Database.Username))
logging.OnError(err).Fatal("unable to set grant")
},
}
@ -36,7 +36,7 @@ Prereqesits:
func VerifyGrant(database, username string) func(*sql.DB) error {
return func(db *sql.DB) error {
logging.WithFields("user", username).Info("verify grant")
logging.WithFields("user", username, "database", database).Info("verify grant")
return verify(db,
exists(fmt.Sprintf(searchGrant, database), username),
exec(fmt.Sprintf(grantStmt, database, username)),

View File

@ -3,6 +3,7 @@ package setup
import (
"context"
_ "embed"
"strings"
"github.com/caos/logging"
"github.com/spf13/cobra"
@ -49,6 +50,12 @@ func Setup(config *Config, steps *Steps, masterKey string) {
steps.s1ProjectionTable = &ProjectionTable{dbClient: dbClient}
steps.s2AssetsTable = &AssetTable{dbClient: dbClient}
steps.S3DefaultInstance.InstanceSetup.Org.Human.Email.Address = strings.TrimSpace(steps.S3DefaultInstance.InstanceSetup.Org.Human.Email.Address)
if steps.S3DefaultInstance.InstanceSetup.Org.Human.Email.Address == "" {
steps.S3DefaultInstance.InstanceSetup.Org.Human.Email.Address = "admin@" + config.ExternalDomain
}
steps.S3DefaultInstance.es = eventstoreClient
steps.S3DefaultInstance.db = dbClient
steps.S3DefaultInstance.defaults = config.SystemDefaults

View File

@ -9,7 +9,7 @@ S3DefaultInstance:
NickName:
DisplayName:
Email:
Address: admin@zitadel.ch
Address: #autogenerated if empty. uses domain from config and prefixes admin@. for example: admin@domain.tdl
Verified: true
PreferredLanguage:
Gender:

View File

@ -162,6 +162,12 @@ func (c *commandNew) SetUpInstance(ctx context.Context, setup *InstanceSetup) (*
if err != nil {
return nil, err
}
if err = c.es.NewInstance(ctx, instanceID); err != nil {
return nil, err
}
ctx = authz.SetCtxData(authz.WithInstanceID(ctx, instanceID), authz.CtxData{OrgID: instanceID, ResourceOwner: instanceID})
requestedDomain := authz.GetInstance(ctx).RequestedDomain()
ctx = authz.SetCtxData(authz.WithRequestedDomain(authz.WithInstanceID(ctx, instanceID), requestedDomain), authz.CtxData{OrgID: instanceID, ResourceOwner: instanceID})

View File

@ -59,6 +59,10 @@ func (es *Eventstore) Push(ctx context.Context, cmds ...Command) ([]Event, error
return eventReaders, nil
}
func (es *Eventstore) NewInstance(ctx context.Context, instanceID string) error {
return es.repo.CreateInstance(ctx, instanceID)
}
func commandsToRepository(instanceID string, cmds []Command) (events []*repository.Event, constraints []*repository.UniqueConstraint, err error) {
events = make([]*repository.Event, len(cmds))
for i, cmd := range cmds {
@ -245,7 +249,3 @@ func uniqueConstraintActionToRepository(action UniqueConstraintAction) repositor
return repository.UniqueConstraintAdd
}
}
func (es *Eventstore) Step20(ctx context.Context, latestSequence uint64) error {
return es.repo.Step20(ctx, latestSequence)
}

View File

@ -698,6 +698,10 @@ func (repo *testRepo) Health(ctx context.Context) error {
return nil
}
func (repo *testRepo) CreateInstance(ctx context.Context, instance string) error {
return nil
}
func (repo *testRepo) Step20(context.Context, uint64) error { return nil }
func (repo *testRepo) Push(ctx context.Context, events []*repository.Event, uniqueConstraints ...*repository.UniqueConstraint) error {

View File

@ -35,6 +35,20 @@ func (m *MockRepository) EXPECT() *MockRepositoryMockRecorder {
return m.recorder
}
// CreateInstance mocks base method.
func (m *MockRepository) CreateInstance(arg0 context.Context, arg1 string) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "CreateInstance", arg0, arg1)
ret0, _ := ret[0].(error)
return ret0
}
// CreateInstance indicates an expected call of CreateInstance.
func (mr *MockRepositoryMockRecorder) CreateInstance(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateInstance", reflect.TypeOf((*MockRepository)(nil).CreateInstance), arg0, arg1)
}
// Filter mocks base method.
func (m *MockRepository) Filter(arg0 context.Context, arg1 *repository.SearchQuery) ([]*repository.Event, error) {
m.ctrl.T.Helper()
@ -97,17 +111,3 @@ func (mr *MockRepositoryMockRecorder) Push(arg0, arg1 interface{}, arg2 ...inter
varargs := append([]interface{}{arg0, arg1}, arg2...)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Push", reflect.TypeOf((*MockRepository)(nil).Push), varargs...)
}
// Step20 mocks base method.
func (m *MockRepository) Step20(arg0 context.Context, arg1 uint64) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Step20", arg0, arg1)
ret0, _ := ret[0].(error)
return ret0
}
// Step20 indicates an expected call of Step20.
func (mr *MockRepositoryMockRecorder) Step20(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Step20", reflect.TypeOf((*MockRepository)(nil).Step20), arg0, arg1)
}

View File

@ -16,6 +16,6 @@ type Repository interface {
Filter(ctx context.Context, searchQuery *SearchQuery) (events []*Event, err error)
//LatestSequence returns the latests sequence found by the the search query
LatestSequence(ctx context.Context, queryFactory *SearchQuery) (uint64, error)
Step20(ctx context.Context, latestSequence uint64) error
//CreateInstance creates a new sequence for the given instance
CreateInstance(ctx context.Context, instanceID string) error
}

View File

@ -153,6 +153,25 @@ func (db *CRDB) Push(ctx context.Context, events []*repository.Event, uniqueCons
return err
}
var instanceRegexp = regexp.MustCompile(`eventstore\.i_[0-9a-zA-Z]{1,}_seq`)
func (db *CRDB) CreateInstance(ctx context.Context, instanceID string) error {
row := db.client.QueryRowContext(ctx, "SELECT CONCAT('eventstore.i_', $1, '_seq')", instanceID)
if row.Err() != nil {
return caos_errs.ThrowInvalidArgument(row.Err(), "SQL-7gtFA", "Errors.InvalidArgument")
}
var sequenceName string
if err := row.Scan(&sequenceName); err != nil || !instanceRegexp.MatchString(sequenceName) {
return caos_errs.ThrowInvalidArgument(err, "SQL-7gtFA", "Errors.InvalidArgument")
}
if _, err := db.client.ExecContext(ctx, "CREATE SEQUENCE "+sequenceName); err != nil {
return caos_errs.ThrowInternal(err, "SQL-7gtFA", "Errors.Internal")
}
return nil
}
// handleUniqueConstraints adds or removes unique constraints
func (db *CRDB) handleUniqueConstraints(ctx context.Context, tx *sql.Tx, uniqueConstraints ...*repository.UniqueConstraint) (err error) {
if len(uniqueConstraints) == 0 || (len(uniqueConstraints) == 1 && uniqueConstraints[0] == nil) {

View File

@ -561,6 +561,84 @@ func TestCRDB_Push_MultipleAggregate(t *testing.T) {
}
}
func TestCRDB_CreateInstance(t *testing.T) {
type args struct {
instanceID string
}
type res struct {
wantErr bool
exists bool
}
tests := []struct {
name string
args args
res res
}{
{
name: "no number",
args: args{
instanceID: "asdf;use defaultdb;DROP DATABASE zitadel;--",
},
res: res{
wantErr: true,
exists: false,
},
},
{
name: "no instance id",
args: args{
instanceID: "",
},
res: res{
wantErr: true,
exists: false,
},
},
{
name: "correct number",
args: args{
instanceID: "1235",
},
res: res{
wantErr: false,
exists: true,
},
},
{
name: "correct text",
args: args{
instanceID: "system",
},
res: res{
wantErr: false,
exists: true,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
db := &CRDB{
client: testCRDBClient,
}
if err := db.CreateInstance(context.Background(), tt.args.instanceID); (err != nil) != tt.res.wantErr {
t.Errorf("CRDB.CreateInstance() error = %v, wantErr %v", err, tt.res.wantErr)
}
sequenceRow := testCRDBClient.QueryRow("SELECT EXISTS(SELECT 1 FROM [SHOW SEQUENCES FROM eventstore] WHERE sequence_name like $1)", "i_"+tt.args.instanceID+"%")
var exists bool
err := sequenceRow.Scan(&exists)
if err != nil {
t.Error("unable to query inserted rows: ", err)
return
}
if exists != tt.res.exists {
t.Errorf("expected exists %v got %v", tt.res.exists, exists)
}
})
}
}
func TestCRDB_Push_Parallel(t *testing.T) {
type args struct {
events [][]*repository.Event

View File

@ -1,58 +0,0 @@
package sql
import (
"context"
"github.com/caos/logging"
repo "github.com/caos/zitadel/internal/eventstore/repository"
)
func (db *CRDB) Step20(ctx context.Context, latestSequence uint64) error {
currentSequence := uint64(0)
limit := uint64(500)
previousSequences := make(map[repo.AggregateType]Sequence)
for currentSequence < latestSequence {
events, err := db.Filter(ctx, &repo.SearchQuery{
Columns: repo.ColumnsEvent,
Limit: limit,
Filters: [][]*repo.Filter{
{
&repo.Filter{
Field: repo.FieldSequence,
Operation: repo.OperationGreater,
Value: currentSequence,
},
},
},
})
if err != nil {
return err
}
tx, err := db.client.Begin()
if err != nil {
return err
}
for _, event := range events {
if _, err := tx.Exec("SAVEPOINT event_update"); err != nil {
return err
}
seq := Sequence(previousSequences[event.AggregateType])
if _, err = tx.Exec("UPDATE eventstore.events SET previous_aggregate_type_sequence = $1 WHERE event_sequence = $2", &seq, event.Sequence); err != nil {
return err
}
if _, err = tx.Exec("RELEASE SAVEPOINT event_update"); err != nil {
return err
}
previousSequences[event.AggregateType] = Sequence(event.Sequence)
currentSequence = event.Sequence
}
if err = tx.Commit(); err != nil {
return err
}
logging.WithFields("currentSeq", currentSequence, "events", len(events)).Info("events updated")
}
return nil
}