This commit is contained in:
adlerhurst
2025-02-23 17:16:23 +01:00
parent 304e5823b2
commit 17c3284215
18 changed files with 624 additions and 408 deletions

View File

@@ -1,9 +1,9 @@
package configure
import (
"github.com/Masterminds/semver/v3"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/zitadel/zitadel/backend/cmd/config"
)
var (
@@ -70,24 +70,21 @@ func (s sub) Fields() []Updater {
return []Updater{
Field[string]{
FieldName: "f1",
Value: &s.F1,
Default: "",
Value: "",
Description: "field 1",
Version: config.V3,
Version: semver.MustParse("3"),
},
Field[int]{
FieldName: "f2",
Value: &s.F2,
Default: 0,
Value: 0,
Description: "field 2",
Version: config.V3,
Version: semver.MustParse("3"),
},
Field[*bool]{
FieldName: "f3",
Value: &s.F3,
Default: nil,
Value: nil,
Description: "field 3",
Version: config.V3,
Version: semver.MustParse("3"),
},
}
}
@@ -101,10 +98,9 @@ func (t test) Fields() []Updater {
return []Updater{
Field[string]{
FieldName: "f1",
Value: &t.F1,
Default: "",
Value: "",
Description: "field 1",
Version: config.V3,
Version: semver.MustParse("3"),
},
Struct{
FieldName: "sub",

View File

@@ -1,246 +0,0 @@
package configure
import (
"encoding/json"
"fmt"
"reflect"
"github.com/manifoldco/promptui"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/zitadel/zitadel/backend/cmd/config"
)
func Update(name, description string, fields []Updater) func(cmd *cobra.Command, args []string) {
return func(cmd *cobra.Command, args []string) {
u := Struct{
FieldName: name,
Description: description,
SubFields: fields,
}
fields := viper.AllSettings()
updateStruct(u, fields, 1)
fmt.Println("Using config file:", viper.ConfigFileUsed(), "fields:", fields)
// viper.MergeConfigMap(fields)
// if err := viper.WriteConfig(); err != nil {
// panic(err)
// }
}
}
func updateStruct(updater StructUpdater, fields map[string]any, depth int) {
for _, field := range updater.Fields() {
// fmt.Printf("field: %s.%s\n %s\n", parent, field.Name(), field.Describe())
setField(field, fields, depth)
}
}
func setField(field Updater, fields map[string]any, depth int) {
if !field.ShouldUpdate(config.V3) {
prompt := promptui.Prompt{
Label: field.Name() + " did not change since last configure, skip?",
IsConfirm: true,
}
if _, err := prompt.Run(); err == nil {
fmt.Println("skip")
return
}
return
}
fmt.Println(field.Name(), field.Describe())
switch f := field.(type) {
case StructUpdater:
if fields[f.Name()] == nil {
fields[f.Name()] = map[string]any{}
}
fmt.Printf("%.*s %s: %s\n", depth*2, "-", f.Name(), f.Describe())
updateStruct(f, fields[f.Name()].(map[string]any), depth+1)
case FieldUpdater:
prompt := promptui.Prompt{
Label: fmt.Sprintf("%s (%s) (%T)", f.Name(), f.Describe(), f.DefaultValue()),
Default: fmt.Sprintf("%v", f.DefaultValue()),
Validate: func(s string) error {
if isConfirm(reflect.TypeOf(f.DefaultValue())) {
return nil
}
return f.Set(s)
},
IsConfirm: isConfirm(reflect.TypeOf(f.DefaultValue())),
}
val, err := prompt.Run()
if err != nil {
panic(err)
}
fields[f.Name()] = f.Set(val)
case OneOfUpdater:
var possibilities []string
for _, subField := range f.Fields() {
possibilities = append(possibilities, subField.Name())
fields[subField.Name()] = subField
}
prompt := promptui.Select{
Label: fmt.Sprintf("Select one of %s: (%s)", f.Name(), f.Describe()),
Items: possibilities,
}
i, value, err := prompt.Run()
if err != nil {
fmt.Println("panic", err)
panic(err)
}
fv := fields[value]
// TODO: fv is result of decoder (postgres.config in this case)
setField(f.Fields()[i], fv.(map[string]any), depth+1)
}
}
func isConfirm(t reflect.Type) bool {
if t.Kind() == reflect.Ptr {
return isConfirm(t.Elem())
}
return t.Kind() == reflect.Bool
}
type Updater interface {
Name() string
Describe() string
ShouldUpdate(version config.Version) bool
}
type FieldUpdater interface {
Updater
DefaultValue() any
Set(value string) error
_field()
}
type StructUpdater interface {
Updater
Fields() []Updater
_struct()
}
type OneOfUpdater interface {
Updater
Fields() []Updater
_oneOf()
}
var _ FieldUpdater = (*Field[string])(nil)
type Field[T any] struct {
FieldName string
Default T
Value *T
Description string
Version config.Version
}
// DefaultValue implements [FieldUpdater].
func (uf Field[T]) DefaultValue() any {
return uf.Default
}
// Describe implements [FieldUpdater].
func (uf Field[T]) Describe() string {
return uf.Description
}
// Set implements [FieldUpdater].
func (uf Field[T]) Set(value string) error {
var v T
if err := json.Unmarshal([]byte(value), &v); err != nil {
return fmt.Errorf("failed to unmarshal value: %v", err)
}
*uf.Value = v
return nil
}
// Field implements [FieldUpdater].
func (uf Field[T]) Name() string {
return uf.FieldName
}
// ShouldUpdate implements [FieldUpdater].
func (uf Field[T]) ShouldUpdate(version config.Version) bool {
return uf.Version <= version
}
func (f Field[T]) _field() {}
var _ StructUpdater = (*Struct)(nil)
type Struct struct {
FieldName string
Description string
SubFields []Updater
}
// Describe implements [StructUpdater].
func (us Struct) Describe() string {
return us.Description
}
func (us Struct) Name() string {
return us.FieldName
}
func (us Struct) Fields() []Updater {
return us.SubFields
}
func (f Struct) _struct() {}
type OneOf struct {
FieldName string
Description string
SubFields []Updater
}
// Describe implements [OneOfUpdater].
func (o OneOf) Describe() string {
return o.Description
}
// Fields implements [OneOfUpdater].
func (o OneOf) Fields() []Updater {
return o.SubFields
}
// Name implements [FieldUpdater].
func (o OneOf) Name() string {
return o.FieldName
}
func (f OneOf) _oneOf() {}
// ShouldUpdate implements [OneOfUpdater].
func (o OneOf) ShouldUpdate(version config.Version) bool {
for _, field := range o.SubFields {
if !field.ShouldUpdate(version) {
continue
}
return true
}
return false
}
var _ OneOfUpdater = (*OneOf)(nil)
func (us Struct) ShouldUpdate(version config.Version) bool {
for _, field := range us.SubFields {
if !field.ShouldUpdate(version) {
continue
}
return true
}
return false
}
func FieldName(parent, field string) string {
if parent == "" {
return field
}
return parent + "." + field
}

View File

@@ -1,109 +0,0 @@
package configure
import (
"fmt"
"os"
"reflect"
"strings"
"github.com/manifoldco/promptui"
)
func Update2(config any) {
// Print the intro
printIntro()
// Start the interactive CLI
interactiveCLI(reflect.ValueOf(config), 0)
fmt.Println(config)
}
const (
ExitValue = "<Exit>"
BackValue = "⬅ Back"
Prefix = "📁 "
)
var introTemplate = `
+----------------------------------------+
| 🛠 Config Interactive CLI 🛠 |
+----------------------------------------+
| |
| %5s : Dive into nested config |
| %6s : Return to previous menu |
| %6s : Exit application |
| |
| Choose an option to explore! |
| |
+----------------------------------------+
`
func printIntro() {
fmt.Printf(introTemplate, Prefix, BackValue, ExitValue)
}
// interactiveCLI handles the interactive CLI
func interactiveCLI(v reflect.Value, depth int) {
for {
var items []string
// If depth is greater than 0, we are in a nested struct and should add a "Back" option
if depth > 0 {
items = append(items, BackValue)
}
// Add all the field names
items = append(items, getFieldNames(v)...)
// Add an "Exit" option
items = append(items, ExitValue)
prompt := promptui.Select{
Label: "Select Field",
Items: items,
}
_, result, err := prompt.Run()
if err != nil {
fmt.Printf("Prompt failed %v\n", err)
return
}
switch result {
case BackValue:
return
case ExitValue:
// Exit the entire application
os.Exit(0)
default:
fieldName := strings.TrimPrefix(result, Prefix)
selectedField := v.FieldByName(fieldName)
if selectedField.Kind() == reflect.Struct {
interactiveCLI(selectedField, depth+1)
} else {
prompt := promptui.Prompt{
Label: fmt.Sprintf("Field %s (%s)", result, selectedField.Kind()),
Default: fmt.Sprintf("%v", selectedField.Interface()),
}
res, err := prompt.Run()
fmt.Println(res, err)
// fmt.Printf("%s: %v\n", result, selectedField.Interface())
}
}
}
}
// getFieldNames returns all the field names
func getFieldNames(v reflect.Value) []string {
t := v.Type()
var fieldNames []string
for i := 0; i < v.NumField(); i++ {
fieldName := t.Field(i).Name
if v.Field(i).Kind() == reflect.Struct {
fieldName = Prefix + fieldName
}
fieldNames = append(fieldNames, fieldName)
}
return fieldNames
}

View File

@@ -0,0 +1,449 @@
package configure
import (
"encoding/json"
"errors"
"fmt"
"reflect"
"strconv"
"strings"
"github.com/Masterminds/semver/v3"
"github.com/manifoldco/promptui"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/zitadel/zitadel/backend/cmd/info"
)
var lastConfiguredVersion *semver.Version
func Update(name, description string, fields []Updater) func(cmd *cobra.Command, args []string) {
return func(cmd *cobra.Command, args []string) {
configVersion := viper.GetString("configuredVersion")
if configVersion != "" {
lastConfiguredVersion, _ = semver.NewVersion(configVersion)
}
for _, field := range fields {
if err := setField(field, "", 1); err != nil {
panic(err)
}
}
fmt.Println("Using config file:", viper.ConfigFileUsed(), "fields:", fields)
fmt.Println(viper.AllSettings())
viper.Set("configuredVersion", info.Version().String())
// viper.MergeConfigMap(fields)
// if err := viper.WriteConfig(); err != nil {
// panic(err)
// }
if err := viper.WriteConfig(); err != nil {
panic(err)
}
}
}
func setField(field Updater, parentPath string, depth int) error {
if !field.ShouldUpdate(lastConfiguredVersion) {
prompt := promptui.Prompt{
Label: field.Name() + " did not change since last configure, skip?",
IsConfirm: true,
}
if _, err := prompt.Run(); err == nil {
fmt.Println("skip")
return nil
}
}
fieldPath := path(parentPath, field.Name())
switch f := field.(type) {
case StructUpdater:
fmt.Printf("\n%.*s %s: %s\n\n", depth*2, "-", f.Name(), f.Describe())
for _, subField := range f.Fields() {
err := setField(subField, fieldPath, depth+1)
if err != nil {
return err
}
}
case FieldUpdater:
value := viper.Get(fieldPath)
if value == nil {
value = f.ValueOrDefault()
}
prompt := promptui.Prompt{
Label: fmt.Sprintf("%s (%s) (%T)", f.Name(), f.Describe(), f.ValueOrDefault()),
Default: fmt.Sprintf("%v", value),
Validate: func(s string) error {
if isConfirm(reflect.TypeOf(value)) {
return nil
}
return f.Set(s)
},
HideEntered: f.ShouldHide(),
IsConfirm: isConfirm(reflect.TypeOf(value)),
}
_, err := prompt.Run()
if err != nil {
panic(err)
}
viper.Set(fieldPath, f.ValueOrDefault())
case OneOfUpdater:
var possibilities []string
for _, subField := range f.Fields() {
possibility := subField.Name()
if possibility == "" {
possibility = subField.Describe()
}
possibilities = append(possibilities, possibility)
}
prompt := promptui.Select{
Label: fmt.Sprintf("Select one of %s: (%s)", f.Name(), f.Describe()),
Items: possibilities,
}
i, _, err := prompt.Run()
if err != nil {
fmt.Println("panic", err)
panic(err)
}
setField(f.Fields()[i], fieldPath, depth-1)
// TODO: fv is result of decoder (postgres.config in this case)
case ConstantUpdater:
viper.Set(fieldPath, f.Value())
}
return nil
}
func path(parent, field string) string {
if parent == "" {
return field
}
if strings.HasSuffix(parent, field) {
return parent
}
if field == "" {
return parent
}
return parent + "." + field
}
func isConfirm(t reflect.Type) bool {
if t == nil {
return false
}
if t.Kind() == reflect.Ptr {
return isConfirm(t.Elem())
}
return t.Kind() == reflect.Bool
}
type Updater interface {
Name() string
Describe() string
ShouldUpdate(version *semver.Version) bool
}
type FieldUpdater interface {
Updater
// DefaultValue() any
Set(value any) error
ValueOrDefault() any
_field()
ShouldHide() bool
}
type StructUpdater interface {
Updater
Fields() []Updater
_struct()
}
type OneOfUpdater interface {
Updater
Fields() []Updater
_oneOf()
}
type ConstantUpdater interface {
Updater
Value() any
}
var _ FieldUpdater = (*Field[string])(nil)
type Field[T any] struct {
FieldName string
Value T
HideInput bool
Description string
Version *semver.Version
Validate func(T) error
}
// Describe implements [FieldUpdater].
func (f Field[T]) Describe() string {
return f.Description
}
// Set implements [FieldUpdater].
func (f *Field[T]) Set(value any) (err error) {
switch v := value.(type) {
case string:
f.Value, err = mapString[T](v)
case map[string]any:
f.Value, err = mapMap[T](v)
case T:
f.Value = v
default:
err = fmt.Errorf("unsupported type %T", v)
}
if err != nil || f.Validate == nil {
return err
}
return f.Validate(f.Value)
}
func (f Field[T]) ValueOrDefault() any {
return f.Value
}
func mapMap[T any](value map[string]any) (t T, err error) {
jsonValue, err := json.Marshal(value)
if err != nil {
return t, err
}
return t, json.Unmarshal(jsonValue, &t)
}
func mapString[T any](value string) (t T, err error) {
var v any
switch reflect.TypeFor[T]().Kind() {
case reflect.Bool:
v, err = strconv.ParseBool(value)
if err != nil {
return t, err
}
case reflect.Int:
i, err := strconv.ParseInt(value, 10, 0)
if err != nil {
return t, err
}
v = int(i)
case reflect.Int8:
i, err := strconv.ParseInt(value, 10, 8)
if err != nil {
return t, err
}
v = int8(i)
case reflect.Int16:
i, err := strconv.ParseInt(value, 10, 16)
if err != nil {
return t, err
}
v = int16(i)
case reflect.Int32:
i, err := strconv.ParseInt(value, 10, 32)
if err != nil {
return t, err
}
v = int32(i)
case reflect.Int64:
i, err := strconv.ParseInt(value, 10, 64)
if err != nil {
return t, err
}
v = int64(i)
case reflect.Uint:
i, err := strconv.ParseUint(value, 10, 0)
if err != nil {
return t, err
}
v = uint(i)
case reflect.Uint8:
i, err := strconv.ParseUint(value, 10, 8)
if err != nil {
return t, err
}
v = uint8(i)
case reflect.Uint16:
i, err := strconv.ParseUint(value, 10, 16)
if err != nil {
return t, err
}
v = uint16(i)
case reflect.Uint32:
i, err := strconv.ParseUint(value, 10, 32)
if err != nil {
return t, err
}
v = uint32(i)
case reflect.Uint64:
i, err := strconv.ParseUint(value, 10, 64)
if err != nil {
return t, err
}
v = uint64(i)
case reflect.Float32:
i, err := strconv.ParseFloat(value, 32)
if err != nil {
return t, err
}
v = float32(i)
case reflect.Float64:
i, err := strconv.ParseFloat(value, 64)
if err != nil {
return t, err
}
v = float64(i)
case reflect.Complex64:
i, err := strconv.ParseComplex(value, 64)
if err != nil {
return t, err
}
v = complex64(i)
case reflect.Complex128:
v, err = strconv.ParseComplex(value, 128)
case reflect.String:
v = value
default:
k := reflect.TypeFor[T]().Kind()
_ = k
return t, errors.New("not implemented")
}
return v.(T), nil
}
// Field implements [FieldUpdater].
func (f Field[T]) Name() string {
return f.FieldName
}
// ShouldUpdate implements [FieldUpdater].
func (f Field[T]) ShouldUpdate(version *semver.Version) bool {
if version == nil {
return true
}
return f.Version.GreaterThan(version)
}
// ShouldHide implements [FieldUpdater].
func (f Field[T]) ShouldHide() bool {
return f.HideInput
}
func (f Field[T]) _field() {}
var _ StructUpdater = (*Struct)(nil)
type Struct struct {
FieldName string
Description string
SubFields []Updater
}
// Describe implements [StructUpdater].
func (s Struct) Describe() string {
return s.Description
}
func (s Struct) Name() string {
return s.FieldName
}
func (s Struct) Fields() []Updater {
return s.SubFields
}
func (s Struct) ShouldUpdate(version *semver.Version) bool {
if version == nil {
return true
}
for _, field := range s.SubFields {
if !field.ShouldUpdate(version) {
continue
}
return true
}
return false
}
func (Struct) _struct() {}
type OneOf struct {
FieldName string
Description string
SubFields []Updater
}
// Describe implements [OneOfUpdater].
func (o OneOf) Describe() string {
return o.Description
}
// Fields implements [OneOfUpdater].
func (o OneOf) Fields() []Updater {
return o.SubFields
}
// Name implements [FieldUpdater].
func (o OneOf) Name() string {
return o.FieldName
}
func (OneOf) _oneOf() {}
// ShouldUpdate implements [OneOfUpdater].
func (o OneOf) ShouldUpdate(version *semver.Version) bool {
if version == nil {
return true
}
for _, field := range o.SubFields {
if !field.ShouldUpdate(version) {
continue
}
return true
}
return false
}
var _ OneOfUpdater = (*OneOf)(nil)
func FieldName(parent, field string) string {
if parent == "" {
return field
}
return parent + "." + field
}
type Constant[T any] struct {
Description string
Constant T
Version *semver.Version
}
var _ ConstantUpdater = (*Constant[any])(nil)
// Describe implements [ConstantUpdater].
func (c Constant[T]) Describe() string {
return c.Description
}
// Name implements [ConstantUpdater].
func (c Constant[T]) Name() string {
return ""
}
// ShouldUpdate implements [ConstantUpdater].
func (c Constant[T]) ShouldUpdate(version *semver.Version) bool {
if version == nil {
return true
}
return c.Version.GreaterThan(version)
}
// Value implements [ConstantUpdater].
func (c Constant[T]) Value() any {
return c.Constant
}

View File

@@ -0,0 +1,36 @@
package info
import (
"time"
"github.com/Masterminds/semver/v3"
)
var (
version string
commit string
date string
)
func Version() *semver.Version {
v, _ := semver.NewVersion(version)
if v != nil {
return v
}
return semver.New(uint64(Date().Year()), uint64(Date().Month()), uint64(Date().Day()), "", "")
}
func Commit() string {
return commit
}
func Date() time.Time {
if date == "" {
return time.Now()
}
d, err := time.Parse(time.RFC3339, date)
if err != nil {
return time.Now()
}
return d
}

View File

@@ -5,7 +5,8 @@ import (
"embed"
"fmt"
"github.com/zitadel/zitadel/backend/cmd/config"
"github.com/Masterminds/semver/v3"
"github.com/zitadel/zitadel/backend/cmd/configure"
"github.com/zitadel/zitadel/backend/storage/database"
)
@@ -18,26 +19,24 @@ var (
type Step001 struct {
Database database.Pool `mapstructure:"-"`
DatabaseName string `configure:"added:"v3",default:"zitadel"`
Username string `configure:"added:"v3",default:"zitadel"`
DatabaseName string
Username string
}
// Fields implements configure.StructUpdater.
func (v Step001) Fields() []configure.Updater {
return []configure.Updater{
configure.Field[string]{
&configure.Field[string]{
FieldName: "databaseName",
Default: "zitadel",
Value: &v.DatabaseName,
Value: "zitadel",
Description: "The name of the database Zitadel will store its data in",
Version: config.V3,
Version: semver.MustParse("3"),
},
configure.Field[string]{
&configure.Field[string]{
FieldName: "username",
Default: "zitadel",
Value: &v.Username,
Value: "zitadel",
Description: "The username Zitadel will use to connect to the database",
Version: config.V3,
Version: semver.MustParse("3"),
},
}
}

View File

@@ -1,6 +1,7 @@
package prepare
import (
"github.com/Masterminds/semver/v3"
"github.com/spf13/cobra"
"github.com/spf13/viper"
@@ -65,7 +66,10 @@ func (c *Config) Name() string {
}
// ShouldUpdate implements configure.StructUpdater.
func (c *Config) ShouldUpdate(version config.Version) bool {
func (c *Config) ShouldUpdate(version *semver.Version) bool {
if version == nil {
return true
}
for _, field := range c.Fields() {
if field.ShouldUpdate(version) {
return true
@@ -77,12 +81,12 @@ func (c *Config) ShouldUpdate(version config.Version) bool {
// Fields implements configure.UpdateConfig.
func (c Config) Fields() []configure.Updater {
return []configure.Updater{
configure.Struct{
&configure.Struct{
FieldName: "step001",
Description: "The configuration for the first step of the prepare command",
SubFields: c.Step001.Fields(),
},
configure.Struct{
&configure.Struct{
FieldName: "database",
Description: "The configuration for the database connection",
SubFields: c.Database.Fields(),

View File

@@ -2,6 +2,7 @@ package prepare
import (
"github.com/spf13/cobra"
step001 "github.com/zitadel/zitadel/backend/cmd/prepare/001"
)

View File

@@ -1,19 +1,6 @@
configuredversion: 2025.2.23
database:
cockroach:
host: localhost
port: 26257
gosql:
fieldname: gosql
default: null
value: null
description: Configuration for connection string for gosql
version: 1
postgres:
fieldname: postgres
default: null
value: null
description: Configuration for connection string for postgres
version: 1
postgres: host=local
step001:
databasename: zitadel
username: zitadel
databasename: zita
username: adel

View File

@@ -20,6 +20,7 @@ type Hook struct {
Match func(string) bool
Decode func(name string, config any) (database.Connector, error)
Name string
Field configure.Updater
}
var hooks = make([]Hook, 0)
@@ -30,11 +31,13 @@ func init() {
Match: postgres.NameMatcher,
Decode: postgres.DecodeConfig,
Name: postgres.Name,
Field: postgres.Field,
},
Hook{
Match: gosql.NameMatcher,
Decode: gosql.DecodeConfig,
Name: gosql.Name,
Field: gosql.Field,
},
)
}
@@ -48,18 +51,17 @@ type Config struct {
// Fields implements [configure.StructUpdater].
func (c *Config) Fields() []configure.Updater {
dialects := configure.OneOf{
FieldName: "dialect",
Description: "The database dialect Zitadel connects to",
SubFields: []configure.Updater{},
}
for _, hook := range hooks {
value := c.Dialects[hook.Name]
dialects.SubFields = append(dialects.SubFields, &configure.Field[any]{
if hook.Field == nil {
panic("hook must configure its config fields")
}
dialects.SubFields = append(dialects.SubFields, &configure.Struct{
FieldName: hook.Name,
Default: nil,
Description: fmt.Sprintf("Configuration for connection string for %s", hook.Name),
Version: config.V3,
Value: &value,
Description: fmt.Sprintf("Configuration for %s", hook.Name),
SubFields: []configure.Updater{hook.Field},
})
}

View File

@@ -6,12 +6,25 @@ import (
"errors"
"strings"
"github.com/Masterminds/semver/v3"
"github.com/jackc/pgx/v5/pgxpool"
"github.com/zitadel/zitadel/backend/cmd/configure"
"github.com/zitadel/zitadel/backend/storage/database"
)
var (
_ database.Connector = (*Config)(nil)
Name = "gosql"
_ database.Connector = (*Config)(nil)
Name = "gosql"
Field = &configure.Field[string]{
Description: "Connection string",
Version: semver.MustParse("v3"),
Validate: func(s string) error {
_, err := pgxpool.ParseConfig(s)
return err
},
}
)
type Config struct {

View File

@@ -6,14 +6,91 @@ import (
"slices"
"strings"
"github.com/Masterminds/semver/v3"
"github.com/jackc/pgx/v5/pgxpool"
"github.com/zitadel/zitadel/backend/cmd/configure"
"github.com/zitadel/zitadel/backend/storage/database"
)
var (
_ database.Connector = (*Config)(nil)
Name = "postgres"
Field = &configure.OneOf{
Description: "Configuring postgres using one of the following options",
SubFields: []configure.Updater{
&configure.Field[string]{
Description: "Connection string",
Version: semver.MustParse("v3"),
Validate: func(s string) error {
_, err := pgxpool.ParseConfig(s)
return err
},
},
&configure.Struct{
Description: "Configuration for the connection",
SubFields: []configure.Updater{
&configure.Field[string]{
FieldName: "host",
Value: "localhost",
Description: "The host to connect to",
Version: semver.MustParse("3"),
},
&configure.Field[uint32]{
FieldName: "port",
Value: 5432,
Description: "The port to connect to",
Version: semver.MustParse("3"),
},
&configure.Field[string]{
FieldName: "database",
Value: "zitadel",
Description: "The database to connect to",
Version: semver.MustParse("3"),
},
&configure.Field[string]{
FieldName: "user",
Description: "The user to connect as",
Value: "zitadel",
Version: semver.MustParse("3"),
},
&configure.Field[string]{
FieldName: "password",
Description: "The password to connect with",
Version: semver.MustParse("3"),
HideInput: true,
},
&configure.OneOf{
FieldName: "sslMode",
Description: "The SSL mode to use",
SubFields: []configure.Updater{
&configure.Constant[string]{
Description: "Disable",
Constant: "disable",
Version: semver.MustParse("3"),
},
&configure.Constant[string]{
Description: "Require",
Constant: "require",
Version: semver.MustParse("3"),
},
&configure.Constant[string]{
Description: "Verify CA",
Constant: "verify-ca",
Version: semver.MustParse("3"),
},
&configure.Constant[string]{
Description: "Verify Full",
Constant: "verify-full",
Version: semver.MustParse("3"),
},
},
},
},
},
},
}
)
type Config struct{ *pgxpool.Config }

View File

@@ -4,6 +4,7 @@ import (
"context"
"github.com/jackc/pgx/v5/pgxpool"
"github.com/zitadel/zitadel/backend/storage/database"
)

View File

@@ -4,6 +4,7 @@ import (
"context"
"github.com/jackc/pgx/v5/pgxpool"
"github.com/zitadel/zitadel/backend/storage/database"
)

View File

@@ -2,6 +2,7 @@ package postgres
import (
"github.com/jackc/pgx/v5"
"github.com/zitadel/zitadel/backend/storage/database"
)

View File

@@ -4,6 +4,7 @@ import (
"context"
"github.com/jackc/pgx/v5"
"github.com/zitadel/zitadel/backend/storage/database"
)

1
go.mod
View File

@@ -100,6 +100,7 @@ require (
cloud.google.com/go/auth v0.6.1 // indirect
cloud.google.com/go/auth/oauth2adapt v0.2.2 // indirect
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.48.0 // indirect
github.com/Masterminds/semver/v3 v3.3.1 // indirect
github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a // indirect
github.com/bmatcuk/doublestar/v4 v4.7.1 // indirect
github.com/chzyer/readline v1.5.1 // indirect

2
go.sum
View File

@@ -38,6 +38,8 @@ github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.48.0 h1:ng6QH9Z4bAXCf0Z1cjR5hKESyc1BUiOrfIOhN+nHfRU=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.48.0/go.mod h1:ZC7rjqRzdhRKDK223jQ7Tsz89ZtrSSLH/VFzf7k5Sb0=
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
github.com/Masterminds/semver/v3 v3.3.1 h1:QtNSWtVZ3nBfk8mAOu/B6v7FMJ+NHTIgUPi7rj+4nv4=
github.com/Masterminds/semver/v3 v3.3.1/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
github.com/Masterminds/squirrel v1.5.4 h1:uUcX/aBc8O7Fg9kaISIUsHXdKuqehiXAMQTYX8afzqM=
github.com/Masterminds/squirrel v1.5.4/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10=
github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc=