diff --git a/cmd/admin/initialise/init.go b/cmd/admin/initialise/init.go index 1f33f1ac9b..6bd461a236 100644 --- a/cmd/admin/initialise/init.go +++ b/cmd/admin/initialise/init.go @@ -1,9 +1,11 @@ package initialise import ( + "database/sql" _ "embed" "github.com/caos/logging" + "github.com/caos/zitadel/internal/database" "github.com/spf13/cobra" "github.com/spf13/viper" @@ -44,7 +46,7 @@ The user provided by flags needs priviledge to if err := viper.Unmarshal(config); err != nil { return err } - return initialise(config) + return initialise(config, verifyUser, verifyDB, verifyGrant) }, } @@ -54,15 +56,38 @@ The user provided by flags needs priviledge to cmd.PersistentFlags().StringVar(&user, userFlag, "", "(required) the user to check if the database, user and grants exists and create if not") cmd.MarkPersistentFlagRequired(userFlag) + cmd.AddCommand(newZitadel(), newDatabase(), newUser(), newGrant()) + return cmd } -func initialise(config *Config) error { +func adminConfig(config database.Config) database.Config { + adminConfig := config + adminConfig.User = user + adminConfig.Password = password + adminConfig.SSL.Cert = sslCert + adminConfig.SSL.Key = sslKey + + return adminConfig +} + +func initialise(config *Config, steps ...func(*sql.DB, database.Config) error) error { logging.Info("initialization started") - if err := prepareDB(config.Database, user, password, sslCert, sslKey); err != nil { + db, err := database.Connect(adminConfig(config.Database)) + if err != nil { return err } - return prepareZitadel(config.Database) + for _, step := range steps { + if err = step(db, config.Database); err != nil { + return err + } + } + + if err = db.Close(); err != nil { + return err + } + + return verifyZitadel(config.Database) } diff --git a/cmd/admin/initialise/prepare_database.go b/cmd/admin/initialise/prepare_database.go deleted file mode 100644 index a8f035c2c1..0000000000 --- a/cmd/admin/initialise/prepare_database.go +++ /dev/null @@ -1,93 +0,0 @@ -package initialise - -import ( - "database/sql" - - "github.com/caos/logging" - "github.com/caos/zitadel/internal/database" -) - -func prepareDB(config database.Config, user, password, sslCert, sslKey string) error { - adminConfig := config - adminConfig.User = user - adminConfig.Password = password - adminConfig.SSL.Cert = sslCert - adminConfig.SSL.Key = sslKey - - db, err := database.Connect(adminConfig) - if err != nil { - return err - } - - logging.Info("verify user") - if err = verifyUser(db, config); err != nil { - return err - } - logging.Info("verify database") - if err = verifyDB(db, config); err != nil { - return err - } - logging.Info("verify grant") - if err = verifyGrant(db, config); err != nil { - return err - } - - return db.Close() -} - -func verifyUser(db *sql.DB, config database.Config) error { - exists, err := existsUser(db, config) - if exists || err != nil { - return err - } - return createUser(db, config) -} - -func existsUser(db *sql.DB, config database.Config) (exists bool, err error) { - row := db.QueryRow("SELECT EXISTS(SELECT username FROM [show roles] WHERE username = $1)", config.User) - err = row.Scan(&exists) - return exists, err -} - -func createUser(db *sql.DB, config database.Config) error { - _, err := db.Exec("CREATE USER $1 WITH PASSWORD $2", config.User, &sql.NullString{String: config.Password, Valid: config.Password != ""}) - return err -} - -func verifyDB(db *sql.DB, config database.Config) error { - exists, err := existsDatabase(db, config) - if exists || err != nil { - return err - } - return createDatabase(db, config) -} - -func existsDatabase(db *sql.DB, config database.Config) (exists bool, err error) { - row := db.QueryRow("SELECT EXISTS(SELECT database_name FROM [show databases] WHERE database_name = $1)", config.Database) - err = row.Scan(&exists) - return exists, err -} - -func createDatabase(db *sql.DB, config database.Config) error { - _, err := db.Exec("CREATE DATABASE " + config.Database) - return err -} - -func verifyGrant(db *sql.DB, config database.Config) error { - exists, err := hasGrant(db, config) - if exists || err != nil { - return err - } - return grant(db, config) -} - -func hasGrant(db *sql.DB, config database.Config) (has bool, err error) { - row := db.QueryRow("SELECT EXISTS(SELECT * FROM [SHOW GRANTS ON DATABASE "+config.Database+"] where grantee = $1 AND privilege_type = 'ALL')", config.User) - err = row.Scan(&has) - return has, err -} - -func grant(db *sql.DB, config database.Config) error { - _, err := db.Exec("GRANT ALL ON DATABASE " + config.Database + " TO " + config.User) - return err -} diff --git a/cmd/admin/initialise/verify_database.go b/cmd/admin/initialise/verify_database.go new file mode 100644 index 0000000000..eeb54f5888 --- /dev/null +++ b/cmd/admin/initialise/verify_database.go @@ -0,0 +1,54 @@ +package initialise + +import ( + "database/sql" + + "github.com/caos/logging" + "github.com/caos/zitadel/internal/database" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +func newDatabase() *cobra.Command { + return &cobra.Command{ + Use: "database", + Short: "initialize only the database", + Long: `Sets up the ZITADEL database. + +Prereqesits: +- cockroachdb + +The user provided by flags needs priviledge to +- create the database if it does not exist +- see other users and create a new one if the user does not exist +- grant all rights of the ZITADEL database to the user created if not yet set +`, + RunE: func(cmd *cobra.Command, args []string) error { + config := new(Config) + if err := viper.Unmarshal(config); err != nil { + return err + } + return initialise(config, verifyDB) + }, + } +} + +func verifyDB(db *sql.DB, config database.Config) error { + logging.Info("verify database") + exists, err := existsDatabase(db, config) + if exists || err != nil { + return err + } + return createDatabase(db, config) +} + +func existsDatabase(db *sql.DB, config database.Config) (exists bool, err error) { + row := db.QueryRow("SELECT EXISTS(SELECT database_name FROM [show databases] WHERE database_name = $1)", config.Database) + err = row.Scan(&exists) + return exists, err +} + +func createDatabase(db *sql.DB, config database.Config) error { + _, err := db.Exec("CREATE DATABASE " + config.Database) + return err +} diff --git a/cmd/admin/initialise/verify_grant.go b/cmd/admin/initialise/verify_grant.go new file mode 100644 index 0000000000..bf62e4ea7e --- /dev/null +++ b/cmd/admin/initialise/verify_grant.go @@ -0,0 +1,49 @@ +package initialise + +import ( + "database/sql" + + "github.com/caos/logging" + "github.com/caos/zitadel/internal/database" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +func newGrant() *cobra.Command { + return &cobra.Command{ + Use: "grant", + Short: "set ALL grant to user", + Long: `Sets ALL grant to the database user. + +Prereqesits: +- cockroachdb +`, + RunE: func(cmd *cobra.Command, args []string) error { + config := new(Config) + if err := viper.Unmarshal(config); err != nil { + return err + } + return initialise(config, verifyGrant) + }, + } +} + +func verifyGrant(db *sql.DB, config database.Config) error { + logging.Info("verify grant") + exists, err := hasGrant(db, config) + if exists || err != nil { + return err + } + return grant(db, config) +} + +func hasGrant(db *sql.DB, config database.Config) (has bool, err error) { + row := db.QueryRow("SELECT EXISTS(SELECT * FROM [SHOW GRANTS ON DATABASE "+config.Database+"] where grantee = $1 AND privilege_type = 'ALL')", config.User) + err = row.Scan(&has) + return has, err +} + +func grant(db *sql.DB, config database.Config) error { + _, err := db.Exec("GRANT ALL ON DATABASE " + config.Database + " TO " + config.User) + return err +} diff --git a/cmd/admin/initialise/verify_user.go b/cmd/admin/initialise/verify_user.go new file mode 100644 index 0000000000..51d980b9a9 --- /dev/null +++ b/cmd/admin/initialise/verify_user.go @@ -0,0 +1,54 @@ +package initialise + +import ( + "database/sql" + + "github.com/caos/logging" + "github.com/caos/zitadel/internal/database" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +func newUser() *cobra.Command { + return &cobra.Command{ + Use: "user", + Short: "initialize only the database user", + Long: `Sets up the ZITADEL database user. + +Prereqesits: +- cockroachdb + +The user provided by flags needs priviledge to +- create the database if it does not exist +- see other users and create a new one if the user does not exist +- grant all rights of the ZITADEL database to the user created if not yet set +`, + RunE: func(cmd *cobra.Command, args []string) error { + config := new(Config) + if err := viper.Unmarshal(config); err != nil { + return err + } + return initialise(config, verifyUser) + }, + } +} + +func verifyUser(db *sql.DB, config database.Config) error { + logging.Info("verify user") + exists, err := existsUser(db, config) + if exists || err != nil { + return err + } + return createUser(db, config) +} + +func existsUser(db *sql.DB, config database.Config) (exists bool, err error) { + row := db.QueryRow("SELECT EXISTS(SELECT username FROM [show roles] WHERE username = $1)", config.User) + err = row.Scan(&exists) + return exists, err +} + +func createUser(db *sql.DB, config database.Config) error { + _, err := db.Exec("CREATE USER $1 WITH PASSWORD $2", config.User, &sql.NullString{String: config.Password, Valid: config.Password != ""}) + return err +} diff --git a/cmd/admin/initialise/prepare_zitadel.go b/cmd/admin/initialise/verify_zitadel.go similarity index 84% rename from cmd/admin/initialise/prepare_zitadel.go rename to cmd/admin/initialise/verify_zitadel.go index 42d6999657..6d735d7ee8 100644 --- a/cmd/admin/initialise/prepare_zitadel.go +++ b/cmd/admin/initialise/verify_zitadel.go @@ -5,6 +5,8 @@ import ( "github.com/caos/logging" "github.com/caos/zitadel/internal/database" + "github.com/spf13/cobra" + "github.com/spf13/viper" ) const ( @@ -13,23 +15,39 @@ const ( eventsTable = "events" ) -func prepareZitadel(config database.Config) error { +func newZitadel() *cobra.Command { + return &cobra.Command{ + Use: "zitadel", + Short: "initialize ZITADEL internas", + Long: `initialize ZITADEL internas. + +Prereqesits: +- cockroachdb with user and database +`, + RunE: func(cmd *cobra.Command, args []string) error { + config := new(Config) + if err := viper.Unmarshal(config); err != nil { + return err + } + return initialise(config, verifyUser) + }, + } +} + +func verifyZitadel(config database.Config) error { db, err := database.Connect(config) if err != nil { return err } - logging.Info("verify projections schema") if err := verifySchema(db, config, projectionsSchema); err != nil { return err } - logging.Info("verify eventstore schema") if err := verifySchema(db, config, eventstoreSchema); err != nil { return err } - logging.Info("verify events table") if err := verifyEvents(db, config); err != nil { return err } @@ -38,6 +56,7 @@ func prepareZitadel(config database.Config) error { } func verifySchema(db *sql.DB, config database.Config, schema string) error { + logging.WithFields("schema", schema).Info("verify schema") exists, err := existsSchema(db, config, schema) if exists || err != nil { return err @@ -57,6 +76,8 @@ func createSchema(db *sql.DB, config database.Config, schema string) error { } func verifyEvents(db *sql.DB, config database.Config) error { + logging.Info("verify events table") + exists, err := existsEvents(db, config) if exists || err != nil { return err