diff --git a/cmd/admin/initialise/config.go b/cmd/admin/initialise/config.go new file mode 100644 index 0000000000..cb44ef60b6 --- /dev/null +++ b/cmd/admin/initialise/config.go @@ -0,0 +1,7 @@ +package initialise + +import "github.com/caos/zitadel/internal/database" + +type Config struct { + Database database.Config +} diff --git a/cmd/admin/initialise/init.go b/cmd/admin/initialise/init.go index 983c8282e9..45b9f3a0e4 100644 --- a/cmd/admin/initialise/init.go +++ b/cmd/admin/initialise/init.go @@ -2,21 +2,53 @@ package initialise import ( _ "embed" + "fmt" "github.com/caos/logging" "github.com/spf13/cobra" + "github.com/spf13/viper" + + //sql import + _ "github.com/lib/pq" +) + +var ( + conn string ) func New() *cobra.Command { - return &cobra.Command{ + cmd := &cobra.Command{ Use: "init", Short: "initialize ZITADEL instance", Long: `init sets up the minimum requirements to start ZITADEL. Prereqesits: - cockroachdb`, RunE: func(cmd *cobra.Command, args []string) error { - logging.New().Info("hello world") - return nil + config := new(Config) + if err := viper.Unmarshal(config); err != nil { + return err + } + return initialise(config) }, } + + // cmd.PersistentFlags().StringArrayVar(&configFiles, "config", nil, "path to config file to overwrite system defaults") + //TODO(hust): simplify to multiple flags + cmd.PersistentFlags().StringVar(&conn, "connection", "", "connection string to connect with a user which is allowed to create the database and user") + + return cmd +} + +func initialise(config *Config) error { + logging.Info("initialization started") + + if conn == "" { + return fmt.Errorf("connection not defined") + } + + if err := prepareDB(config.Database); err != nil { + return err + } + + return prepareZitadel(config.Database) } diff --git a/cmd/admin/initialise/prepare_database.go b/cmd/admin/initialise/prepare_database.go new file mode 100644 index 0000000000..326083efa8 --- /dev/null +++ b/cmd/admin/initialise/prepare_database.go @@ -0,0 +1,87 @@ +package initialise + +import ( + "database/sql" + + "github.com/caos/logging" + "github.com/caos/zitadel/internal/database" +) + +func prepareDB(config database.Config) error { + db, err := sql.Open("postgres", conn) + 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/prepare_zitadel.go b/cmd/admin/initialise/prepare_zitadel.go new file mode 100644 index 0000000000..42d6999657 --- /dev/null +++ b/cmd/admin/initialise/prepare_zitadel.go @@ -0,0 +1,114 @@ +package initialise + +import ( + "database/sql" + + "github.com/caos/logging" + "github.com/caos/zitadel/internal/database" +) + +const ( + eventstoreSchema = "eventstore" + projectionsSchema = "projections" + eventsTable = "events" +) + +func prepareZitadel(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 + } + + return db.Close() +} + +func verifySchema(db *sql.DB, config database.Config, schema string) error { + exists, err := existsSchema(db, config, schema) + if exists || err != nil { + return err + } + return createSchema(db, config, schema) +} + +func existsSchema(db *sql.DB, config database.Config, schema string) (exists bool, err error) { + row := db.QueryRow("SELECT EXISTS(SELECT schema_name FROM [SHOW SCHEMAS] WHERE schema_name = $1)", schema) + err = row.Scan(&exists) + return exists, err +} + +func createSchema(db *sql.DB, config database.Config, schema string) error { + _, err := db.Exec("CREATE SCHEMA " + schema) + return err +} + +func verifyEvents(db *sql.DB, config database.Config) error { + exists, err := existsEvents(db, config) + if exists || err != nil { + return err + } + return createEvents(db, config) +} + +func existsEvents(db *sql.DB, config database.Config) (exists bool, err error) { + row := db.QueryRow("SELECT EXISTS(SELECT table_name FROM [SHOW TABLES] WHERE table_name = $1)", eventsTable) + err = row.Scan(&exists) + return exists, err +} + +func createEvents(db *sql.DB, config database.Config) error { + tx, err := db.Begin() + if err != nil { + return err + } + if _, err = tx.Exec("SET experimental_enable_hash_sharded_indexes = on"); err != nil { + tx.Rollback() + return err + } + + stmt := `CREATE TABLE eventstore.events ( + id UUID DEFAULT gen_random_uuid() + , event_type TEXT NOT NULL + , aggregate_type TEXT NOT NULL + , aggregate_id TEXT NOT NULL + , aggregate_version TEXT NOT NULL + , event_sequence BIGINT NOT NULL + , previous_aggregate_sequence BIGINT + , previous_aggregate_type_sequence INT8 + , creation_date TIMESTAMPTZ NOT NULL DEFAULT now() + , event_data JSONB + , editor_user TEXT NOT NULL + , editor_service TEXT NOT NULL + , resource_owner TEXT NOT NULL + + , PRIMARY KEY (event_sequence DESC) USING HASH WITH BUCKET_COUNT = 10 + , INDEX agg_type_agg_id (aggregate_type, aggregate_id) + , INDEX agg_type (aggregate_type) + , INDEX agg_type_seq (aggregate_type, event_sequence DESC) + STORING (id, event_type, aggregate_id, aggregate_version, previous_aggregate_sequence, creation_date, event_data, editor_user, editor_service, resource_owner, previous_aggregate_type_sequence) + , INDEX changes_idx (aggregate_type, aggregate_id, creation_date) USING HASH WITH BUCKET_COUNT = 10 + , INDEX max_sequence (aggregate_type, aggregate_id, event_sequence DESC) + , CONSTRAINT previous_sequence_unique UNIQUE (previous_aggregate_sequence DESC) + , CONSTRAINT prev_agg_type_seq_unique UNIQUE(previous_aggregate_type_sequence) +)` + if _, err = tx.Exec(stmt); err != nil { + tx.Rollback() + return err + } + + return tx.Commit() +} diff --git a/cmd/admin/setup/setup.go b/cmd/admin/setup/setup.go index 6c43aff6fb..c15815e637 100644 --- a/cmd/admin/setup/setup.go +++ b/cmd/admin/setup/setup.go @@ -15,7 +15,7 @@ func New() *cobra.Command { Requirements: - cockroachdb`, RunE: func(cmd *cobra.Command, args []string) error { - logging.New().Info("hello world") + logging.Info("hello world") return nil }, } diff --git a/cmd/admin/start/start.go b/cmd/admin/start/start.go index 06d8bc2239..a0bf8ba286 100644 --- a/cmd/admin/start/start.go +++ b/cmd/admin/start/start.go @@ -15,7 +15,7 @@ func New() *cobra.Command { Requirements: - cockroachdb`, RunE: func(cmd *cobra.Command, args []string) error { - logging.New().Info("hello world") + logging.Info("hello world") logging.WithFields("field", 1).Info("hello world") return nil }, diff --git a/cmd/defaults.yaml b/cmd/defaults.yaml index f68c480906..b62e31457e 100644 --- a/cmd/defaults.yaml +++ b/cmd/defaults.yaml @@ -1,4 +1,20 @@ Log: Level: debug Formatter: - Format: text \ No newline at end of file + Format: text + +database: + host: localhost + port: 26257 + user: zitadel + database: zitadel + password: + maxOpenConns: 3 + ssl: + mode: disable + rootCert: + cert: + key: + options: + # MaxConnLifetime: 30m + # MaxConnIdleTime: 30m diff --git a/go.mod b/go.mod index 9b72d27fec..53f86d1fe0 100644 --- a/go.mod +++ b/go.mod @@ -17,7 +17,7 @@ require ( github.com/aws/aws-sdk-go-v2/credentials v1.6.4 github.com/aws/aws-sdk-go-v2/service/s3 v1.21.0 github.com/boombuler/barcode v1.0.1 - github.com/caos/logging v0.1.0 + github.com/caos/logging v0.2.1 github.com/caos/oidc v1.0.1 github.com/caos/orbos v1.5.14-0.20211102124704-34db02bceed2 github.com/cockroachdb/cockroach-go/v2 v2.2.4 @@ -41,7 +41,6 @@ require ( github.com/kevinburke/twilio-go v0.0.0-20210327194925-1623146bcf73 github.com/lib/pq v1.10.4 github.com/lucasb-eyer/go-colorful v1.2.0 - github.com/manifoldco/promptui v0.9.0 github.com/minio/minio-go/v7 v7.0.20 github.com/muesli/gamut v0.2.0 github.com/nicksnyder/go-i18n/v2 v2.1.2 @@ -49,7 +48,6 @@ require ( github.com/pquerna/otp v1.3.0 github.com/rakyll/statik v0.1.7 github.com/rs/cors v1.8.0 - github.com/sirupsen/logrus v1.8.1 github.com/sony/sonyflake v1.0.0 github.com/spf13/cobra v1.3.0 github.com/spf13/viper v1.10.1 @@ -108,10 +106,7 @@ require ( github.com/cenkalti/backoff/v4 v4.1.1 // indirect github.com/census-instrumentation/opencensus-proto v0.3.0 // indirect github.com/cespare/xxhash/v2 v2.1.2 // indirect - github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e // indirect github.com/cloudflare/cfssl v0.0.0-20190726000631-633726f6bcb7 // indirect - github.com/cloudflare/cloudflare-go v0.23.0 // indirect - github.com/cloudscale-ch/cloudscale-go-sdk v1.7.1 // indirect github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4 // indirect github.com/cncf/xds/go v0.0.0-20211130200136-a8f946100490 // indirect github.com/davecgh/go-spew v1.1.1 // indirect @@ -131,7 +126,7 @@ require ( github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect github.com/gobuffalo/flect v0.2.3 // indirect github.com/gofrs/flock v0.8.1 // indirect - github.com/gofrs/uuid v3.2.0+incompatible // indirect + github.com/gofrs/uuid v4.0.0+incompatible // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang-jwt/jwt/v4 v4.1.0 // indirect github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect @@ -188,6 +183,7 @@ require ( github.com/rs/xid v1.2.1 // indirect github.com/satori/go.uuid v1.2.0 // indirect github.com/sergi/go-diff v1.1.0 // indirect + github.com/sirupsen/logrus v1.8.1 // indirect github.com/spf13/afero v1.8.1 // indirect github.com/spf13/cast v1.4.1 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect @@ -205,14 +201,14 @@ require ( golang.org/x/image v0.0.0-20200927104501-e162460cd6b5 // indirect golang.org/x/mod v0.5.1 // indirect golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 // indirect - golang.org/x/sys v0.0.0-20220207234003-57398862261d // indirect + golang.org/x/sys v0.0.0-20220209214540-3681064d5158 // indirect golang.org/x/term v0.0.0-20210503060354-a79de5458b56 // indirect golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect google.golang.org/appengine v1.6.7 // indirect gopkg.in/inf.v0 v0.9.1 // indirect - gopkg.in/ini.v1 v1.66.3 // indirect + gopkg.in/ini.v1 v1.66.4 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect k8s.io/component-base v0.22.2 // indirect diff --git a/go.sum b/go.sum index 4ab71d4e18..81b3aa644b 100644 --- a/go.sum +++ b/go.sum @@ -179,10 +179,9 @@ github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnweb github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/boombuler/barcode v1.0.1 h1:NDBbPmhS+EqABEs5Kg3n/5ZNjy73Pz7SIV+KCeqyXcs= github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= -github.com/caos/logging v0.0.2 h1:ebg5C/HN0ludYR+WkvnFjwSExF4wvyiWPyWGcKMYsoo= github.com/caos/logging v0.0.2/go.mod h1:9LKiDE2ChuGv6CHYif/kiugrfEXu9AwDiFWSreX7Wp0= -github.com/caos/logging v0.1.0 h1:xJ0BsCWvcRJKljIKbVa9n0o2FinWaO7wO12EUvnUCT8= -github.com/caos/logging v0.1.0/go.mod h1:B8QNS0WDmR2Keac52Fw+XN4ZJkzLDGrcRIPB2Ux4uRo= +github.com/caos/logging v0.2.1 h1:412Z2ytE+YDwVg6JhwgpHo2TjDhb8kbLOFEWrJ7t3i4= +github.com/caos/logging v0.2.1/go.mod h1:B8QNS0WDmR2Keac52Fw+XN4ZJkzLDGrcRIPB2Ux4uRo= github.com/caos/oidc v1.0.0/go.mod h1:4l0PPwdc6BbrdCFhNrRTUddsG292uHGa7gE2DSEIqoU= github.com/caos/oidc v1.0.1 h1:8UHAPynCObwaqortppDtJFktjqLDLYSLidkNy0Num4o= github.com/caos/oidc v1.0.1/go.mod h1:4l0PPwdc6BbrdCFhNrRTUddsG292uHGa7gE2DSEIqoU= @@ -203,20 +202,15 @@ github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5/go.mod h1:/iP1qXHoty45bqomnu2LM+VVyAEdWN+vtSHGlQgyxbw= -github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e h1:fY5BOSpyZCqRo5OhCuC+XN+r/bBCmeuuJtjz+bCNIf8= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 h1:q763qf9huN11kDQavWsoZXJNW3xEE4JJyHa5Q25/sd8= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudflare/cfssl v0.0.0-20190726000631-633726f6bcb7 h1:Puu1hUwfps3+1CUzYdAZXijuvLuRMirgiXdf3zsM2Ig= github.com/cloudflare/cfssl v0.0.0-20190726000631-633726f6bcb7/go.mod h1:yMWuSON2oQp+43nFtAV/uvKQIFpSPerB57DCt9t8sSA= -github.com/cloudflare/cloudflare-go v0.23.0 h1:ePPZC8wLgtwz5itvgnDFFPPEku0G1a2tVKl5D69k3ac= github.com/cloudflare/cloudflare-go v0.23.0/go.mod h1:sPWL/lIC6biLEdyGZwBQ1rGQKF1FhM7N60fuNiFdYTI= -github.com/cloudscale-ch/cloudscale-go-sdk v1.7.1 h1:DC+0N1zX1Bb1RvBp3tHHYy1mQ3pGyHUP+BGxRUs59YQ= github.com/cloudscale-ch/cloudscale-go-sdk v1.7.1/go.mod h1:FhOTOCgKAVvRRMQc1mC0D7xK/3zYnmcZBWFXNkacvMc= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= @@ -396,8 +390,9 @@ github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/E github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= -github.com/gofrs/uuid v3.2.0+incompatible h1:y12jRkkFxsd7GpqdSZ+/KCs/fJbqpEXSGd4+jfEaewE= github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= +github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= @@ -751,8 +746,6 @@ github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/manifoldco/promptui v0.9.0 h1:3V4HzJk1TtXW1MTZMP7mdlwbBpIinw3HztaIlYthEiA= -github.com/manifoldco/promptui v0.9.0/go.mod h1:ka04sppxSGFAtxX0qhlYQjISsg9mR4GWtQEhdbn6Pgg= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= @@ -1310,7 +1303,6 @@ golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1398,8 +1390,9 @@ golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220207234003-57398862261d h1:Bm7BNOQt2Qv7ZqysjeLjgCBanX+88Z/OtdvsrEv1Djc= golang.org/x/sys v0.0.0-20220207234003-57398862261d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220209214540-3681064d5158 h1:rm+CHSpPEEW2IsXUib1ThaHIjuBVZjxNgSKmBLFfD4c= +golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -1686,8 +1679,8 @@ gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.57.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/ini.v1 v1.66.3 h1:jRskFVxYaMGAMUbN0UZ7niA9gzL9B49DOqE78vg0k3w= -gopkg.in/ini.v1 v1.66.3/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.66.4 h1:SsAcf+mM7mRZo2nJNGt8mZCjG8ZRaNGMURJw7BsIST4= +gopkg.in/ini.v1 v1.66.4/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= gopkg.in/raintank/schema.v1 v1.0.0/go.mod h1:mx46t/rI5UA/b+WtF5ThX+qFJ7P7MOmE3ZMR12Wfr8c= diff --git a/internal/config/types/sql.go b/internal/config/types/sql.go index 59b1075d3b..7cbc6ad41c 100644 --- a/internal/config/types/sql.go +++ b/internal/config/types/sql.go @@ -5,7 +5,6 @@ import ( "strings" "github.com/caos/logging" - "github.com/caos/zitadel/internal/errors" ) diff --git a/internal/database/config.go b/internal/database/config.go new file mode 100644 index 0000000000..0c22f9d32a --- /dev/null +++ b/internal/database/config.go @@ -0,0 +1,82 @@ +package database + +import ( + "strings" + + "github.com/caos/logging" + "github.com/caos/zitadel/internal/config/types" +) + +const ( + sslDisabledMode = "disable" +) + +type Config struct { + Host string + Port string + User string + Password string + Database string + SSL *ssl + MaxOpenConns uint32 + MaxConnLifetime types.Duration + MaxConnIdleTime types.Duration + + //Additional options to be appended as options= + //The value will be taken as is. Multiple options are space separated. + Options string +} + +type ssl struct { + // type of connection security + Mode string + // RootCert Path to the CA certificate + RootCert string + // Cert Path to the client certificate + Cert string + // Key Path to the client private key + Key string +} + +func (s *Config) checkSSL() { + if s.SSL == nil || s.SSL.Mode == sslDisabledMode || s.SSL.Mode == "" { + s.SSL = &ssl{Mode: sslDisabledMode} + return + } + if s.SSL.RootCert == "" { + logging.WithFields( + "cert set", s.SSL.Cert != "", + "key set", s.SSL.Key != "", + "rootCert set", s.SSL.RootCert != "", + ).Fatal("at least ssl root cert has to be set") + } +} + +func (c Config) String() string { + c.checkSSL() + fields := []string{ + "host=" + c.Host, + "port=" + c.Port, + "user=" + c.User, + "dbname=" + c.Database, + "application_name=zitadel", + "sslmode=" + c.SSL.Mode, + } + if c.Options != "" { + fields = append(fields, "options="+c.Options) + } + if c.Password != "" { + fields = append(fields, "password="+c.Password) + } + if c.SSL.Mode != sslDisabledMode { + fields = append(fields, "sslrootcert="+c.SSL.RootCert) + if c.SSL.Cert != "" { + fields = append(fields, "sslcert="+c.SSL.Cert) + } + if c.SSL.Key != "" { + fields = append(fields, "sslkey="+c.SSL.Key) + } + } + + return strings.Join(fields, " ") +} diff --git a/internal/database/config/connect.go b/internal/database/config/connect.go deleted file mode 100644 index 9f58dbfce3..0000000000 --- a/internal/database/config/connect.go +++ /dev/null @@ -1,17 +0,0 @@ -package config - -import ( - "database/sql" - - "github.com/caos/zitadel/internal/errors" -) - -var client *sql.DB - -type Config struct{} - -func Connect() (*sql.DB, error) { - //TODO: viper read into Config - - return nil, errors.ThrowUnimplemented(nil, "CONFI-8bvVL", "connect is unimplemented") -} diff --git a/internal/database/database.go b/internal/database/database.go new file mode 100644 index 0000000000..5f3d321f3b --- /dev/null +++ b/internal/database/database.go @@ -0,0 +1,18 @@ +package database + +import ( + "database/sql" +) + +func Connect(config Config) (*sql.DB, error) { + client, err := sql.Open("postgres", config.String()) + if err != nil { + return nil, err + } + + client.SetMaxOpenConns(int(config.MaxOpenConns)) + client.SetConnMaxLifetime(config.MaxConnLifetime.Duration) + client.SetConnMaxIdleTime(config.MaxConnIdleTime.Duration) + + return client, nil +}