feat(be): use omitempty for json config

This commit is contained in:
Denis Gukov 2024-09-29 23:53:33 +05:00
parent 0078297d25
commit bea1c6045f
5 changed files with 139 additions and 90 deletions

View File

@ -120,7 +120,7 @@ func tryFindLDAPUser(username, password string) (*db.User, error) {
prepareClaims(entry) prepareClaims(entry)
claims, err := parseClaims(entry, &util.Config.LdapMappings) claims, err := parseClaims(entry, util.Config.LdapMappings)
if err != nil { if err != nil {
return nil, err return nil, err
} }

37
cli/cmd/runner_setup.go Normal file
View File

@ -0,0 +1,37 @@
package cmd
import (
"fmt"
"github.com/ansible-semaphore/semaphore/cli/setup"
"github.com/ansible-semaphore/semaphore/util"
"github.com/spf13/cobra"
)
func init() {
runnerCmd.AddCommand(runnerSetupCmd)
}
var runnerSetupCmd = &cobra.Command{
Use: "setup",
Short: "Perform interactive setup",
Run: func(cmd *cobra.Command, args []string) {
doRunnerSetup()
},
}
// nolint: gocyclo
func doRunnerSetup() int {
var config *util.ConfigType
config = &util.ConfigType{}
setup.InteractiveRunnerSetup(config)
configPath := setup.SaveConfig(config)
util.ConfigInit(configPath, false)
fmt.Printf(" Re-launch this program pointing to the configuration file\n\n./semaphore server --config %v\n\n", configPath)
fmt.Printf(" To run as daemon:\n\nnohup ./semaphore server --config %v &\n\n", configPath)
return 0
}

View File

@ -21,6 +21,23 @@ Hello! You will now be guided through a setup to:
` `
func InteractiveRunnerSetup(conf *util.ConfigType) {
askValue("Semaphore server URL", "", &conf.WebHost)
askValue("Path to the file where runner token will be stored", "", &conf.Runner.TokenFile)
haveToken := false
askConfirmation("Do you have runner token?", false, &haveToken)
if haveToken {
token := ""
askValue("Runner token", "", &token)
// TODO: write token
}
}
func InteractiveSetup(conf *util.ConfigType) { func InteractiveSetup(conf *util.ConfigType) {
fmt.Print(interactiveSetupBlurb) fmt.Print(interactiveSetupBlurb)
@ -100,10 +117,12 @@ func scanBoltDb(conf *util.ConfigType) {
workingDirectory = os.TempDir() workingDirectory = os.TempDir()
} }
defaultBoltDBPath := filepath.Join(workingDirectory, "database.boltdb") defaultBoltDBPath := filepath.Join(workingDirectory, "database.boltdb")
conf.BoltDb = &util.DbConfig{}
askValue("db filename", defaultBoltDBPath, &conf.BoltDb.Hostname) askValue("db filename", defaultBoltDBPath, &conf.BoltDb.Hostname)
} }
func scanMySQL(conf *util.ConfigType) { func scanMySQL(conf *util.ConfigType) {
conf.MySQL = &util.DbConfig{}
askValue("db Hostname", "127.0.0.1:3306", &conf.MySQL.Hostname) askValue("db Hostname", "127.0.0.1:3306", &conf.MySQL.Hostname)
askValue("db User", "root", &conf.MySQL.Username) askValue("db User", "root", &conf.MySQL.Username)
askValue("db Password", "", &conf.MySQL.Password) askValue("db Password", "", &conf.MySQL.Password)
@ -111,6 +130,7 @@ func scanMySQL(conf *util.ConfigType) {
} }
func scanPostgres(conf *util.ConfigType) { func scanPostgres(conf *util.ConfigType) {
conf.Postgres = &util.DbConfig{}
askValue("db Hostname", "127.0.0.1:5432", &conf.Postgres.Hostname) askValue("db Hostname", "127.0.0.1:5432", &conf.Postgres.Hostname)
askValue("db User", "root", &conf.Postgres.Username) askValue("db User", "root", &conf.Postgres.Username)
askValue("db Password", "", &conf.Postgres.Password) askValue("db Password", "", &conf.Postgres.Password)
@ -129,7 +149,11 @@ func scanErrorChecker(n int, err error) {
} }
} }
func SaveConfig(config *util.ConfigType) (configPath string) { type IConfig interface {
ToJSON() ([]byte, error)
}
func SaveConfig(config IConfig) (configPath string) {
configDirectory, err := os.Getwd() configDirectory, err := os.Getwd()
if err != nil { if err != nil {
configDirectory, err = os.UserConfigDir() configDirectory, err = os.UserConfigDir()
@ -168,19 +192,6 @@ func SaveConfig(config *util.ConfigType) (configPath string) {
return return
} }
func AskConfigConfirmation(config *util.ConfigType) bool {
bytes, err := config.ToJSON()
if err != nil {
panic(err)
}
fmt.Printf("\nGenerated configuration:\n %v\n\n", string(bytes))
var correct bool
askConfirmation("Is this correct?", true, &correct)
return correct
}
func askValue(prompt string, defaultValue string, item interface{}) { func askValue(prompt string, defaultValue string, item interface{}) {
// Print prompt with optional default value // Print prompt with optional default value
fmt.Print(prompt) fmt.Print(prompt)

View File

@ -55,9 +55,9 @@ func (p *JobPool) hasRunningJobs() bool {
} }
func (p *JobPool) Register() (err error) { func (p *JobPool) Register() (err error) {
if util.Config.Runner.RegistrationToken == "" { //if util.Config.Runner.RegistrationToken == "" {
return fmt.Errorf("runner registration token required") // return fmt.Errorf("runner registration token required")
} //}
if util.Config.Runner.TokenFile == "" { if util.Config.Runner.TokenFile == "" {
return fmt.Errorf("runner token file required") return fmt.Errorf("runner token file required")
@ -80,7 +80,7 @@ func (p *JobPool) Unregister() (err error) {
client := &http.Client{} client := &http.Client{}
url := util.Config.Runner.ApiURL + "/internal/runners" url := util.Config.WebHost + "/api/internal/runners"
req, err := http.NewRequest("DELETE", url, nil) req, err := http.NewRequest("DELETE", url, nil)
if err != nil { if err != nil {
@ -194,7 +194,7 @@ func (p *JobPool) sendProgress() {
client := &http.Client{} client := &http.Client{}
url := util.Config.Runner.ApiURL + "/internal/runners" url := util.Config.Runner.Webhook + "/api/internal/runners"
body := RunnerProgress{ body := RunnerProgress{
Jobs: nil, Jobs: nil,
@ -249,7 +249,9 @@ func (p *JobPool) tryRegisterRunner() bool {
// Can not restore runner configuration. Register new runner on the server. // Can not restore runner configuration. Register new runner on the server.
if util.Config.Runner.RegistrationToken == "" { registrationToken := ""
if registrationToken == "" {
panic("registration token cannot be empty") panic("registration token cannot be empty")
} }
@ -257,10 +259,10 @@ func (p *JobPool) tryRegisterRunner() bool {
client := &http.Client{} client := &http.Client{}
url := util.Config.Runner.ApiURL + "/internal/runners" url := util.Config.WebHost + "/api/internal/runners"
jsonBytes, err := json.Marshal(RunnerRegistration{ jsonBytes, err := json.Marshal(RunnerRegistration{
RegistrationToken: util.Config.Runner.RegistrationToken, RegistrationToken: registrationToken,
Webhook: util.Config.Runner.Webhook, Webhook: util.Config.Runner.Webhook,
MaxParallelTasks: util.Config.Runner.MaxParallelTasks, MaxParallelTasks: util.Config.Runner.MaxParallelTasks,
}) })
@ -312,7 +314,7 @@ func (p *JobPool) checkNewJobs() {
client := &http.Client{} client := &http.Client{}
url := util.Config.Runner.ApiURL + "/internal/runners" url := util.Config.WebHost + "/api/internal/runners"
req, err := http.NewRequest("GET", url, nil) req, err := http.NewRequest("GET", url, nil)

View File

@ -36,11 +36,11 @@ const (
type DbConfig struct { type DbConfig struct {
Dialect string `json:"-"` Dialect string `json:"-"`
Hostname string `json:"host" env:"SEMAPHORE_DB_HOST"` Hostname string `json:"host,omitempty" env:"SEMAPHORE_DB_HOST"`
Username string `json:"user" env:"SEMAPHORE_DB_USER"` Username string `json:"user,omitempty" env:"SEMAPHORE_DB_USER"`
Password string `json:"pass" env:"SEMAPHORE_DB_PASS"` Password string `json:"pass,omitempty" env:"SEMAPHORE_DB_PASS"`
DbName string `json:"name" env:"SEMAPHORE_DB"` DbName string `json:"name,omitempty" env:"SEMAPHORE_DB"`
Options map[string]string `json:"options" env:"SEMAPHORE_DB_OPTIONS"` Options map[string]string `json:"options,omitempty" env:"SEMAPHORE_DB_OPTIONS"`
} }
type ldapMappings struct { type ldapMappings struct {
@ -91,11 +91,9 @@ const (
// //
// */ // */
type RunnerSettings struct { type RunnerConfig struct {
ApiURL string `json:"api_url" env:"SEMAPHORE_RUNNER_API_URL"` Token string `json:"-" env:"SEMAPHORE_RUNNER_TOKEN"`
RegistrationToken string `json:"registration_token" env:"SEMAPHORE_RUNNER_REGISTRATION_TOKEN"`
Token string `json:"token" env:"SEMAPHORE_RUNNER_TOKEN"`
TokenFile string `json:"token_file" env:"SEMAPHORE_RUNNER_TOKEN_FILE"` TokenFile string `json:"token_file" env:"SEMAPHORE_RUNNER_TOKEN_FILE"`
// OneOff indicates than runner runs only one job and exit. It is very useful for dynamic runners. // OneOff indicates than runner runs only one job and exit. It is very useful for dynamic runners.
@ -105,101 +103,102 @@ type RunnerSettings struct {
// 2) Semaphore found runner for task and calls runner's webhook if it provided. // 2) Semaphore found runner for task and calls runner's webhook if it provided.
// 3) Your server or lambda handling the call and starts the one-off runner. // 3) Your server or lambda handling the call and starts the one-off runner.
// 4) The runner connects to the Semaphore server and handles the enqueued task(s). // 4) The runner connects to the Semaphore server and handles the enqueued task(s).
OneOff bool `json:"one_off" env:"SEMAPHORE_RUNNER_ONE_OFF"` OneOff bool `json:"one_off,omitempty" env:"SEMAPHORE_RUNNER_ONE_OFF"`
Webhook string `json:"webhook" env:"SEMAPHORE_RUNNER_WEBHOOK"` Webhook string `json:"webhook,omitempty" env:"SEMAPHORE_RUNNER_WEBHOOK"`
MaxParallelTasks int `json:"max_parallel_tasks" default:"1" env:"SEMAPHORE_RUNNER_MAX_PARALLEL_TASKS"`
MaxParallelTasks int `json:"max_parallel_tasks,omitempty" default:"1" env:"SEMAPHORE_RUNNER_MAX_PARALLEL_TASKS"`
} }
// ConfigType mapping between Config and the json file that sets it // ConfigType mapping between Config and the json file that sets it
type ConfigType struct { type ConfigType struct {
MySQL DbConfig `json:"mysql"` MySQL *DbConfig `json:"mysql,omitempty"`
BoltDb DbConfig `json:"bolt"` BoltDb *DbConfig `json:"bolt,omitempty"`
Postgres DbConfig `json:"postgres"` Postgres *DbConfig `json:"postgres,omitempty"`
Dialect string `json:"dialect" default:"bolt" rule:"^mysql|bolt|postgres$" env:"SEMAPHORE_DB_DIALECT"` Dialect string `json:"dialect,omitempty" default:"bolt" rule:"^mysql|bolt|postgres$" env:"SEMAPHORE_DB_DIALECT"`
// Format `:port_num` eg, :3000 // Format `:port_num` eg, :3000
// if : is missing it will be corrected // if : is missing it will be corrected
Port string `json:"port" default:":3000" rule:"^:?([0-9]{1,5})$" env:"SEMAPHORE_PORT"` Port string `json:"port,omitempty" default:":3000" rule:"^:?([0-9]{1,5})$" env:"SEMAPHORE_PORT"`
// Interface ip, put in front of the port. // Interface ip, put in front of the port.
// defaults to empty // defaults to empty
Interface string `json:"interface" env:"SEMAPHORE_INTERFACE"` Interface string `json:"interface,omitempty" env:"SEMAPHORE_INTERFACE"`
// semaphore stores ephemeral projects here // semaphore stores ephemeral projects here
TmpPath string `json:"tmp_path" default:"/tmp/semaphore" env:"SEMAPHORE_TMP_PATH"` TmpPath string `json:"tmp_path,omitempty" default:"/tmp/semaphore" env:"SEMAPHORE_TMP_PATH"`
// SshConfigPath is a path to the custom SSH config file. // SshConfigPath is a path to the custom SSH config file.
// Default path is ~/.ssh/config. // Default path is ~/.ssh/config.
SshConfigPath string `json:"ssh_config_path" env:"SEMAPHORE_SSH_PATH"` SshConfigPath string `json:"ssh_config_path,omitempty" env:"SEMAPHORE_SSH_PATH"`
GitClientId string `json:"git_client" rule:"^go_git|cmd_git$" env:"SEMAPHORE_GIT_CLIENT" default:"cmd_git"` GitClientId string `json:"git_client,omitempty" rule:"^go_git|cmd_git$" env:"SEMAPHORE_GIT_CLIENT" default:"cmd_git"`
// web host // web host
WebHost string `json:"web_host" env:"SEMAPHORE_WEB_ROOT"` WebHost string `json:"web_host,omitempty" env:"SEMAPHORE_WEB_ROOT"`
// cookie hashing & encryption // cookie hashing & encryption
CookieHash string `json:"cookie_hash" env:"SEMAPHORE_COOKIE_HASH"` CookieHash string `json:"cookie_hash,omitempty" env:"SEMAPHORE_COOKIE_HASH"`
CookieEncryption string `json:"cookie_encryption" env:"SEMAPHORE_COOKIE_ENCRYPTION"` CookieEncryption string `json:"cookie_encryption,omitempty" env:"SEMAPHORE_COOKIE_ENCRYPTION"`
// AccessKeyEncryption is BASE64 encoded byte array used // AccessKeyEncryption is BASE64 encoded byte array used
// for encrypting and decrypting access keys stored in database. // for encrypting and decrypting access keys stored in database.
AccessKeyEncryption string `json:"access_key_encryption" env:"SEMAPHORE_ACCESS_KEY_ENCRYPTION"` AccessKeyEncryption string `json:"access_key_encryption,omitempty" env:"SEMAPHORE_ACCESS_KEY_ENCRYPTION"`
// email alerting // email alerting
EmailAlert bool `json:"email_alert" env:"SEMAPHORE_EMAIL_ALERT"` EmailAlert bool `json:"email_alert,omitempty" env:"SEMAPHORE_EMAIL_ALERT"`
EmailSender string `json:"email_sender" env:"SEMAPHORE_EMAIL_SENDER"` EmailSender string `json:"email_sender,omitempty" env:"SEMAPHORE_EMAIL_SENDER"`
EmailHost string `json:"email_host" env:"SEMAPHORE_EMAIL_HOST"` EmailHost string `json:"email_host,omitempty" env:"SEMAPHORE_EMAIL_HOST"`
EmailPort string `json:"email_port" rule:"^(|[0-9]{1,5})$" env:"SEMAPHORE_EMAIL_PORT"` EmailPort string `json:"email_port,omitempty" rule:"^(|[0-9]{1,5})$" env:"SEMAPHORE_EMAIL_PORT"`
EmailUsername string `json:"email_username" env:"SEMAPHORE_EMAIL_USERNAME"` EmailUsername string `json:"email_username,omitempty" env:"SEMAPHORE_EMAIL_USERNAME"`
EmailPassword string `json:"email_password" env:"SEMAPHORE_EMAIL_PASSWORD"` EmailPassword string `json:"email_password,omitempty" env:"SEMAPHORE_EMAIL_PASSWORD"`
EmailSecure bool `json:"email_secure" env:"SEMAPHORE_EMAIL_SECURE"` EmailSecure bool `json:"email_secure,omitempty" env:"SEMAPHORE_EMAIL_SECURE"`
// ldap settings // ldap settings
LdapEnable bool `json:"ldap_enable" env:"SEMAPHORE_LDAP_ENABLE"` LdapEnable bool `json:"ldap_enable,omitempty" env:"SEMAPHORE_LDAP_ENABLE"`
LdapBindDN string `json:"ldap_binddn" env:"SEMAPHORE_LDAP_BIND_DN"` LdapBindDN string `json:"ldap_binddn,omitempty" env:"SEMAPHORE_LDAP_BIND_DN"`
LdapBindPassword string `json:"ldap_bindpassword" env:"SEMAPHORE_LDAP_BIND_PASSWORD"` LdapBindPassword string `json:"ldap_bindpassword,omitempty" env:"SEMAPHORE_LDAP_BIND_PASSWORD"`
LdapServer string `json:"ldap_server" env:"SEMAPHORE_LDAP_SERVER"` LdapServer string `json:"ldap_server,omitempty" env:"SEMAPHORE_LDAP_SERVER"`
LdapSearchDN string `json:"ldap_searchdn" env:"SEMAPHORE_LDAP_SEARCH_DN"` LdapSearchDN string `json:"ldap_searchdn,omitempty" env:"SEMAPHORE_LDAP_SEARCH_DN"`
LdapSearchFilter string `json:"ldap_searchfilter" env:"SEMAPHORE_LDAP_SEARCH_FILTER"` LdapSearchFilter string `json:"ldap_searchfilter,omitempty" env:"SEMAPHORE_LDAP_SEARCH_FILTER"`
LdapMappings ldapMappings `json:"ldap_mappings"` LdapMappings *ldapMappings `json:"ldap_mappings,omitempty"`
LdapNeedTLS bool `json:"ldap_needtls" env:"SEMAPHORE_LDAP_NEEDTLS"` LdapNeedTLS bool `json:"ldap_needtls,omitempty" env:"SEMAPHORE_LDAP_NEEDTLS"`
// Telegram, Slack, Rocket.Chat, Microsoft Teams and DingTalk alerting // Telegram, Slack, Rocket.Chat, Microsoft Teams and DingTalk alerting
TelegramAlert bool `json:"telegram_alert" env:"SEMAPHORE_TELEGRAM_ALERT"` TelegramAlert bool `json:"telegram_alert,omitempty" env:"SEMAPHORE_TELEGRAM_ALERT"`
TelegramChat string `json:"telegram_chat" env:"SEMAPHORE_TELEGRAM_CHAT"` TelegramChat string `json:"telegram_chat,omitempty" env:"SEMAPHORE_TELEGRAM_CHAT"`
TelegramToken string `json:"telegram_token" env:"SEMAPHORE_TELEGRAM_TOKEN"` TelegramToken string `json:"telegram_token,omitempty" env:"SEMAPHORE_TELEGRAM_TOKEN"`
SlackAlert bool `json:"slack_alert" env:"SEMAPHORE_SLACK_ALERT"` SlackAlert bool `json:"slack_alert,omitempty" env:"SEMAPHORE_SLACK_ALERT"`
SlackUrl string `json:"slack_url" env:"SEMAPHORE_SLACK_URL"` SlackUrl string `json:"slack_url,omitempty" env:"SEMAPHORE_SLACK_URL"`
RocketChatAlert bool `json:"rocketchat_alert" env:"SEMAPHORE_ROCKETCHAT_ALERT"` RocketChatAlert bool `json:"rocketchat_alert,omitempty" env:"SEMAPHORE_ROCKETCHAT_ALERT"`
RocketChatUrl string `json:"rocketchat_url" env:"SEMAPHORE_ROCKETCHAT_URL"` RocketChatUrl string `json:"rocketchat_url,omitempty" env:"SEMAPHORE_ROCKETCHAT_URL"`
MicrosoftTeamsAlert bool `json:"microsoft_teams_alert" env:"SEMAPHORE_MICROSOFT_TEAMS_ALERT"` MicrosoftTeamsAlert bool `json:"microsoft_teams_alert,omitempty" env:"SEMAPHORE_MICROSOFT_TEAMS_ALERT"`
MicrosoftTeamsUrl string `json:"microsoft_teams_url" env:"SEMAPHORE_MICROSOFT_TEAMS_URL"` MicrosoftTeamsUrl string `json:"microsoft_teams_url,omitempty" env:"SEMAPHORE_MICROSOFT_TEAMS_URL"`
DingTalkAlert bool `json:"dingtalk_alert" env:"SEMAPHORE_DINGTALK_ALERT"` DingTalkAlert bool `json:"dingtalk_alert,omitempty" env:"SEMAPHORE_DINGTALK_ALERT"`
DingTalkUrl string `json:"dingtalk_url" env:"SEMAPHORE_DINGTALK_URL"` DingTalkUrl string `json:"dingtalk_url,omitempty" env:"SEMAPHORE_DINGTALK_URL"`
// oidc settings // oidc settings
OidcProviders map[string]OidcProvider `json:"oidc_providers"` OidcProviders map[string]OidcProvider `json:"oidc_providers,omitempty"`
MaxTaskDurationSec int `json:"max_task_duration_sec" env:"SEMAPHORE_MAX_TASK_DURATION_SEC"` MaxTaskDurationSec int `json:"max_task_duration_sec,omitempty" env:"SEMAPHORE_MAX_TASK_DURATION_SEC"`
MaxTasksPerTemplate int `json:"max_tasks_per_template" env:"SEMAPHORE_MAX_TASKS_PER_TEMPLATE"` MaxTasksPerTemplate int `json:"max_tasks_per_template,omitempty" env:"SEMAPHORE_MAX_TASKS_PER_TEMPLATE"`
// task concurrency // task concurrency
MaxParallelTasks int `json:"max_parallel_tasks" default:"10" rule:"^[0-9]{1,10}$" env:"SEMAPHORE_MAX_PARALLEL_TASKS"` MaxParallelTasks int `json:"max_parallel_tasks,omitempty" default:"10" rule:"^[0-9]{1,10}$" env:"SEMAPHORE_MAX_PARALLEL_TASKS"`
RunnerRegistrationToken string `json:"runner_registration_token" env:"SEMAPHORE_RUNNER_REGISTRATION_TOKEN"` RunnerRegistrationToken string `json:"runner_registration_token,omitempty" env:"SEMAPHORE_RUNNER_REGISTRATION_TOKEN"`
// feature switches // feature switches
PasswordLoginDisable bool `json:"password_login_disable" env:"SEMAPHORE_PASSWORD_LOGIN_DISABLED"` PasswordLoginDisable bool `json:"password_login_disable,omitempty" env:"SEMAPHORE_PASSWORD_LOGIN_DISABLED"`
NonAdminCanCreateProject bool `json:"non_admin_can_create_project" env:"SEMAPHORE_NON_ADMIN_CAN_CREATE_PROJECT"` NonAdminCanCreateProject bool `json:"non_admin_can_create_project,omitempty" env:"SEMAPHORE_NON_ADMIN_CAN_CREATE_PROJECT"`
UseRemoteRunner bool `json:"use_remote_runner" env:"SEMAPHORE_USE_REMOTE_RUNNER"` UseRemoteRunner bool `json:"use_remote_runner,omitempty" env:"SEMAPHORE_USE_REMOTE_RUNNER"`
IntegrationAlias string `json:"global_integration_alias" env:"SEMAPHORE_INTEGRATION_ALIAS"` IntegrationAlias string `json:"global_integration_alias,omitempty" env:"SEMAPHORE_INTEGRATION_ALIAS"`
Apps map[string]App `json:"apps" env:"SEMAPHORE_APPS"` Apps map[string]App `json:"apps,omitempty" env:"SEMAPHORE_APPS"`
Runner RunnerSettings `json:"runner"` Runner *RunnerConfig `json:"runner,omitempty"`
} }
// Config exposes the application configuration storage for use in the application // Config exposes the application configuration storage for use in the application
@ -239,7 +238,7 @@ func ConfigInit(configPath string, noConfigFile bool) {
WebHostURL = nil WebHostURL = nil
} }
if Config.Runner.TokenFile != "" { if Config.Runner != nil && Config.Runner.TokenFile != "" {
runnerTokenBytes, err := os.ReadFile(Config.Runner.TokenFile) runnerTokenBytes, err := os.ReadFile(Config.Runner.TokenFile)
if err == nil { if err == nil {
Config.Runner.Token = string(runnerTokenBytes) Config.Runner.Token = string(runnerTokenBytes)
@ -752,11 +751,11 @@ func (conf *ConfigType) GetDBConfig() (dbConfig DbConfig, err error) {
switch dialect { switch dialect {
case DbDriverBolt: case DbDriverBolt:
dbConfig = conf.BoltDb dbConfig = *conf.BoltDb
case DbDriverPostgres: case DbDriverPostgres:
dbConfig = conf.Postgres dbConfig = *conf.Postgres
case DbDriverMySQL: case DbDriverMySQL:
dbConfig = conf.MySQL dbConfig = *conf.MySQL
default: default:
err = errors.New("database configuration not found") err = errors.New("database configuration not found")
} }