-
Notifications
You must be signed in to change notification settings - Fork 881
feat: support postgresql connection via individual flags #15379
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the PR! Left a few suggestions and things to consider.
cli/server.go
Outdated
@@ -395,6 +395,22 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd. | |||
|
|||
config := r.createConfig() | |||
|
|||
if vals.PostgresURL == "" && vals.PostgresHost != "" && vals.PostgresUsername != "" && vals.PostgresPassword != "" && vals.PostgresDatabase != "" { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should probably return an error if both connection URL and any other setting is provided. There's no good decision to make on which to prefer over the other so the user has to decide (hence the error) or we may introduce surprising behavior.
cli/server.go
Outdated
if err != nil { | ||
return err | ||
} | ||
cliui.Infof(inv.Stdout, "Created PostgreSQL URL from provided flags") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's remove this log, the user doesn't need to know about inner workings of how the options are handled.
provided via other flags, PostgreSQL binaries will be downloaded from | ||
Maven (https://repo1.maven.org/maven2) and store all data in the | ||
config root. Access the built-in database with "coder server | ||
postgres-builtin-url". |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should also document that this can't be used together with the other options.
cli/server.go
Outdated
@@ -395,6 +395,22 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd. | |||
|
|||
config := r.createConfig() | |||
|
|||
if vals.PostgresURL == "" && vals.PostgresHost != "" && vals.PostgresUsername != "" && vals.PostgresPassword != "" && vals.PostgresDatabase != "" { | |||
pgURL := fmt.Sprintf("postgres://%s:%s@%s:%s/%s?%s", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider what happens if only username is given, or no database, etc. I'm not sure if Set
below will error under what circumstances, but is the error message helpful in the user figuring out what's missing? Additional validation needed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mafredri
if either of them is not set, the existing behaviour will continue, we will only form the URL if PostgresHost
PostgresUsername
PostgresPassword
and PostgresDatabase
are present
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I don't realize I have to specify all flags, I will see the following confusing error:
❯ CODER_PG_HOST=mypgip ./coder server
[...]
error: Failed to start built-in PostgreSQL. Optionally, specify an external deployment with `--postgres-url`: could not start postgres using /home/coder/.config/coderv2/postgres/bin/bin/pg_ctl start -w -D /home/coder/.config/coderv2/postgres/data -o -p 41307:
I tried to use individual pg flag(s) but am directed towards pg url. We should handle this case as well. (I.e. it is a configuration error but there's no hint.)
Also, thinking about this fmt.Sprintf
some more, I think we should leave the encoding to url.URL
just to be safe. This also entails changing PostgresOptions
from serpent.String
to serpent.StringArray
, otherwise we expose an implementation detail that options need to be URL encoded (and joined by &
).
So something like this (didn't test):
vals.PostgresURL.Set((&url.URL{
Scheme: "postgres",
User: url.UserPassword(vals.PostgresUsername.String(), vals.PostgresPassword.String()),
Host: vals.PostgresHost.String() + ":" + vals.PostgresPort.String(),
Path: "/" + vals.PostgresDatabase.String(),
RawQuery: strings.Join(vals.PostgresOptions.GetSlice(), "&"),
}).String())
@mafredri I've addressed the comments, please do have a look |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for amending the previous feedback, just a couple more and I think this is good to go 👍🏻
cli/server.go
Outdated
if vals.PostgresURL != "" && (vals.PostgresHost != "" || vals.PostgresUsername != "" || | ||
vals.PostgresPassword != "" || vals.PostgresDatabase != "") { | ||
return xerrors.New("cannot specify both --postgres-url and individual postgres connection flags " + | ||
"(--postgres-host, --postgres-username, etc). Please use only one connection method") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"(--postgres-host, --postgres-username, etc). Please use only one connection method") | |
"(--postgres-host, --postgres-username, etc), please specify only one connection method") |
Nit: Consistent terminology.
cli/server.go
Outdated
@@ -395,6 +395,22 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd. | |||
|
|||
config := r.createConfig() | |||
|
|||
if vals.PostgresURL == "" && vals.PostgresHost != "" && vals.PostgresUsername != "" && vals.PostgresPassword != "" && vals.PostgresDatabase != "" { | |||
pgURL := fmt.Sprintf("postgres://%s:%s@%s:%s/%s?%s", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I don't realize I have to specify all flags, I will see the following confusing error:
❯ CODER_PG_HOST=mypgip ./coder server
[...]
error: Failed to start built-in PostgreSQL. Optionally, specify an external deployment with `--postgres-url`: could not start postgres using /home/coder/.config/coderv2/postgres/bin/bin/pg_ctl start -w -D /home/coder/.config/coderv2/postgres/data -o -p 41307:
I tried to use individual pg flag(s) but am directed towards pg url. We should handle this case as well. (I.e. it is a configuration error but there's no hint.)
Also, thinking about this fmt.Sprintf
some more, I think we should leave the encoding to url.URL
just to be safe. This also entails changing PostgresOptions
from serpent.String
to serpent.StringArray
, otherwise we expose an implementation detail that options need to be URL encoded (and joined by &
).
So something like this (didn't test):
vals.PostgresURL.Set((&url.URL{
Scheme: "postgres",
User: url.UserPassword(vals.PostgresUsername.String(), vals.PostgresPassword.String()),
Host: vals.PostgresHost.String() + ":" + vals.PostgresPort.String(),
Path: "/" + vals.PostgresDatabase.String(),
RawQuery: strings.Join(vals.PostgresOptions.GetSlice(), "&"),
}).String())
@mafredri I've updated the PR |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just have one minor nit remaining but otherwise this is good to go. Thanks a lot for working on this @joobisb and sorry for the wait.
cli/server.go
Outdated
return xerrors.Errorf("validate postgres configuration: %w", err) | ||
} | ||
|
||
if vals.PostgresURL == "" && vals.PostgresHost != "" && vals.PostgresUsername != "" && vals.PostgresPassword != "" && vals.PostgresDatabase != "" { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we instead return a boolean from validatePostgresFlags
that tells us to use flags? We basically have the same logic in two places and there's a risk of one of them going stale if something changes in the future.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mafredri I've addressed this
Thanks for your contribution @joobisb 🎉! This is now ready to go 🚀 (as soon as final CI checks have completed). |
@matifali could you please help with this as well as e2e is failing here as well |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see the problem in the original issue but I don’t think it warrants more server flags. Users can create the connection URL via interpolation in bash, etc.
We should have a very high bar for adding server flags in general and an even higher bar for multiple ways to configure the same thing.
@joobisb Thank you very much for the effort you put into this and I want to apologize that we didn't catch the bad product fit earlier. I hope this doesn't discourage you and want you to know it was a pleasure working with you on this, I look forward to more such opportunities in the future. |
Pull request was closed
@mafredri Thank-you for your kind words, and no worries. Things won't always go as planned. I also look forward to working with you again. |
Closes #15264
Currently
CODER_PG_CONNECTION_URL
is the only variable through which we will be able to provide the postgres credentials.With this PR, we will support additional envs to configure PostgreSQL connections, namely