fix: env.json caching, readiness and unique lockerIDs (#3596)

* fix: readiness check

* disable cache for env.json

* always generate unique lockerID

* fix tests
This commit is contained in:
Livio Amstutz 2022-05-04 17:09:49 +02:00 committed by GitHub
parent 929ed8745a
commit 94e420bb24
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 8 additions and 276 deletions

View File

@ -15,7 +15,6 @@ import (
"github.com/zitadel/zitadel/internal/api/grpc/server"
http_util "github.com/zitadel/zitadel/internal/api/http"
"github.com/zitadel/zitadel/internal/authz/repository"
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/errors"
"github.com/zitadel/zitadel/internal/query"
"github.com/zitadel/zitadel/internal/telemetry/tracing"
@ -139,19 +138,6 @@ func (a *API) healthHandler() http.Handler {
}
return nil
},
func(ctx context.Context) error {
iam, err := a.health.Instance(ctx)
if err != nil && !errors.IsNotFound(err) {
return errors.ThrowPreconditionFailed(err, "API-dsgT2", "IAM SETUP CHECK FAILED")
}
if iam == nil || iam.SetupStarted < domain.StepCount-1 {
return errors.ThrowPreconditionFailed(nil, "API-HBfs3", "IAM NOT SET UP")
}
if iam.SetupDone < domain.StepCount-1 {
return errors.ThrowPreconditionFailed(nil, "API-DASs2", "IAM SETUP RUNNING")
}
return nil
},
}
handler := http.NewServeMux()
handler.HandleFunc("/healthz", handleHealth)

View File

@ -73,7 +73,7 @@ func Start(config Config, externalSecure bool, issuer op.IssuerFromRequest, inst
security := middleware.SecurityHeaders(csp(), nil)
handler := mux.NewRouter()
handler.Use(cache, security)
handler.Use(security)
handler.Handle(envRequestPath, middleware.TelemetryHandler()(instanceHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
instance := authz.GetInstance(r.Context())
if instance.InstanceID() == "" {
@ -89,7 +89,7 @@ func Start(config Config, externalSecure bool, issuer op.IssuerFromRequest, inst
_, err = w.Write(environmentJSON)
logging.OnError(err).Error("error serving environment.json")
}))))
handler.SkipClean(true).PathPrefix("").Handler(http.FileServer(&spaHandler{http.FS(fSys)}))
handler.SkipClean(true).PathPrefix("").Handler(cache(http.FileServer(&spaHandler{http.FS(fSys)})))
return handler, nil
}

View File

@ -15,9 +15,6 @@ type InstanceWriteModel struct {
State domain.InstanceState
GeneratedDomain string
SetUpStarted domain.Step
SetUpDone domain.Step
GlobalOrgID string
ProjectID string
DefaultLanguage language.Tag
@ -53,12 +50,6 @@ func (wm *InstanceWriteModel) Reduce() error {
wm.GlobalOrgID = e.OrgID
case *instance.DefaultLanguageSetEvent:
wm.DefaultLanguage = e.Language
case *instance.SetupStepEvent:
if e.Done {
wm.SetUpDone = e.Step
} else {
wm.SetUpStarted = e.Step
}
}
}
return nil
@ -78,9 +69,7 @@ func (wm *InstanceWriteModel) Query() *eventstore.SearchQueryBuilder {
instance.InstanceDomainRemovedEventType,
instance.ProjectSetEventType,
instance.GlobalOrgSetEventType,
instance.DefaultLanguageSetEventType,
instance.SetupStartedEventType,
instance.SetupDoneEventType).
instance.DefaultLanguageSetEventType).
Builder()
}

View File

@ -4,7 +4,6 @@ import (
"context"
"database/sql"
"fmt"
"os"
"time"
"github.com/zitadel/logging"
@ -34,11 +33,8 @@ type locker struct {
}
func NewLocker(client *sql.DB, lockTable, projectionName string) Locker {
workerName, err := os.Hostname()
if err != nil || workerName == "" {
workerName, err = id.SonyFlakeGenerator.Next()
logging.OnError(err).Panic("unable to generate lockID")
}
workerName, err := id.SonyFlakeGenerator.Next()
logging.OnError(err).Panic("unable to generate lockID")
return &locker{
client: client,
lockStmt: fmt.Sprintf(lockStmtFormat, lockTable),

View File

@ -2,7 +2,6 @@ package spooler
import (
"math/rand"
"os"
"github.com/zitadel/logging"
@ -19,11 +18,8 @@ type Config struct {
}
func (c *Config) New() *Spooler {
lockID, err := os.Hostname()
if err != nil || lockID == "" {
lockID, err = id.SonyFlakeGenerator.Next()
logging.OnError(err).Panic("unable to generate lockID")
}
lockID, err := id.SonyFlakeGenerator.Next()
logging.OnError(err).Panic("unable to generate lockID")
//shuffle the handlers for better balance when running multiple pods
rand.Shuffle(len(c.ViewHandlers), func(i, j int) {

View File

@ -11,7 +11,6 @@ import (
"golang.org/x/text/language"
"github.com/zitadel/zitadel/internal/api/authz"
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/errors"
"github.com/zitadel/zitadel/internal/query/projection"
)
@ -56,14 +55,6 @@ var (
name: projection.InstanceColumnConsoleAppID,
table: instanceTable,
}
InstanceColumnSetupStarted = Column{
name: projection.InstanceColumnSetUpStarted,
table: instanceTable,
}
InstanceColumnSetupDone = Column{
name: projection.InstanceColumnSetUpDone,
table: instanceTable,
}
InstanceColumnDefaultLanguage = Column{
name: projection.InstanceColumnDefaultLanguage,
table: instanceTable,
@ -82,8 +73,6 @@ type Instance struct {
ConsoleID string
ConsoleAppID string
DefaultLang language.Tag
SetupStarted domain.Step
SetupDone domain.Step
Domains []*InstanceDomain
host string
}
@ -211,8 +200,6 @@ func prepareInstanceQuery(host string) (sq.SelectBuilder, func(*sql.Row) (*Insta
InstanceColumnProjectID.identifier(),
InstanceColumnConsoleID.identifier(),
InstanceColumnConsoleAppID.identifier(),
InstanceColumnSetupStarted.identifier(),
InstanceColumnSetupDone.identifier(),
InstanceColumnDefaultLanguage.identifier(),
).
From(instanceTable.identifier()).PlaceholderFormat(sq.Dollar),
@ -228,8 +215,6 @@ func prepareInstanceQuery(host string) (sq.SelectBuilder, func(*sql.Row) (*Insta
&instance.IAMProjectID,
&instance.ConsoleID,
&instance.ConsoleAppID,
&instance.SetupStarted,
&instance.SetupDone,
&lang,
)
if err != nil {
@ -254,8 +239,6 @@ func prepareInstancesQuery() (sq.SelectBuilder, func(*sql.Rows) (*Instances, err
InstanceColumnProjectID.identifier(),
InstanceColumnConsoleID.identifier(),
InstanceColumnConsoleAppID.identifier(),
InstanceColumnSetupStarted.identifier(),
InstanceColumnSetupDone.identifier(),
InstanceColumnDefaultLanguage.identifier(),
countColumn.identifier(),
).From(instanceTable.identifier()).PlaceholderFormat(sq.Dollar),
@ -276,8 +259,6 @@ func prepareInstancesQuery() (sq.SelectBuilder, func(*sql.Rows) (*Instances, err
&instance.IAMProjectID,
&instance.ConsoleID,
&instance.ConsoleAppID,
&instance.SetupStarted,
&instance.SetupDone,
&lang,
&count,
)
@ -312,8 +293,6 @@ func prepareInstanceDomainQuery(host string) (sq.SelectBuilder, func(*sql.Rows)
InstanceColumnProjectID.identifier(),
InstanceColumnConsoleID.identifier(),
InstanceColumnConsoleAppID.identifier(),
InstanceColumnSetupStarted.identifier(),
InstanceColumnSetupDone.identifier(),
InstanceColumnDefaultLanguage.identifier(),
InstanceDomainDomainCol.identifier(),
InstanceDomainIsPrimaryCol.identifier(),
@ -350,8 +329,6 @@ func prepareInstanceDomainQuery(host string) (sq.SelectBuilder, func(*sql.Rows)
&instance.IAMProjectID,
&instance.ConsoleID,
&instance.ConsoleAppID,
&instance.SetupStarted,
&instance.SetupDone,
&lang,
&domain,
&isPrimary,

View File

@ -11,7 +11,6 @@ import (
sq "github.com/Masterminds/squirrel"
"golang.org/x/text/language"
"github.com/zitadel/zitadel/internal/domain"
errs "github.com/zitadel/zitadel/internal/errors"
)
@ -41,8 +40,6 @@ func Test_InstancePrepares(t *testing.T) {
` projections.instances.iam_project_id,`+
` projections.instances.console_client_id,`+
` projections.instances.console_app_id,`+
` projections.instances.setup_started,`+
` projections.instances.setup_done,`+
` projections.instances.default_language`+
` FROM projections.instances`),
nil,
@ -72,8 +69,6 @@ func Test_InstancePrepares(t *testing.T) {
` projections.instances.iam_project_id,`+
` projections.instances.console_client_id,`+
` projections.instances.console_app_id,`+
` projections.instances.setup_started,`+
` projections.instances.setup_done,`+
` projections.instances.default_language`+
` FROM projections.instances`),
[]string{
@ -85,8 +80,6 @@ func Test_InstancePrepares(t *testing.T) {
"iam_project_id",
"console_client_id",
"console_app_id",
"setup_started",
"setup_done",
"default_language",
},
[]driver.Value{
@ -98,8 +91,6 @@ func Test_InstancePrepares(t *testing.T) {
"project-id",
"client-id",
"app-id",
domain.Step2,
domain.Step1,
"en",
},
),
@ -113,8 +104,6 @@ func Test_InstancePrepares(t *testing.T) {
IAMProjectID: "project-id",
ConsoleID: "client-id",
ConsoleAppID: "app-id",
SetupStarted: domain.Step2,
SetupDone: domain.Step1,
DefaultLang: language.English,
},
},
@ -133,8 +122,6 @@ func Test_InstancePrepares(t *testing.T) {
` projections.instances.iam_project_id,`+
` projections.instances.console_client_id,`+
` projections.instances.console_app_id,`+
` projections.instances.setup_started,`+
` projections.instances.setup_done,`+
` projections.instances.default_language`+
` FROM projections.instances`),
sql.ErrConnDone,

View File

@ -22,8 +22,6 @@ const (
InstanceColumnConsoleID = "console_client_id"
InstanceColumnConsoleAppID = "console_app_id"
InstanceColumnSequence = "sequence"
InstanceColumnSetUpStarted = "setup_started"
InstanceColumnSetUpDone = "setup_done"
InstanceColumnDefaultLanguage = "default_language"
)
@ -46,8 +44,6 @@ func NewInstanceProjection(ctx context.Context, config crdb.StatementHandlerConf
crdb.NewColumn(InstanceColumnConsoleID, crdb.ColumnTypeText, crdb.Default("")),
crdb.NewColumn(InstanceColumnConsoleAppID, crdb.ColumnTypeText, crdb.Default("")),
crdb.NewColumn(InstanceColumnSequence, crdb.ColumnTypeInt64),
crdb.NewColumn(InstanceColumnSetUpStarted, crdb.ColumnTypeInt64, crdb.Default(0)),
crdb.NewColumn(InstanceColumnSetUpDone, crdb.ColumnTypeInt64, crdb.Default(0)),
crdb.NewColumn(InstanceColumnDefaultLanguage, crdb.ColumnTypeText, crdb.Default("")),
},
crdb.NewPrimaryKey(InstanceColumnID),
@ -82,14 +78,6 @@ func (p *InstanceProjection) reducers() []handler.AggregateReducer {
Event: instance.DefaultLanguageSetEventType,
Reduce: p.reduceDefaultLanguageSet,
},
{
Event: instance.SetupStartedEventType,
Reduce: p.reduceSetupEvent,
},
{
Event: instance.SetupDoneEventType,
Reduce: p.reduceSetupEvent,
},
},
},
}
@ -184,24 +172,3 @@ func (p *InstanceProjection) reduceDefaultLanguageSet(event eventstore.Event) (*
},
), nil
}
func (p *InstanceProjection) reduceSetupEvent(event eventstore.Event) (*handler.Statement, error) {
e, ok := event.(*instance.SetupStepEvent)
if !ok {
return nil, errors.ThrowInvalidArgumentf(nil, "HANDL-d9nfw", "reduce.wrong.event.type %v", []eventstore.EventType{instance.SetupDoneEventType, instance.SetupStartedEventType})
}
columns := []handler.Column{
handler.NewCol(InstanceColumnID, e.Aggregate().InstanceID),
handler.NewCol(InstanceColumnChangeDate, e.CreationDate()),
handler.NewCol(InstanceColumnSequence, e.Sequence()),
}
if e.EventType == instance.SetupStartedEventType {
columns = append(columns, handler.NewCol(InstanceColumnSetUpStarted, e.Step))
} else {
columns = append(columns, handler.NewCol(InstanceColumnSetUpDone, e.Step))
}
return crdb.NewUpsertStatement(
e,
columns,
), nil
}

View File

@ -3,7 +3,6 @@ package projection
import (
"testing"
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/errors"
"github.com/zitadel/zitadel/internal/eventstore"
"github.com/zitadel/zitadel/internal/eventstore/handler"
@ -141,66 +140,6 @@ func TestInstanceProjection_reduces(t *testing.T) {
},
},
},
{
name: "reduceSetupStarted",
args: args{
event: getEvent(testEvent(
repository.EventType(instance.SetupStartedEventType),
instance.AggregateType,
[]byte(`{"Step": 1}`),
), instance.SetupStepMapper),
},
reduce: (&InstanceProjection{}).reduceSetupEvent,
want: wantReduce{
projection: InstanceProjectionTable,
aggregateType: eventstore.AggregateType("instance"),
sequence: 15,
previousSequence: 10,
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "UPSERT INTO projections.instances (id, change_date, sequence, setup_started) VALUES ($1, $2, $3, $4)",
expectedArgs: []interface{}{
"instance-id",
anyArg{},
uint64(15),
domain.Step1,
},
},
},
},
},
},
{
name: "reduceSetupDone",
args: args{
event: getEvent(testEvent(
repository.EventType(instance.SetupDoneEventType),
instance.AggregateType,
[]byte(`{"Step": 1}`),
), instance.SetupStepMapper),
},
reduce: (&InstanceProjection{}).reduceSetupEvent,
want: wantReduce{
projection: InstanceProjectionTable,
aggregateType: eventstore.AggregateType("instance"),
sequence: 15,
previousSequence: 10,
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "UPSERT INTO projections.instances (id, change_date, sequence, setup_done) VALUES ($1, $2, $3, $4)",
expectedArgs: []interface{}{
"instance-id",
anyArg{},
uint64(15),
domain.Step1,
},
},
},
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {

View File

@ -1,103 +0,0 @@
package instance
import (
"context"
"encoding/json"
"strconv"
"github.com/zitadel/zitadel/internal/eventstore"
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/errors"
"github.com/zitadel/zitadel/internal/eventstore/repository"
)
const (
UniqueStepStarted = "stepstarted"
UniqueStepDone = "stepdone"
SetupDoneEventType eventstore.EventType = "iam.setup.done"
SetupStartedEventType eventstore.EventType = "iam.setup.started"
)
type SetupStepEvent struct {
eventstore.BaseEvent `json:"-"`
Step domain.Step `json:"Step"`
Done bool `json:"-"`
}
func NewAddSetupStepStartedUniqueConstraint(step domain.Step) *eventstore.EventUniqueConstraint {
return eventstore.NewAddEventUniqueConstraint(
UniqueStepStarted,
strconv.Itoa(int(step)),
"Errors.Step.Started.AlreadyExists")
}
func NewAddSetupStepDoneUniqueConstraint(step domain.Step) *eventstore.EventUniqueConstraint {
return eventstore.NewAddEventUniqueConstraint(
UniqueStepDone,
strconv.Itoa(int(step)),
"Errors.Step.Done.AlreadyExists")
}
func (e *SetupStepEvent) Data() interface{} {
return e
}
func (e *SetupStepEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
if e.Done {
return []*eventstore.EventUniqueConstraint{NewAddSetupStepDoneUniqueConstraint(e.Step)}
} else {
return []*eventstore.EventUniqueConstraint{NewAddSetupStepStartedUniqueConstraint(e.Step)}
}
}
func SetupStepMapper(event *repository.Event) (eventstore.Event, error) {
step := &SetupStepEvent{
BaseEvent: *eventstore.BaseEventFromRepo(event),
Done: eventstore.EventType(event.Type) == SetupDoneEventType,
Step: domain.Step1,
}
if len(event.Data) == 0 {
return step, nil
}
err := json.Unmarshal(event.Data, step)
if err != nil {
return nil, errors.ThrowInternal(err, "IAM-O6rVg", "unable to unmarshal step")
}
return step, nil
}
func NewSetupStepDoneEvent(
ctx context.Context,
aggregate *eventstore.Aggregate,
step domain.Step,
) *SetupStepEvent {
return &SetupStepEvent{
BaseEvent: *eventstore.NewBaseEventForPush(
ctx,
aggregate,
SetupDoneEventType,
),
Step: step,
Done: true,
}
}
func NewSetupStepStartedEvent(
ctx context.Context,
aggregate *eventstore.Aggregate,
step domain.Step,
) *SetupStepEvent {
return &SetupStepEvent{
BaseEvent: *eventstore.NewBaseEventForPush(
ctx,
aggregate,
SetupStartedEventType,
),
Step: step,
}
}

View File

@ -5,9 +5,7 @@ import (
)
func RegisterEventMappers(es *eventstore.Eventstore) {
es.RegisterFilterEventMapper(SetupStartedEventType, SetupStepMapper).
RegisterFilterEventMapper(SetupDoneEventType, SetupStepMapper).
RegisterFilterEventMapper(GlobalOrgSetEventType, GlobalOrgSetMapper).
es.RegisterFilterEventMapper(GlobalOrgSetEventType, GlobalOrgSetMapper).
RegisterFilterEventMapper(ProjectSetEventType, ProjectSetMapper).
RegisterFilterEventMapper(ConsoleSetEventType, ConsoleSetMapper).
RegisterFilterEventMapper(DefaultLanguageSetEventType, DefaultLanguageSetMapper).