Thanks to visit codestin.com
Credit goes to github.com

Skip to content

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

Closed
wants to merge 9 commits into from

Conversation

joobisb
Copy link
Contributor

@joobisb joobisb commented Nov 5, 2024

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

CODER_PG_HOST
CODER_PG_PORT 
CODER_PG_USERNAME
CODER_PG_PASSWORD
CODER_PG_DATABASE
CODER_PG_OPTIONS

@cdr-bot cdr-bot bot added the community Pull Requests and issues created by the community. label Nov 5, 2024
Copy link
Member

@mafredri mafredri left a 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 != "" {
Copy link
Member

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")
Copy link
Member

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".
Copy link
Member

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",
Copy link
Member

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?

Copy link
Contributor Author

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

Copy link
Member

@mafredri mafredri Nov 6, 2024

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())

@joobisb
Copy link
Contributor Author

joobisb commented Nov 6, 2024

@mafredri I've addressed the comments, please do have a look

Copy link
Member

@mafredri mafredri left a 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")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"(--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",
Copy link
Member

@mafredri mafredri Nov 6, 2024

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())

@joobisb
Copy link
Contributor Author

joobisb commented Nov 6, 2024

Thanks for amending the previous feedback, just a couple more and I think this is good to go 👍🏻

@mafredri I've updated the PR

@matifali matifali requested a review from mafredri November 12, 2024 09:44
Copy link
Member

@mafredri mafredri left a 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 != "" {
Copy link
Member

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.

Copy link
Contributor Author

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

@mafredri mafredri enabled auto-merge (squash) November 15, 2024 11:40
@mafredri
Copy link
Member

Thanks for your contribution @joobisb 🎉! This is now ready to go 🚀 (as soon as final CI checks have completed).

@joobisb
Copy link
Contributor Author

joobisb commented Nov 15, 2024

@matifali could you please help with this as well as e2e is failing here as well

Copy link
Member

@ammario ammario left a 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.

@mafredri
Copy link
Member

@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.

@mafredri mafredri closed this Nov 20, 2024
auto-merge was automatically disabled November 20, 2024 14:19

Pull request was closed

@joobisb
Copy link
Contributor Author

joobisb commented Nov 22, 2024

@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.

@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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
community Pull Requests and issues created by the community.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Provide Postgresql database settings not only via connection string
3 participants