mirror of
https://github.com/zitadel/zitadel.git
synced 2025-02-28 20:27:23 +00:00
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:
parent
375a57377d
commit
db554536a1
@ -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)),
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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})
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user