fix: instance remove (#4602)

This commit is contained in:
Livio Spring 2022-10-26 15:06:48 +02:00 committed by GitHub
parent 001636f2b4
commit d721f725fd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
89 changed files with 656 additions and 122 deletions

View File

@ -150,6 +150,12 @@ func (m *Styling) processLabelPolicy(event *models.Event) (err error) {
return err
}
err = m.generateStylingFile(policy)
case instance.InstanceRemovedEventType:
err = m.deleteInstanceFilesFromStorage(event.InstanceID)
if err != nil {
return err
}
return m.view.DeleteInstanceStyling(event)
default:
return m.view.ProcessedStylingSequence(event)
}
@ -262,6 +268,10 @@ func (m *Styling) uploadFilesToStorage(instanceID, aggregateID, contentType stri
return err
}
func (m *Styling) deleteInstanceFilesFromStorage(instanceID string) error {
return m.static.RemoveInstanceObjects(context.Background(), instanceID)
}
func (m *Styling) generateColorPaletteRGBA255(hex string) map[string]string {
palette := make(map[string]string)
defaultColor := gamut.Hex(hex)

View File

@ -23,6 +23,14 @@ func (v *View) PutStyling(policy *model.LabelPolicyView, event *models.Event) er
return v.ProcessedStylingSequence(event)
}
func (v *View) DeleteInstanceStyling(event *models.Event) error {
err := view.DeleteInstanceStyling(v.Db, stylingTyble, event.InstanceID)
if err != nil {
return err
}
return v.ProcessedStylingSequence(event)
}
func (v *View) GetLatestStylingSequence(instanceID string) (*global_view.CurrentSequence, error) {
return v.latestSequence(stylingTyble, instanceID)
}

View File

@ -63,6 +63,7 @@ func (s *Server) UpdateInstance(ctx context.Context, req *system_pb.UpdateInstan
}
func (s *Server) RemoveInstance(ctx context.Context, req *system_pb.RemoveInstanceRequest) (*system_pb.RemoveInstanceResponse, error) {
ctx = authz.WithInstanceID(ctx, req.InstanceId)
details, err := s.command.RemoveInstance(ctx, req.InstanceId)
if err != nil {
return nil, err

View File

@ -117,6 +117,8 @@ func (i *IDPConfig) processIdpConfig(providerType iam_model.IDPProviderType, eve
return err
}
return i.view.DeleteIDPConfig(idp.IDPConfigID, event)
case instance.InstanceRemovedEventType:
return i.view.DeleteInstanceIDPs(event)
default:
return i.view.ProcessedIDPConfigSequence(event)
}

View File

@ -138,6 +138,8 @@ func (i *IDPProvider) processIdpProvider(event *models.Event) (err error) {
return i.view.PutIDPProviders(event, providers...)
case org.LoginPolicyRemovedEventType:
return i.view.DeleteIDPProvidersByAggregateID(event.AggregateID, event.InstanceID, event)
case instance.InstanceRemovedEventType:
return i.view.DeleteInstanceIDPs(event)
default:
return i.view.ProcessedIDPProviderSequence(event)
}

View File

@ -9,6 +9,7 @@ import (
"github.com/zitadel/zitadel/internal/eventstore/v1/query"
"github.com/zitadel/zitadel/internal/eventstore/v1/spooler"
view_model "github.com/zitadel/zitadel/internal/project/repository/view/model"
"github.com/zitadel/zitadel/internal/repository/instance"
"github.com/zitadel/zitadel/internal/repository/project"
)
@ -51,7 +52,7 @@ func (p *OrgProjectMapping) Subscription() *v1.Subscription {
}
func (_ *OrgProjectMapping) AggregateTypes() []es_models.AggregateType {
return []es_models.AggregateType{project.AggregateType}
return []es_models.AggregateType{project.AggregateType, instance.AggregateType}
}
func (p *OrgProjectMapping) CurrentSequence(instanceID string) (uint64, error) {
@ -96,6 +97,8 @@ func (p *OrgProjectMapping) Reduce(event *es_models.Event) (err error) {
if err == nil {
return p.view.ProcessedOrgProjectMappingSequence(event)
}
case instance.InstanceRemovedEventType:
return p.view.DeleteInstanceOrgProjectMappings(event)
default:
return p.view.ProcessedOrgProjectMappingSequence(event)
}

View File

@ -11,6 +11,7 @@ import (
es_models "github.com/zitadel/zitadel/internal/eventstore/v1/models"
"github.com/zitadel/zitadel/internal/eventstore/v1/query"
"github.com/zitadel/zitadel/internal/eventstore/v1/spooler"
"github.com/zitadel/zitadel/internal/repository/instance"
"github.com/zitadel/zitadel/internal/repository/project"
"github.com/zitadel/zitadel/internal/repository/user"
view_model "github.com/zitadel/zitadel/internal/user/repository/view/model"
@ -55,7 +56,7 @@ func (t *RefreshToken) Subscription() *v1.Subscription {
}
func (t *RefreshToken) AggregateTypes() []es_models.AggregateType {
return []es_models.AggregateType{user.AggregateType, project.AggregateType}
return []es_models.AggregateType{user.AggregateType, project.AggregateType, instance.AggregateType}
}
func (t *RefreshToken) CurrentSequence(instanceID string) (uint64, error) {
@ -109,6 +110,8 @@ func (t *RefreshToken) Reduce(event *es_models.Event) (err error) {
user.UserDeactivatedType,
user.UserRemovedType:
return t.view.DeleteUserRefreshTokens(event.AggregateID, event.InstanceID, event)
case instance.InstanceRemovedEventType:
return t.view.DeleteInstanceRefreshTokens(event)
default:
return t.view.ProcessedRefreshTokenSequence(event)
}

View File

@ -16,6 +16,7 @@ import (
proj_model "github.com/zitadel/zitadel/internal/project/model"
project_es_model "github.com/zitadel/zitadel/internal/project/repository/eventsourcing/model"
proj_view "github.com/zitadel/zitadel/internal/project/repository/view"
"github.com/zitadel/zitadel/internal/repository/instance"
"github.com/zitadel/zitadel/internal/repository/project"
"github.com/zitadel/zitadel/internal/repository/user"
user_repo "github.com/zitadel/zitadel/internal/repository/user"
@ -61,7 +62,7 @@ func (t *Token) Subscription() *v1.Subscription {
}
func (_ *Token) AggregateTypes() []es_models.AggregateType {
return []es_models.AggregateType{user.AggregateType, project.AggregateType}
return []es_models.AggregateType{user.AggregateType, project.AggregateType, instance.AggregateType}
}
func (p *Token) CurrentSequence(instanceID string) (uint64, error) {
@ -144,6 +145,8 @@ func (t *Token) Reduce(event *es_models.Event) (err error) {
applicationsIDs = append(applicationsIDs, app.AppID)
}
return t.view.DeleteApplicationTokens(event, applicationsIDs...)
case instance.InstanceRemovedEventType:
return t.view.DeleteInstanceTokens(event)
default:
return t.view.ProcessedTokenSequence(event)
}

View File

@ -16,6 +16,7 @@ import (
org_es_model "github.com/zitadel/zitadel/internal/org/repository/eventsourcing/model"
"github.com/zitadel/zitadel/internal/org/repository/view"
query2 "github.com/zitadel/zitadel/internal/query"
"github.com/zitadel/zitadel/internal/repository/instance"
"github.com/zitadel/zitadel/internal/repository/org"
user_repo "github.com/zitadel/zitadel/internal/repository/user"
usr_view "github.com/zitadel/zitadel/internal/user/repository/view"
@ -63,7 +64,7 @@ func (u *User) Subscription() *v1.Subscription {
return u.subscription
}
func (_ *User) AggregateTypes() []es_models.AggregateType {
return []es_models.AggregateType{user_repo.AggregateType, org.AggregateType}
return []es_models.AggregateType{user_repo.AggregateType, org.AggregateType, instance.AggregateType}
}
func (u *User) CurrentSequence(instanceID string) (uint64, error) {
@ -88,6 +89,8 @@ func (u *User) Reduce(event *es_models.Event) (err error) {
return u.ProcessUser(event)
case org.AggregateType:
return u.ProcessOrg(event)
case instance.AggregateType:
return u.ProcessInstance(event)
default:
return nil
}
@ -229,6 +232,15 @@ func (u *User) ProcessOrg(event *es_models.Event) (err error) {
}
}
func (u *User) ProcessInstance(event *es_models.Event) (err error) {
switch eventstore.EventType(event.Type) {
case instance.InstanceRemovedEventType:
return u.view.DeleteInstanceUsers(event)
default:
return u.view.ProcessedUserSequence(event)
}
}
func (u *User) fillLoginNamesOnOrgUsers(event *es_models.Event) error {
userLoginMustBeDomain, _, domains, err := u.loginNameInformation(context.Background(), event.ResourceOwner, event.InstanceID)
if err != nil {

View File

@ -150,6 +150,8 @@ func (i *ExternalIDP) processIdpConfig(event *es_models.Event) (err error) {
i.fillConfigData(provider, config)
}
return i.view.PutExternalIDPs(event, exterinalIDPs...)
case instance.InstanceRemovedEventType:
return i.view.DeleteInstanceExternalIDPs(event)
default:
return i.view.ProcessedExternalIDPSequence(event)
}

View File

@ -17,6 +17,7 @@ import (
org_es_model "github.com/zitadel/zitadel/internal/org/repository/eventsourcing/model"
"github.com/zitadel/zitadel/internal/org/repository/view"
query2 "github.com/zitadel/zitadel/internal/query"
"github.com/zitadel/zitadel/internal/repository/instance"
"github.com/zitadel/zitadel/internal/repository/org"
"github.com/zitadel/zitadel/internal/repository/user"
view_model "github.com/zitadel/zitadel/internal/user/repository/view/model"
@ -61,7 +62,7 @@ func (u *UserSession) Subscription() *v1.Subscription {
}
func (_ *UserSession) AggregateTypes() []models.AggregateType {
return []models.AggregateType{user.AggregateType, org.AggregateType}
return []models.AggregateType{user.AggregateType, org.AggregateType, instance.AggregateType}
}
func (u *UserSession) CurrentSequence(instanceID string) (uint64, error) {
@ -153,6 +154,8 @@ func (u *UserSession) Reduce(event *models.Event) (err error) {
return u.fillLoginNamesOnOrgUsers(event)
case user.UserRemovedType:
return u.view.DeleteUserSessions(event.AggregateID, event.InstanceID, event)
case instance.InstanceRemovedEventType:
return u.view.DeleteInstanceUserSessions(event)
default:
return u.view.ProcessedUserSessionSequence(event)
}

View File

@ -56,6 +56,14 @@ func (v *View) DeleteExternalIDPsByUserID(userID, instanceID string, event *mode
return v.ProcessedExternalIDPSequence(event)
}
func (v *View) DeleteInstanceExternalIDPs(event *models.Event) error {
err := view.DeleteInstanceExternalIDPs(v.Db, externalIDPTable, event.InstanceID)
if err != nil && !errors.IsNotFound(err) {
return err
}
return v.ProcessedExternalIDPSequence(event)
}
func (v *View) GetLatestExternalIDPSequence(instanceID string) (*global_view.CurrentSequence, error) {
return v.latestSequence(externalIDPTable, instanceID)
}

View File

@ -41,6 +41,14 @@ func (v *View) DeleteIDPConfig(idpID string, event *models.Event) error {
return v.ProcessedIDPConfigSequence(event)
}
func (v *View) DeleteInstanceIDPs(event *models.Event) error {
err := view.DeleteInstanceIDPs(v.Db, idpConfigTable, event.InstanceID)
if err != nil && !errors.IsNotFound(err) {
return err
}
return v.ProcessedIDPConfigSequence(event)
}
func (v *View) GetLatestIDPConfigSequence(instanceID string) (*global_view.CurrentSequence, error) {
return v.latestSequence(idpConfigTable, instanceID)
}

View File

@ -61,6 +61,14 @@ func (v *View) DeleteIDPProvidersByAggregateID(aggregateID, instanceID string, e
return v.ProcessedIDPProviderSequence(event)
}
func (v *View) DeleteInstanceIDPProviders(event *models.Event) error {
err := view.DeleteInstanceIDPProviders(v.Db, idpProviderTable, event.InstanceID)
if err != nil && !errors.IsNotFound(err) {
return err
}
return v.ProcessedIDPProviderSequence(event)
}
func (v *View) GetLatestIDPProviderSequence(instanceID string) (*global_view.CurrentSequence, error) {
return v.latestSequence(idpProviderTable, instanceID)
}

View File

@ -32,6 +32,14 @@ func (v *View) DeleteOrgProjectMapping(orgID, projectID, instanceID string, even
return v.ProcessedOrgProjectMappingSequence(event)
}
func (v *View) DeleteInstanceOrgProjectMappings(event *models.Event) error {
err := view.DeleteInstanceOrgProjectMappings(v.Db, orgPrgojectMappingTable, event.InstanceID)
if err != nil && !errors.IsNotFound(err) {
return err
}
return v.ProcessedOrgProjectMappingSequence(event)
}
func (v *View) DeleteOrgProjectMappingsByProjectID(projectID, instanceID string) error {
return view.DeleteOrgProjectMappingsByProjectID(v.Db, orgPrgojectMappingTable, projectID, instanceID)
}

View File

@ -65,6 +65,14 @@ func (v *View) DeleteApplicationRefreshTokens(event *models.Event, ids ...string
return v.ProcessedRefreshTokenSequence(event)
}
func (v *View) DeleteInstanceRefreshTokens(event *models.Event) error {
err := usr_view.DeleteInstanceRefreshTokens(v.Db, refreshTokenTable, event.InstanceID)
if err != nil && !errors.IsNotFound(err) {
return err
}
return v.ProcessedRefreshTokenSequence(event)
}
func (v *View) GetLatestRefreshTokenSequence(instanceID string) (*repository.CurrentSequence, error) {
return v.latestSequence(refreshTokenTable, instanceID)
}

View File

@ -76,6 +76,14 @@ func (v *View) DeleteTokensFromRefreshToken(refreshTokenID, instanceID string, e
return v.ProcessedTokenSequence(event)
}
func (v *View) DeleteInstanceTokens(event *models.Event) error {
err := usr_view.DeleteInstanceTokens(v.Db, tokenTable, event.InstanceID)
if err != nil && !errors.IsNotFound(err) {
return err
}
return v.ProcessedTokenSequence(event)
}
func (v *View) GetLatestTokenSequence(instanceID string) (*repository.CurrentSequence, error) {
return v.latestSequence(tokenTable, instanceID)
}

View File

@ -181,6 +181,14 @@ func (v *View) DeleteUser(userID, instanceID string, event *models.Event) error
return v.ProcessedUserSequence(event)
}
func (v *View) DeleteInstanceUsers(event *models.Event) error {
err := view.DeleteInstanceUsers(v.Db, userTable, event.InstanceID)
if err != nil && !errors.IsNotFound(err) {
return err
}
return v.ProcessedUserSequence(event)
}
func (v *View) GetLatestUserSequence(instanceID string) (*repository.CurrentSequence, error) {
return v.latestSequence(userTable, instanceID)
}

View File

@ -56,6 +56,14 @@ func (v *View) DeleteUserSessions(userID, instanceID string, event *models.Event
return v.ProcessedUserSessionSequence(event)
}
func (v *View) DeleteInstanceUserSessions(event *models.Event) error {
err := view.DeleteInstanceUserSessions(v.Db, userSessionTable, event.InstanceID)
if err != nil && !errors.IsNotFound(err) {
return err
}
return v.ProcessedUserSessionSequence(event)
}
func (v *View) GetLatestUserSessionSequence(instanceID string) (*repository.CurrentSequence, error) {
return v.latestSequence(userSessionTable, instanceID)
}

View File

@ -550,7 +550,7 @@ func (c *Commands) prepareUpdateInstance(a *instance.Aggregate, name string) pre
if err != nil {
return nil, err
}
if writeModel.State == domain.InstanceStateUnspecified {
if !writeModel.State.Exists() {
return nil, errors.ThrowNotFound(nil, "INST-nuso2m", "Errors.Instance.NotFound")
}
if writeModel.Name == name {
@ -631,17 +631,16 @@ func (c *Commands) prepareRemoveInstance(a *instance.Aggregate) preparation.Vali
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
writeModel, err := c.getInstanceWriteModelByID(ctx, a.ID)
if err != nil {
return nil, errors.ThrowPreconditionFailed(err, "COMMA-pax9m3", "Errors.Instance.NotFound")
return nil, errors.ThrowNotFound(err, "COMMA-pax9m3", "Errors.Instance.NotFound")
}
events := []eventstore.Command{instance.NewInstanceRemovedEvent(ctx, &a.Aggregate, writeModel.Name)}
domainsWriteModel, err := c.getInstanceDomainsWriteModel(ctx, a.ID)
if err == nil {
for _, domainName := range domainsWriteModel.Domains {
events = append(events, instance.NewDomainRemovedEvent(ctx, &a.Aggregate, domainName))
}
if !writeModel.State.Exists() {
return nil, errors.ThrowNotFound(err, "COMMA-AE3GS", "Errors.Instance.NotFound")
}
return events, nil
return []eventstore.Command{instance.NewInstanceRemovedEvent(ctx,
&a.Aggregate,
writeModel.Name,
writeModel.Domains)},
nil
}, nil
}
}

View File

@ -14,6 +14,7 @@ type InstanceWriteModel struct {
Name string
State domain.InstanceState
GeneratedDomain string
Domains []string
DefaultOrgID string
ProjectID string
@ -41,10 +42,16 @@ func (wm *InstanceWriteModel) Reduce() error {
case *instance.InstanceRemovedEvent:
wm.State = domain.InstanceStateRemoved
case *instance.DomainAddedEvent:
if !e.Generated {
continue
if e.Generated {
wm.GeneratedDomain = e.Domain
}
wm.Domains = append(wm.Domains, e.Domain)
case *instance.DomainRemovedEvent:
for _, customDomain := range wm.Domains {
if customDomain == e.Domain {
wm.Domains = removeDomainFromDomains(wm.Domains, e.Domain)
}
}
wm.GeneratedDomain = e.Domain
case *instance.ProjectSetEvent:
wm.ProjectID = e.ProjectID
case *instance.DefaultOrgSetEvent:

View File

@ -14,14 +14,13 @@ import (
"github.com/zitadel/zitadel/internal/repository/instance"
)
func TestCommandSide_ChangeInstance(t *testing.T) {
func TestCommandSide_UpdateInstance(t *testing.T) {
type fields struct {
eventstore *eventstore.Eventstore
}
type args struct {
ctx context.Context
name string
instanceID string
ctx context.Context
name string
}
type res struct {
want *domain.ObjectDetails
@ -41,9 +40,8 @@ func TestCommandSide_ChangeInstance(t *testing.T) {
),
},
args: args{
ctx: authz.WithInstanceID(context.Background(), "INSTANCE"),
instanceID: "INSTANCE",
name: "",
ctx: authz.WithInstanceID(context.Background(), "INSTANCE"),
name: "",
},
res: res{
err: caos_errs.IsErrorInvalidArgument,
@ -58,17 +56,15 @@ func TestCommandSide_ChangeInstance(t *testing.T) {
),
},
args: args{
ctx: authz.WithInstanceID(context.Background(), "INSTANCE"),
instanceID: "INSTANCE",
name: "INSTANCE_CHANGED",
ctx: authz.WithInstanceID(context.Background(), "INSTANCE"),
name: "INSTANCE_CHANGED",
},
res: res{
err: caos_errs.IsNotFound,
},
},
/* instance removed is not yet implemented
{
name: "generator removed, not found error",
name: "instance removed, not found error",
fields: fields{
eventstore: eventstoreExpect(
t,
@ -84,6 +80,7 @@ func TestCommandSide_ChangeInstance(t *testing.T) {
instance.NewInstanceRemovedEvent(context.Background(),
&instance.NewAggregate("INSTANCE").Aggregate,
"INSTANCE",
nil,
),
),
),
@ -96,7 +93,7 @@ func TestCommandSide_ChangeInstance(t *testing.T) {
res: res{
err: caos_errs.IsNotFound,
},
},*/
},
{
name: "no changes, precondition error",
fields: fields{
@ -114,9 +111,8 @@ func TestCommandSide_ChangeInstance(t *testing.T) {
),
},
args: args{
ctx: authz.WithInstanceID(context.Background(), "INSTANCE"),
instanceID: "INSTANCE",
name: "INSTANCE",
ctx: authz.WithInstanceID(context.Background(), "INSTANCE"),
name: "INSTANCE",
},
res: res{
err: caos_errs.IsPreconditionFailed,
@ -178,3 +174,148 @@ func TestCommandSide_ChangeInstance(t *testing.T) {
})
}
}
func TestCommandSide_RemoveInstance(t *testing.T) {
type fields struct {
eventstore *eventstore.Eventstore
}
type args struct {
ctx context.Context
instanceID string
}
type res struct {
want *domain.ObjectDetails
err func(error) bool
}
tests := []struct {
name string
fields fields
args args
res res
}{
{
name: "instance not existing, not found error",
fields: fields{
eventstore: eventstoreExpect(
t,
expectFilter(),
),
},
args: args{
ctx: authz.WithInstanceID(context.Background(), "INSTANCE"),
instanceID: "INSTANCE",
},
res: res{
err: caos_errs.IsNotFound,
},
},
{
name: "instance removed, not found error",
fields: fields{
eventstore: eventstoreExpect(
t,
expectFilter(
eventFromEventPusher(
instance.NewInstanceAddedEvent(
context.Background(),
&instance.NewAggregate("INSTANCE").Aggregate,
"INSTANCE",
),
),
eventFromEventPusher(
instance.NewInstanceRemovedEvent(context.Background(),
&instance.NewAggregate("INSTANCE").Aggregate,
"INSTANCE",
nil,
),
),
),
),
},
args: args{
ctx: authz.WithInstanceID(context.Background(), "INSTANCE"),
instanceID: "INSTANCE",
},
res: res{
err: caos_errs.IsNotFound,
},
},
{
name: "instance remove, ok",
fields: fields{
eventstore: eventstoreExpect(
t,
expectFilter(
eventFromEventPusherWithInstanceID(
"INSTANCE",
instance.NewInstanceAddedEvent(context.Background(),
&instance.NewAggregate("INSTANCE").Aggregate,
"INSTANCE",
),
),
eventFromEventPusherWithInstanceID(
"INSTANCE",
instance.NewDomainAddedEvent(context.Background(),
&instance.NewAggregate("INSTANCE").Aggregate,
"instance.domain",
true,
),
),
eventFromEventPusherWithInstanceID(
"INSTANCE",
instance.NewDomainAddedEvent(context.Background(),
&instance.NewAggregate("INSTANCE").Aggregate,
"custom.domain",
false,
),
),
),
expectPush(
[]*repository.Event{
eventFromEventPusherWithInstanceID(
"INSTANCE",
instance.NewInstanceRemovedEvent(context.Background(),
&instance.NewAggregate("INSTANCE").Aggregate,
"INSTANCE",
[]string{
"instance.domain",
"custom.domain",
},
),
),
},
uniqueConstraintsFromEventConstraint(instance.NewRemoveInstanceDomainUniqueConstraint("instance.domain")),
uniqueConstraintsFromEventConstraint(instance.NewRemoveInstanceDomainUniqueConstraint("custom.domain")),
uniqueConstraintsFromEventConstraintWithInstanceID("INSTANCE", eventstore.NewRemoveInstanceUniqueConstraints()),
),
),
},
args: args{
ctx: authz.WithInstanceID(context.Background(), "INSTANCE"),
instanceID: "INSTANCE",
},
res: res{
want: &domain.ObjectDetails{
ResourceOwner: "INSTANCE",
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
r := &Commands{
eventstore: tt.fields.eventstore,
}
got, err := r.RemoveInstance(tt.args.ctx, tt.args.instanceID)
if tt.res.err == nil {
assert.NoError(t, err)
}
if tt.res.err != nil && !tt.res.err(err) {
t.Errorf("got wrong err: %v ", err)
}
if tt.res.err == nil {
assert.Equal(t, tt.res.want, got)
}
})
}
}

View File

@ -14,6 +14,10 @@ const (
instanceStateCount
)
func (f InstanceState) Valid() bool {
return f >= 0 && f < instanceStateCount
func (s InstanceState) Valid() bool {
return s >= 0 && s < instanceStateCount
}
func (s InstanceState) Exists() bool {
return s != InstanceStateUnspecified && s != InstanceStateRemoved
}

View File

@ -12,7 +12,7 @@ import (
"github.com/zitadel/zitadel/internal/eventstore/repository"
)
//Eventstore abstracts all functions needed to store valid events
// Eventstore abstracts all functions needed to store valid events
// and filters the stored events
type Eventstore struct {
repo repository.Repository
@ -32,13 +32,13 @@ func NewEventstore(repo repository.Repository) *Eventstore {
}
}
//Health checks if the eventstore can properly work
// Health checks if the eventstore can properly work
// It checks if the repository can serve load
func (es *Eventstore) Health(ctx context.Context) error {
return es.repo.Health(ctx)
}
//Push pushes the events in a single transaction
// Push pushes the events in a single transaction
// an event needs at least an aggregate
func (es *Eventstore) Push(ctx context.Context, cmds ...Command) ([]Event, error) {
events, constraints, err := commandsToRepository(authz.GetInstance(ctx).InstanceID(), cmds)
@ -119,7 +119,7 @@ func uniqueConstraintsToRepository(instanceID string, constraints []*EventUnique
return uniqueConstraints
}
//Filter filters the stored events based on the searchQuery
// Filter filters the stored events based on the searchQuery
// and maps the events to the defined event structs
func (es *Eventstore) Filter(ctx context.Context, queryFactory *SearchQueryBuilder) ([]Event, error) {
query, err := queryFactory.build(authz.GetInstance(ctx).InstanceID())
@ -165,7 +165,7 @@ type reducer interface {
AppendEvents(...Event)
}
//FilterToReducer filters the events based on the search query, appends all events to the reducer and calls it's reduce function
// FilterToReducer filters the events based on the search query, appends all events to the reducer and calls it's reduce function
func (es *Eventstore) FilterToReducer(ctx context.Context, searchQuery *SearchQueryBuilder, r reducer) error {
events, err := es.Filter(ctx, searchQuery)
if err != nil {
@ -177,7 +177,7 @@ func (es *Eventstore) FilterToReducer(ctx context.Context, searchQuery *SearchQu
return r.Reduce()
}
//LatestSequence filters the latest sequence for the given search query
// LatestSequence filters the latest sequence for the given search query
func (es *Eventstore) LatestSequence(ctx context.Context, queryFactory *SearchQueryBuilder) (uint64, error) {
query, err := queryFactory.build(authz.GetInstance(ctx).InstanceID())
if err != nil {
@ -186,7 +186,7 @@ func (es *Eventstore) LatestSequence(ctx context.Context, queryFactory *SearchQu
return es.repo.LatestSequence(ctx, query)
}
//InstanceIDs returns the instance ids found by the search query
// InstanceIDs returns the instance ids found by the search query
func (es *Eventstore) InstanceIDs(ctx context.Context, queryFactory *SearchQueryBuilder) ([]string, error) {
query, err := queryFactory.build(authz.GetInstance(ctx).InstanceID())
if err != nil {
@ -201,7 +201,7 @@ type QueryReducer interface {
Query() *SearchQueryBuilder
}
//FilterToQueryReducer filters the events based on the search query of the query function,
// FilterToQueryReducer filters the events based on the search query of the query function,
// appends all events to the reducer and calls it's reduce function
func (es *Eventstore) FilterToQueryReducer(ctx context.Context, r QueryReducer) error {
events, err := es.Filter(ctx, r.Query())
@ -213,7 +213,7 @@ func (es *Eventstore) FilterToQueryReducer(ctx context.Context, r QueryReducer)
return r.Reduce()
}
//RegisterFilterEventMapper registers a function for mapping an eventstore event to an event
// RegisterFilterEventMapper registers a function for mapping an eventstore event to an event
func (es *Eventstore) RegisterFilterEventMapper(eventType EventType, mapper func(*repository.Event) (Event, error)) *Eventstore {
if mapper == nil || eventType == "" {
return es
@ -258,6 +258,8 @@ func uniqueConstraintActionToRepository(action UniqueConstraintAction) repositor
return repository.UniqueConstraintAdd
case UniqueConstraintRemove:
return repository.UniqueConstraintRemoved
case UniqueConstraintInstanceRemove:
return repository.UniqueConstraintInstanceRemoved
default:
return repository.UniqueConstraintAdd
}

View File

@ -92,6 +92,8 @@ const (
uniqueDelete = `DELETE FROM eventstore.unique_constraints
WHERE unique_type = $1 and unique_field = $2 and instance_id = $3`
uniqueDeleteInstance = `DELETE FROM eventstore.unique_constraints
WHERE instance_id = $1`
)
type CRDB struct {
@ -193,7 +195,7 @@ func (db *CRDB) handleUniqueConstraints(ctx context.Context, tx *sql.Tx, uniqueC
return caos_errs.ThrowAlreadyExists(err, "SQL-M0dsf", uniqueConstraint.ErrorMessage)
}
return caos_errs.ThrowInternal(err, "SQL-dM9ds", "unable to create unique constraint ")
return caos_errs.ThrowInternal(err, "SQL-dM9ds", "unable to create unique constraint")
}
case repository.UniqueConstraintRemoved:
_, err := tx.ExecContext(ctx, uniqueDelete, uniqueConstraint.UniqueType, uniqueConstraint.UniqueField, uniqueConstraint.InstanceID)
@ -201,7 +203,14 @@ func (db *CRDB) handleUniqueConstraints(ctx context.Context, tx *sql.Tx, uniqueC
logging.WithFields(
"unique_type", uniqueConstraint.UniqueType,
"unique_field", uniqueConstraint.UniqueField).WithError(err).Info("delete unique constraint failed")
return caos_errs.ThrowInternal(err, "SQL-6n88i", "unable to remove unique constraint ")
return caos_errs.ThrowInternal(err, "SQL-6n88i", "unable to remove unique constraint")
}
case repository.UniqueConstraintInstanceRemoved:
_, err := tx.ExecContext(ctx, uniqueDeleteInstance, uniqueConstraint.InstanceID)
if err != nil {
logging.WithFields(
"instance_id", uniqueConstraint.InstanceID).WithError(err).Info("delete instance unique constraints failed")
return caos_errs.ThrowInternal(err, "SQL-6n88i", "unable to remove unique constraints of instance")
}
}
}

View File

@ -379,24 +379,28 @@ func TestCRDB_Push_OneAggregate(t *testing.T) {
}},
},
{
name: "push 1 event and add asset",
name: "push 1 event and remove instance unique constraints",
args: args{
ctx: context.Background(),
events: []*repository.Event{
generateEvent(t, "12"),
},
uniqueConstraints: generateRemoveInstanceUniqueConstraints(t, "instanceID"),
uniqueDataType: "usernames",
uniqueDataField: "testremove",
uniqueDataInstanceID: "instanceID",
},
res: res{
wantErr: false,
eventsRes: eventsRes{
pushedEventsCount: 1,
assetCount: 1,
uniqueCount: 0,
aggID: []string{"12"},
aggType: repository.AggregateType(t.Name()),
}},
},
{
name: "push 1 event and remove asset",
name: "push 1 event and add asset",
args: args{
ctx: context.Background(),
events: []*repository.Event{
@ -407,11 +411,28 @@ func TestCRDB_Push_OneAggregate(t *testing.T) {
wantErr: false,
eventsRes: eventsRes{
pushedEventsCount: 1,
assetCount: 0,
assetCount: 1,
aggID: []string{"13"},
aggType: repository.AggregateType(t.Name()),
}},
},
{
name: "push 1 event and remove asset",
args: args{
ctx: context.Background(),
events: []*repository.Event{
generateEvent(t, "14"),
},
},
res: res{
wantErr: false,
eventsRes: eventsRes{
pushedEventsCount: 1,
assetCount: 0,
aggID: []string{"14"},
aggType: repository.AggregateType(t.Name()),
}},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
@ -1201,3 +1222,13 @@ func generateRemoveUniqueConstraint(t *testing.T, table, uniqueField string) *re
return e
}
func generateRemoveInstanceUniqueConstraints(t *testing.T, instanceID string) *repository.UniqueConstraint {
t.Helper()
e := &repository.UniqueConstraint{
InstanceID: instanceID,
Action: repository.UniqueConstraintInstanceRemoved,
}
return e
}

View File

@ -1,6 +1,6 @@
package repository
//UniqueCheck represents all information about a unique attribute
// UniqueCheck represents all information about a unique attribute
type UniqueConstraint struct {
//UniqueField is the field which should be unique
UniqueField string
@ -23,6 +23,7 @@ type UniqueConstraintAction int32
const (
UniqueConstraintAdd UniqueConstraintAction = iota
UniqueConstraintRemoved
UniqueConstraintInstanceRemoved
uniqueConstraintActionCount
)

View File

@ -18,6 +18,7 @@ type UniqueConstraintAction int32
const (
UniqueConstraintAdd UniqueConstraintAction = iota
UniqueConstraintRemove
UniqueConstraintInstanceRemove
)
func NewAddEventUniqueConstraint(
@ -42,6 +43,12 @@ func NewRemoveEventUniqueConstraint(
}
}
func NewRemoveInstanceUniqueConstraints() *EventUniqueConstraint {
return &EventUniqueConstraint{
Action: UniqueConstraintInstanceRemove,
}
}
func NewAddGlobalEventUniqueConstraint(
uniqueType,
uniqueField,

View File

@ -112,3 +112,8 @@ func DeleteIDPProvidersByAggregateID(db *gorm.DB, table, aggregateID, instanceID
)
return delete(db)
}
func DeleteInstanceIDPProviders(db *gorm.DB, table, instanceID string) error {
delete := repository.PrepareDeleteByKey(table, model.IDPProviderSearchKey(iam_model.IDPProviderSearchKeyInstanceID), instanceID)
return delete(db)
}

View File

@ -63,6 +63,10 @@ func DeleteIDP(db *gorm.DB, table, idpID, instanceID string) error {
repository.Key{model.IDPConfigSearchKey(iam_model.IDPConfigSearchKeyIdpConfigID), idpID},
repository.Key{model.IDPConfigSearchKey(iam_model.IDPConfigSearchKeyInstanceID), instanceID},
)
return delete(db)
}
func DeleteInstanceIDPs(db *gorm.DB, table, instanceID string) error {
delete := repository.PrepareDeleteByKey(table, model.IDPConfigSearchKey(iam_model.IDPConfigSearchKeyInstanceID), instanceID)
return delete(db)
}

View File

@ -28,8 +28,7 @@ func PutStyling(db *gorm.DB, table string, policy *model.LabelPolicyView) error
return save(db, policy)
}
func DeleteStyling(db *gorm.DB, table, aggregateID string) error {
delete := repository.PrepareDeleteByKey(table, model.LabelPolicySearchKey(iam_model.LabelPolicySearchKeyAggregateID), aggregateID)
func DeleteInstanceStyling(db *gorm.DB, table, instanceID string) error {
delete := repository.PrepareDeleteByKey(table, model.LabelPolicySearchKey(iam_model.LabelPolicySearchKeyInstanceID), instanceID)
return delete(db)
}

View File

@ -37,6 +37,11 @@ func DeleteOrgProjectMapping(db *gorm.DB, table, orgID, projectID, instanceID st
return delete(db)
}
func DeleteInstanceOrgProjectMappings(db *gorm.DB, table, instanceID string) error {
delete := repository.PrepareDeleteByKey(table, model.OrgProjectMappingSearchKey(proj_model.OrgProjectMappingSearchKeyInstanceID), instanceID)
return delete(db)
}
func DeleteOrgProjectMappingsByProjectID(db *gorm.DB, table, projectID, instanceID string) error {
delete := repository.PrepareDeleteByKeys(table,
repository.Key{model.OrgProjectMappingSearchKey(proj_model.OrgProjectMappingSearchKeyProjectID), projectID},

View File

@ -179,7 +179,7 @@ func TestActionProjection_reduces(t *testing.T) {
event: getEvent(testEvent(
repository.EventType(instance.InstanceRemovedEventType),
instance.AggregateType,
[]byte(`{"name": "Name"}`),
nil,
), instance.InstanceRemovedEventMapper),
},
reduce: reduceInstanceRemovedHelper(ActionInstanceIDCol),

View File

@ -220,7 +220,7 @@ func TestAppProjection_reduces(t *testing.T) {
event: getEvent(testEvent(
repository.EventType(instance.InstanceRemovedEventType),
instance.AggregateType,
[]byte(`{"name": "Name"}`),
nil,
), instance.InstanceRemovedEventMapper),
},
reduce: reduceInstanceRemovedHelper(AppColumnInstanceID),

View File

@ -226,7 +226,7 @@ func TestAuthNKeyProjection_reduces(t *testing.T) {
event: getEvent(testEvent(
repository.EventType(instance.InstanceRemovedEventType),
instance.AggregateType,
[]byte(`{"name": "Name"}`),
nil,
), instance.InstanceRemovedEventMapper),
},
reduce: reduceInstanceRemovedHelper(AuthNKeyInstanceIDCol),

View File

@ -132,7 +132,7 @@ func TestCustomTextProjection_reduces(t *testing.T) {
event: getEvent(testEvent(
repository.EventType(instance.InstanceRemovedEventType),
instance.AggregateType,
[]byte(`{"name": "Name"}`),
nil,
), instance.InstanceRemovedEventMapper),
},
reduce: reduceInstanceRemovedHelper(CustomTextInstanceIDCol),

View File

@ -217,7 +217,7 @@ func TestDebugNotificationProviderProjection_reduces(t *testing.T) {
event: getEvent(testEvent(
repository.EventType(instance.InstanceRemovedEventType),
instance.AggregateType,
[]byte(`{"name": "Name"}`),
nil,
), instance.InstanceRemovedEventMapper),
},
reduce: reduceInstanceRemovedHelper(DebugNotificationProviderInstanceIDCol),

View File

@ -129,7 +129,7 @@ func TestDomainPolicyProjection_reduces(t *testing.T) {
event: getEvent(testEvent(
repository.EventType(instance.InstanceRemovedEventType),
instance.AggregateType,
[]byte(`{"name": "Name"}`),
nil,
), instance.InstanceRemovedEventMapper),
},
reduce: reduceInstanceRemovedHelper(DomainPolicyInstanceIDCol),

View File

@ -109,7 +109,7 @@ func TestFlowProjection_reduces(t *testing.T) {
event: getEvent(testEvent(
repository.EventType(instance.InstanceRemovedEventType),
instance.AggregateType,
[]byte(`{"name": "Name"}`),
nil,
), instance.InstanceRemovedEventMapper),
},
reduce: reduceInstanceRemovedHelper(FlowInstanceIDCol),

View File

@ -190,7 +190,7 @@ func TestIDPLoginPolicyLinkProjection_reduces(t *testing.T) {
event: getEvent(testEvent(
repository.EventType(instance.InstanceRemovedEventType),
instance.AggregateType,
[]byte(`{"name": "Name"}`),
nil,
), instance.InstanceRemovedEventMapper),
},
reduce: reduceInstanceRemovedHelper(IDPUserLinkInstanceIDCol),

View File

@ -201,7 +201,7 @@ func TestIDPProjection_reduces(t *testing.T) {
event: getEvent(testEvent(
repository.EventType(instance.InstanceRemovedEventType),
instance.AggregateType,
[]byte(`{"name": "Name"}`),
nil,
), instance.InstanceRemovedEventMapper),
},
reduce: reduceInstanceRemovedHelper(IDPInstanceIDCol),

View File

@ -154,7 +154,7 @@ func TestIDPUserLinkProjection_reduces(t *testing.T) {
event: getEvent(testEvent(
repository.EventType(instance.InstanceRemovedEventType),
instance.AggregateType,
[]byte(`{"name": "Name"}`),
nil,
), instance.InstanceRemovedEventMapper),
},
reduce: reduceInstanceRemovedHelper(IDPUserLinkInstanceIDCol),

View File

@ -85,7 +85,7 @@ func TestInstanceDomainProjection_reduces(t *testing.T) {
event: getEvent(testEvent(
repository.EventType(instance.InstanceRemovedEventType),
instance.AggregateType,
[]byte(`{"name": "Name"}`),
nil,
), instance.InstanceRemovedEventMapper),
},
reduce: reduceInstanceRemovedHelper(InstanceDomainInstanceIDCol),

View File

@ -178,7 +178,7 @@ func TestInstanceMemberProjection_reduces(t *testing.T) {
event: getEvent(testEvent(
repository.EventType(instance.InstanceRemovedEventType),
instance.AggregateType,
[]byte(`{"name": "Name"}`),
nil,
), instance.InstanceRemovedEventMapper),
},
reduce: reduceInstanceRemovedHelper(MemberInstanceID),

View File

@ -56,7 +56,7 @@ func TestInstanceProjection_reduces(t *testing.T) {
event: getEvent(testEvent(
repository.EventType(instance.InstanceRemovedEventType),
instance.AggregateType,
[]byte(`{"name": "Name"}`),
nil,
), instance.InstanceRemovedEventMapper),
},
reduce: reduceInstanceRemovedHelper(InstanceColumnID),

View File

@ -106,7 +106,7 @@ func TestKeyProjection_reduces(t *testing.T) {
event: getEvent(testEvent(
repository.EventType(instance.InstanceRemovedEventType),
instance.AggregateType,
[]byte(`{"name": "Name"}`),
nil,
), instance.InstanceRemovedEventMapper),
},
reduce: reduceInstanceRemovedHelper(KeyColumnInstanceID),

View File

@ -131,7 +131,7 @@ func TestLabelPolicyProjection_reduces(t *testing.T) {
event: getEvent(testEvent(
repository.EventType(instance.InstanceRemovedEventType),
instance.AggregateType,
[]byte(`{"name": "Name"}`),
nil,
), instance.InstanceRemovedEventMapper),
},
reduce: reduceInstanceRemovedHelper(LabelPolicyInstanceIDCol),

View File

@ -125,7 +125,7 @@ func TestLockoutPolicyProjection_reduces(t *testing.T) {
event: getEvent(testEvent(
repository.EventType(instance.InstanceRemovedEventType),
instance.AggregateType,
[]byte(`{"name": "Name"}`),
nil,
), instance.InstanceRemovedEventMapper),
},
reduce: reduceInstanceRemovedHelper(LockoutPolicyInstanceIDCol),

View File

@ -213,7 +213,7 @@ func (p *loginNameProjection) reducers() []handler.AggregateReducer {
},
{
Event: instance.InstanceRemovedEventType,
Reduce: reduceInstanceRemovedHelper(LoginNameUserInstanceIDCol),
Reduce: p.reduceInstanceRemoved,
},
},
},
@ -432,3 +432,32 @@ func (p *loginNameProjection) reduceDomainRemoved(event eventstore.Event) (*hand
crdb.WithTableSuffix(loginNameDomainSuffix),
), nil
}
func (p *loginNameProjection) reduceInstanceRemoved(event eventstore.Event) (*handler.Statement, error) {
e, ok := event.(*instance.InstanceRemovedEvent)
if !ok {
return nil, errors.ThrowInvalidArgumentf(nil, "HANDL-ASeg3", "reduce.wrong.event.type %s", instance.InstanceRemovedEventType)
}
return crdb.NewMultiStatement(
event,
crdb.AddDeleteStatement(
[]handler.Condition{
handler.NewCond(LoginNameDomainInstanceIDCol, e.Aggregate().ID),
},
crdb.WithTableSuffix(loginNameDomainSuffix),
),
crdb.AddDeleteStatement(
[]handler.Condition{
handler.NewCond(LoginNamePoliciesInstanceIDCol, e.Aggregate().ID),
},
crdb.WithTableSuffix(loginNamePolicySuffix),
),
crdb.AddDeleteStatement(
[]handler.Condition{
handler.NewCond(LoginNameUserInstanceIDCol, e.Aggregate().ID),
},
crdb.WithTableSuffix(loginNameUserSuffix),
),
), nil
}

View File

@ -486,10 +486,10 @@ func TestLoginNameProjection_reduces(t *testing.T) {
event: getEvent(testEvent(
repository.EventType(instance.InstanceRemovedEventType),
instance.AggregateType,
[]byte(`{"name": "Name"}`),
nil,
), instance.InstanceRemovedEventMapper),
},
reduce: reduceInstanceRemovedHelper(LoginNameUserInstanceIDCol),
reduce: (&loginNameProjection{}).reduceInstanceRemoved,
want: wantReduce{
aggregateType: eventstore.AggregateType("instance"),
sequence: 15,
@ -497,7 +497,19 @@ func TestLoginNameProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "DELETE FROM projections.login_names WHERE (instance_id = $1)",
expectedStmt: "DELETE FROM projections.login_names_domains WHERE (instance_id = $1)",
expectedArgs: []interface{}{
"agg-id",
},
},
{
expectedStmt: "DELETE FROM projections.login_names_policies WHERE (instance_id = $1)",
expectedArgs: []interface{}{
"agg-id",
},
},
{
expectedStmt: "DELETE FROM projections.login_names_users WHERE (instance_id = $1)",
expectedArgs: []interface{}{
"agg-id",
},

View File

@ -543,7 +543,7 @@ func TestLoginPolicyProjection_reduces(t *testing.T) {
event: getEvent(testEvent(
repository.EventType(instance.InstanceRemovedEventType),
instance.AggregateType,
[]byte(`{"name": "Name"}`),
nil,
), instance.InstanceRemovedEventMapper),
},
reduce: reduceInstanceRemovedHelper(LoginPolicyInstanceIDCol),

View File

@ -82,11 +82,6 @@ func (p *mailTemplateProjection) reducers() []handler.AggregateReducer {
Event: instance.MailTemplateChangedEventType,
Reduce: p.reduceChanged,
},
},
},
{
Aggregate: instance.AggregateType,
EventRedusers: []handler.EventReducer{
{
Event: instance.InstanceRemovedEventType,
Reduce: reduceInstanceRemovedHelper(MailTemplateInstanceIDCol),

View File

@ -120,7 +120,7 @@ func TestMailTemplateProjection_reduces(t *testing.T) {
event: getEvent(testEvent(
repository.EventType(instance.InstanceRemovedEventType),
instance.AggregateType,
[]byte(`{"name": "Name"}`),
nil,
), instance.InstanceRemovedEventMapper),
},
reduce: reduceInstanceRemovedHelper(MailTemplateInstanceIDCol),

View File

@ -336,7 +336,7 @@ func TestMessageTextProjection_reduces(t *testing.T) {
event: getEvent(testEvent(
repository.EventType(instance.InstanceRemovedEventType),
instance.AggregateType,
[]byte(`{"name": "Name"}`),
nil,
), instance.InstanceRemovedEventMapper),
},
reduce: reduceInstanceRemovedHelper(MessageTextInstanceIDCol),

View File

@ -66,11 +66,6 @@ func (p *oidcSettingsProjection) reducers() []handler.AggregateReducer {
Event: instance.OIDCSettingsChangedEventType,
Reduce: p.reduceOIDCSettingsChanged,
},
},
},
{
Aggregate: instance.AggregateType,
EventRedusers: []handler.EventReducer{
{
Event: instance.InstanceRemovedEventType,
Reduce: reduceInstanceRemovedHelper(OIDCSettingsColumnInstanceID),

View File

@ -94,7 +94,7 @@ func TestOIDCSettingsProjection_reduces(t *testing.T) {
event: getEvent(testEvent(
repository.EventType(instance.InstanceRemovedEventType),
instance.AggregateType,
[]byte(`{"name": "Name"}`),
nil,
), instance.InstanceRemovedEventMapper),
},
reduce: reduceInstanceRemovedHelper(OIDCSettingsColumnInstanceID),

View File

@ -194,7 +194,7 @@ func TestOrgDomainProjection_reduces(t *testing.T) {
event: getEvent(testEvent(
repository.EventType(instance.InstanceRemovedEventType),
instance.AggregateType,
[]byte(`{"name": "Name"}`),
nil,
), instance.InstanceRemovedEventMapper),
},
reduce: reduceInstanceRemovedHelper(OrgDomainInstanceIDCol),

View File

@ -208,7 +208,7 @@ func TestOrgMemberProjection_reduces(t *testing.T) {
event: getEvent(testEvent(
repository.EventType(instance.InstanceRemovedEventType),
instance.AggregateType,
[]byte(`{"name": "Name"}`),
nil,
), instance.InstanceRemovedEventMapper),
},
reduce: reduceInstanceRemovedHelper(MemberInstanceID),

View File

@ -7,6 +7,7 @@ import (
"github.com/zitadel/zitadel/internal/eventstore"
"github.com/zitadel/zitadel/internal/eventstore/handler"
"github.com/zitadel/zitadel/internal/eventstore/handler/crdb"
"github.com/zitadel/zitadel/internal/repository/instance"
"github.com/zitadel/zitadel/internal/repository/org"
)
@ -73,6 +74,15 @@ func (p *orgMetadataProjection) reducers() []handler.AggregateReducer {
},
},
},
{
Aggregate: instance.AggregateType,
EventRedusers: []handler.EventReducer{
{
Event: instance.InstanceRemovedEventType,
Reduce: reduceInstanceRemovedHelper(OrgMetadataColumnInstanceID),
},
},
},
}
}

View File

@ -7,6 +7,7 @@ import (
"github.com/zitadel/zitadel/internal/eventstore"
"github.com/zitadel/zitadel/internal/eventstore/handler"
"github.com/zitadel/zitadel/internal/eventstore/repository"
"github.com/zitadel/zitadel/internal/repository/instance"
"github.com/zitadel/zitadel/internal/repository/org"
)
@ -137,6 +138,32 @@ func TestOrgMetadataProjection_reduces(t *testing.T) {
},
},
},
{
name: "reduceInstanceRemoved",
args: args{
event: getEvent(testEvent(
repository.EventType(instance.InstanceRemovedEventType),
instance.AggregateType,
nil,
), instance.InstanceRemovedEventMapper),
},
reduce: reduceInstanceRemovedHelper(MemberInstanceID),
want: wantReduce{
aggregateType: eventstore.AggregateType("instance"),
sequence: 15,
previousSequence: 10,
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "DELETE FROM projections.org_metadata WHERE (instance_id = $1)",
expectedArgs: []interface{}{
"agg-id",
},
},
},
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {

View File

@ -194,7 +194,7 @@ func TestOrgProjection_reduces(t *testing.T) {
event: getEvent(testEvent(
repository.EventType(instance.InstanceRemovedEventType),
instance.AggregateType,
[]byte(`{"name": "Name"}`),
nil,
), instance.InstanceRemovedEventMapper),
},
reduce: reduceInstanceRemovedHelper(OrgColumnInstanceID),

View File

@ -125,7 +125,7 @@ func TestPasswordAgeProjection_reduces(t *testing.T) {
event: getEvent(testEvent(
repository.EventType(instance.InstanceRemovedEventType),
instance.AggregateType,
[]byte(`{"name": "Name"}`),
nil,
), instance.InstanceRemovedEventMapper),
},
reduce: reduceInstanceRemovedHelper(AgePolicyInstanceIDCol),

View File

@ -137,7 +137,7 @@ func TestPasswordComplexityProjection_reduces(t *testing.T) {
event: getEvent(testEvent(
repository.EventType(instance.InstanceRemovedEventType),
instance.AggregateType,
[]byte(`{"name": "Name"}`),
nil,
), instance.InstanceRemovedEventMapper),
},
reduce: reduceInstanceRemovedHelper(ComplexityPolicyInstanceIDCol),

View File

@ -128,7 +128,7 @@ func TestPrivacyPolicyProjection_reduces(t *testing.T) {
event: getEvent(testEvent(
repository.EventType(instance.InstanceRemovedEventType),
instance.AggregateType,
[]byte(`{"name": "Name"}`),
nil,
), instance.InstanceRemovedEventMapper),
},
reduce: reduceInstanceRemovedHelper(PrivacyPolicyInstanceIDCol),

View File

@ -216,7 +216,7 @@ func TestProjectGrantMemberProjection_reduces(t *testing.T) {
event: getEvent(testEvent(
repository.EventType(instance.InstanceRemovedEventType),
instance.AggregateType,
[]byte(`{"name": "Name"}`),
nil,
), instance.InstanceRemovedEventMapper),
},
reduce: reduceInstanceRemovedHelper(MemberInstanceID),

View File

@ -55,7 +55,7 @@ func TestProjectGrantProjection_reduces(t *testing.T) {
event: getEvent(testEvent(
repository.EventType(instance.InstanceRemovedEventType),
instance.AggregateType,
[]byte(`{"name": "Name"}`),
nil,
), instance.InstanceRemovedEventMapper),
},
reduce: reduceInstanceRemovedHelper(ProjectGrantColumnInstanceID),

View File

@ -209,7 +209,7 @@ func TestProjectMemberProjection_reduces(t *testing.T) {
event: getEvent(testEvent(
repository.EventType(instance.InstanceRemovedEventType),
instance.AggregateType,
[]byte(`{"name": "Name"}`),
nil,
), instance.InstanceRemovedEventMapper),
},
reduce: reduceInstanceRemovedHelper(MemberInstanceID),

View File

@ -53,7 +53,7 @@ func TestProjectRoleProjection_reduces(t *testing.T) {
event: getEvent(testEvent(
repository.EventType(instance.InstanceRemovedEventType),
instance.AggregateType,
[]byte(`{"name": "Name"}`),
nil,
), instance.InstanceRemovedEventMapper),
},
reduce: reduceInstanceRemovedHelper(ProjectRoleColumnInstanceID),

View File

@ -54,7 +54,7 @@ func TestProjectProjection_reduces(t *testing.T) {
event: getEvent(testEvent(
repository.EventType(instance.InstanceRemovedEventType),
instance.AggregateType,
[]byte(`{"name": "Name"}`),
nil,
), instance.InstanceRemovedEventMapper),
},
reduce: reduceInstanceRemovedHelper(ProjectColumnInstanceID),

View File

@ -76,6 +76,10 @@ func (p *secretGeneratorProjection) reducers() []handler.AggregateReducer {
Event: instance.SecretGeneratorRemovedEventType,
Reduce: p.reduceSecretGeneratorRemoved,
},
{
Event: instance.InstanceRemovedEventType,
Reduce: reduceInstanceRemovedHelper(SecretGeneratorColumnInstanceID),
},
},
},
}

View File

@ -122,6 +122,32 @@ func TestSecretGeneratorProjection_reduces(t *testing.T) {
},
},
},
{
name: "reduceInstanceRemoved",
args: args{
event: getEvent(testEvent(
repository.EventType(instance.InstanceRemovedEventType),
instance.AggregateType,
nil,
), instance.InstanceRemovedEventMapper),
},
reduce: reduceInstanceRemovedHelper(MemberInstanceID),
want: wantReduce{
aggregateType: eventstore.AggregateType("instance"),
sequence: 15,
previousSequence: 10,
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "DELETE FROM projections.secret_generators2 WHERE (instance_id = $1)",
expectedArgs: []interface{}{
"agg-id",
},
},
},
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {

View File

@ -271,7 +271,7 @@ func TestSMSProjection_reduces(t *testing.T) {
event: getEvent(testEvent(
repository.EventType(instance.InstanceRemovedEventType),
instance.AggregateType,
[]byte(`{"name": "Name"}`),
nil,
), instance.InstanceRemovedEventMapper),
},
reduce: reduceInstanceRemovedHelper(SMSColumnInstanceID),

View File

@ -151,7 +151,7 @@ func TestSMTPConfigProjection_reduces(t *testing.T) {
event: getEvent(testEvent(
repository.EventType(instance.InstanceRemovedEventType),
instance.AggregateType,
[]byte(`{"name": "Name"}`),
nil,
), instance.InstanceRemovedEventMapper),
},
reduce: reduceInstanceRemovedHelper(SMTPConfigColumnInstanceID),

View File

@ -244,7 +244,7 @@ func TestUserAuthMethodProjection_reduces(t *testing.T) {
event: getEvent(testEvent(
repository.EventType(instance.InstanceRemovedEventType),
instance.AggregateType,
[]byte(`{"name": "Name"}`),
nil,
), instance.InstanceRemovedEventMapper),
},
reduce: reduceInstanceRemovedHelper(UserAuthMethodInstanceIDCol),

View File

@ -159,7 +159,7 @@ func TestUserGrantProjection_reduces(t *testing.T) {
event: getEvent(testEvent(
repository.EventType(instance.InstanceRemovedEventType),
instance.AggregateType,
[]byte(`{"name": "Name"}`),
nil,
), instance.InstanceRemovedEventMapper),
},
reduce: reduceInstanceRemovedHelper(UserGrantInstanceID),

View File

@ -144,7 +144,7 @@ func TestUserMetadataProjection_reduces(t *testing.T) {
event: getEvent(testEvent(
repository.EventType(instance.InstanceRemovedEventType),
instance.AggregateType,
[]byte(`{"name": "Name"}`),
nil,
), instance.InstanceRemovedEventMapper),
},
reduce: reduceInstanceRemovedHelper(UserMetadataColumnInstanceID),

View File

@ -115,7 +115,7 @@ func TestPersonalAccessTokenProjection_reduces(t *testing.T) {
event: getEvent(testEvent(
repository.EventType(instance.InstanceRemovedEventType),
instance.AggregateType,
[]byte(`{"name": "Name"}`),
nil,
), instance.InstanceRemovedEventMapper),
},
reduce: reduceInstanceRemovedHelper(PersonalAccessTokenColumnInstanceID),

View File

@ -1623,7 +1623,7 @@ func TestUserProjection_reduces(t *testing.T) {
event: getEvent(testEvent(
repository.EventType(instance.InstanceRemovedEventType),
instance.AggregateType,
[]byte(`{"name": "Name"}`),
nil,
), instance.InstanceRemovedEventMapper),
},
reduce: reduceInstanceRemovedHelper(UserInstanceIDCol),

View File

@ -92,35 +92,36 @@ func InstanceChangedEventMapper(event *repository.Event) (eventstore.Event, erro
type InstanceRemovedEvent struct {
eventstore.BaseEvent `json:"-"`
name string
domains []string
}
func (e *InstanceRemovedEvent) Data() interface{} {
return e
}
func (e *InstanceRemovedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil
}
func NewInstanceRemovedEvent(ctx context.Context, aggregate *eventstore.Aggregate, name string) *InstanceRemovedEvent {
func (e *InstanceRemovedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
constraints := make([]*eventstore.EventUniqueConstraint, len(e.domains)+1)
for i, domain := range e.domains {
constraints[i] = NewRemoveInstanceDomainUniqueConstraint(domain)
}
constraints[len(e.domains)] = eventstore.NewRemoveInstanceUniqueConstraints()
return constraints
}
func NewInstanceRemovedEvent(ctx context.Context, aggregate *eventstore.Aggregate, name string, domains []string) *InstanceRemovedEvent {
return &InstanceRemovedEvent{
BaseEvent: *eventstore.NewBaseEventForPush(
ctx,
aggregate,
InstanceRemovedEventType,
),
name: name,
name: name,
domains: domains,
}
}
func InstanceRemovedEventMapper(event *repository.Event) (eventstore.Event, error) {
instanceRemoved := &InstanceRemovedEvent{
return &InstanceRemovedEvent{
BaseEvent: *eventstore.BaseEventFromRepo(event),
}
err := json.Unmarshal(event.Data, instanceRemoved)
if err != nil {
return nil, errors.ThrowInternal(err, "INSTANCE-39jlW", "unable to unmarshal instance removed")
}
return instanceRemoved, nil
}, nil
}

View File

@ -180,3 +180,20 @@ func (c *crdbStorage) RemoveObjects(ctx context.Context, instanceID, resourceOwn
}
return nil
}
func (c *crdbStorage) RemoveInstanceObjects(ctx context.Context, instanceID string) error {
stmt, args, err := squirrel.Delete(assetsTable).
Where(squirrel.Eq{
AssetColInstanceID: instanceID,
}).
PlaceholderFormat(squirrel.Dollar).
ToSql()
if err != nil {
return caos_errors.ThrowInternal(err, "DATAB-Sfgeq", "Errors.Internal")
}
_, err = c.client.ExecContext(ctx, stmt, args...)
if err != nil {
return caos_errors.ThrowInternal(err, "DATAB-Efgt2", "Errors.Assets.Object.RemoveFailed")
}
return nil
}

View File

@ -35,6 +35,8 @@ const (
" WHERE asset_type = $1" +
" AND instance_id = $2" +
" AND resource_owner = $3"
removeInstanceObjectsStmt = "DELETE FROM system.assets" +
" WHERE instance_id = $1"
)
func Test_crdbStorage_CreateObject(t *testing.T) {
@ -224,6 +226,50 @@ func Test_crdbStorage_RemoveObjects(t *testing.T) {
})
}
}
func Test_crdbStorage_RemoveInstanceObjects(t *testing.T) {
type fields struct {
client db
}
type args struct {
ctx context.Context
instanceID string
}
tests := []struct {
name string
fields fields
args args
wantErr bool
}{
{
"remove ok",
fields{
client: prepareDB(t,
expectExec(
removeInstanceObjectsStmt,
nil,
"instanceID",
)),
},
args{
ctx: context.Background(),
instanceID: "instanceID",
},
false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
c := &crdbStorage{
client: tt.fields.client.db,
}
err := c.RemoveInstanceObjects(tt.args.ctx, tt.args.instanceID)
if (err != nil) != tt.wantErr {
t.Errorf("RemoveInstanceObjects() error = %v, wantErr %v", err, tt.wantErr)
return
}
})
}
}
type db struct {
mock sqlmock.Sqlmock

View File

@ -82,6 +82,20 @@ func (mr *MockStorageMockRecorder) PutObject(ctx, instanceID, location, resource
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PutObject", reflect.TypeOf((*MockStorage)(nil).PutObject), ctx, instanceID, location, resourceOwner, name, contentType, objectType, object, objectSize)
}
// RemoveInstanceObjects mocks base method.
func (m *MockStorage) RemoveInstanceObjects(ctx context.Context, instanceID string) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "RemoveInstanceObjects", ctx, instanceID)
ret0, _ := ret[0].(error)
return ret0
}
// RemoveInstanceObjects indicates an expected call of RemoveInstanceObjects.
func (mr *MockStorageMockRecorder) RemoveInstanceObjects(ctx, instanceID interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoveInstanceObjects", reflect.TypeOf((*MockStorage)(nil).RemoveInstanceObjects), ctx, instanceID)
}
// RemoveObject mocks base method.
func (m *MockStorage) RemoveObject(ctx context.Context, instanceID, resourceOwner, name string) error {
m.ctrl.T.Helper()

View File

@ -136,6 +136,11 @@ func (m *Minio) RemoveObjects(ctx context.Context, instanceID, resourceOwner str
return g.Wait()
}
func (m *Minio) RemoveInstanceObjects(ctx context.Context, instanceID string) error {
bucketName := m.prefixBucketName(instanceID)
return m.Client.RemoveBucket(ctx, bucketName)
}
func (m *Minio) createBucket(ctx context.Context, name, location string) error {
if location == "" {
location = m.Location

View File

@ -15,6 +15,7 @@ type Storage interface {
GetObjectInfo(ctx context.Context, instanceID, resourceOwner, name string) (*Asset, error)
RemoveObject(ctx context.Context, instanceID, resourceOwner, name string) error
RemoveObjects(ctx context.Context, instanceID, resourceOwner string, objectType ObjectType) error
RemoveInstanceObjects(ctx context.Context, instanceID string) error
//TODO: add functionality to move asset location
}

View File

@ -115,3 +115,8 @@ func DeleteExternalIDPsByUserID(db *gorm.DB, table, userID, instanceID string) e
)
return delete(db)
}
func DeleteInstanceExternalIDPs(db *gorm.DB, table, instanceID string) error {
delete := repository.PrepareDeleteByKey(table, model.ExternalIDPSearchKey(usr_model.ExternalIDPSearchKeyInstanceID), instanceID)
return delete(db)
}

View File

@ -94,3 +94,8 @@ func DeleteApplicationRefreshTokens(db *gorm.DB, table string, appIDs []string)
delete := repository.PrepareDeleteByKey(table, usr_model.RefreshTokenSearchKey(model.RefreshTokenSearchKeyApplicationID), appIDs)
return delete(db)
}
func DeleteInstanceRefreshTokens(db *gorm.DB, table string, instanceID string) error {
delete := repository.PrepareDeleteByKey(table, usr_model.RefreshTokenSearchKey(model.RefreshTokenSearchKeyInstanceID), instanceID)
return delete(db)
}

View File

@ -97,3 +97,8 @@ func DeleteApplicationTokens(db *gorm.DB, table, instanceID string, appIDs []str
)
return delete(db)
}
func DeleteInstanceTokens(db *gorm.DB, table, instanceID string) error {
delete := repository.PrepareDeleteByKey(table, usr_model.TokenSearchKey(model.TokenSearchKeyInstanceID), instanceID)
return delete(db)
}

View File

@ -125,3 +125,8 @@ func DeleteUserSessions(db *gorm.DB, table, userID, instanceID string) error {
)
return delete(db)
}
func DeleteInstanceUserSessions(db *gorm.DB, table, instanceID string) error {
delete := repository.PrepareDeleteByKey(table, model.UserSessionSearchKey(usr_model.UserSessionSearchKeyInstanceID), instanceID)
return delete(db)
}

View File

@ -204,3 +204,8 @@ func DeleteUser(db *gorm.DB, table, userID, instanceID string) error {
)
return delete(db)
}
func DeleteInstanceUsers(db *gorm.DB, table, instanceID string) error {
delete := repository.PrepareDeleteByKey(table, model.UserSearchKey(usr_model.UserSearchKeyInstanceID), instanceID)
return delete(db)
}