No-fuss DB connection configuration via libpq PG* environment variables#1748
Open
brontolosone wants to merge 7 commits intogetodk:masterfrom
Open
No-fuss DB connection configuration via libpq PG* environment variables#1748brontolosone wants to merge 7 commits intogetodk:masterfrom
brontolosone wants to merge 7 commits intogetodk:masterfrom
Conversation
9a7bb60 to
088afaf
Compare
007711a to
3d75b9b
Compare
6885630 to
c0be247
Compare
c0be247 to
b9606dc
Compare
2 tasks
0c20f66 to
26137b5
Compare
Member
There was a problem hiding this comment.
Curious whether you considered adding the function here to the existing lib/util/db.js? That file has been getting kind of big, so I'm open to splitting it up like this, but I'd be curious to learn more about your thinking in this area.
Contributor
Author
There was a problem hiding this comment.
I like files as an organizational unit, and they're pretty much free, well at least for me they are, df -i tells me I'm not nearly out of inodes yet ;-)
- Yes this functionality is related to the DB, in a sense, but
lib/util/db.jsby and large has to do with SQL templating and pseudo-ORM functions, while this new configuration functionality isn't. - This new
load-db-envmodule often needs to be loaded early on, and for that my instinct is that it should be small, simple, and have minimal dependencies (also to avoid cyclic dependencies) - everything in ODK Central backend is related to ODK, maybe we should put everything in one file
odk.js, it'd be perfectly organized 🤡 - one thing you may have noticed as well is that in this codebase there are quite a few large (to my taste) modules that are informally sectioned using quite decorative header comments, eg in
lib/util/db.jswe have:which to me is a faint code smell, I feel one should use the language's formal modularization features for modularization, not comments, which impose a cognitive load on human readers. Since I don't like that smell I err on the side of making a module rather than following the (anti-?) pattern of cordoning off a "module section" with elaborate decorative comments as section headers (it even has its own typographical mini-style) within a module.//////////////////////////////////////////////////////////////////////////////// // SLONIK UTIL
26137b5 to
8f4aaa9
Compare
…es, and support legacy config by setting those variables when defined in config yet unset in environment
…onment variables now
…ent with the observed earlier behaviour, and that's that.
8f4aaa9 to
9a4528d
Compare
9a4528d to
7626a2e
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Related
Our code / config / knex (+deptree) / slonik (+deptree), they're all miming to eachother about DB connection configuration. It's easy to forget that *eventually*, that information just needs to be conveyed to `libpq` — the *actual* bedrock database driver. Not one of these middlemen inherently cares about the specifics, it's like a bucket brigade of passing & mangling information; but in the end we just want a DB connection.Motivation, background
That whole wrapper mille-feuille is rife with misconceptions (eg, how SSL works / should be conveyed), incomplete exposure of connection features (eg, TCP connection timeouts), and incompatibilities (again, SSL, and also Unix domain sockets).
But it just so happens that
libpq(the thing that actually does the thing)is designed so that one can talk directly to it to configure its connections. This works with a set of environment variables that
libpqreads from the process environment. It will use that information unless in the connection setup call to libpq something else is explicitly configured. In the documentation it says about these env vars:And indeed one can imagine that it is nice to be able to write a client application without having to re-expose the complete postgres connection parameter interface.
So if we adopt that configuration mechanism (which means: we get out of the way!), we can stop worrying about what to support, what configuration interface to present to users, and how to convey things to knex/slonik in their idiosyncratic way (if even supported). 🥳
Advantages would be:
psql. If you get a connection, you did it right, if you don't, you did it wrong (and probably there'll be some output from the tool hinting at what's wrong).psql,libpq,postgresqlare all from the same vendor; they're not miming to eachother, there's just so much less ambiguity around why something isn't working. It also makes it easy for a sysadmin to communicate connection details and support their users, because of that uniform configuration interface.Approach
configmodule, and its cascading inheritance. Initially I toyed a bit with sourcing different files with different environment variables (eg, through the Makefile) depending on whether we're running tests or not, but I didn't quite get good DX this way, plus I think that getting used to a new config interface would be an impediment to getting this PR in. Thus, I wrapped (oh no! wrapping! interpretation) that interface, one can still set the same limited set of db config variables that way, but they'll go into env vars rather than into connection setup call parameters. So everything still works! Yet, one can also override things throug environment variables, eg if one runsPGDATABASE=someotherdatabase make dev, then that's what you'll get, it won't be overridden with what's inconfig. Example:odkcentralin this case) is not being applied, because we've explicitly set PGDATABASE. So you'll be made aware of what's going on. No surprises. You're going to connect to thestaging_odkcentraldatabase.As an example of the flexibility, my own
default.databaseconfig inconfig/local.jsonis, with this PR:userandpasswordfield, otherwise I'd get the values from the higher-up config precedence waterfall (default.jsonetc).The
"ssl": trueconfig fragment is also supported, but I thought it appropriate to print a warning, as I don't feel doing SSL without authenticating the other party is on par with the warm feeling of safety that"ssl": trueinstills. So you'll see this helpful warning:What has been done to verify that this works as intended?
Tests still pass, but see note at the top re #1746 .
Why is this the best possible solution? Were any other approaches considered?
Don't get me started 😆 . See background/rationale at the top of this PR.
How does this change affect users? Describe intentional changes to behavior and behavior that could have accidentally been affected by code changes. In other words, what are the regression risks?
For all quotidian setups, there should be no regression, legacy config will continue to work. But, if people have been patching code to do workarounds to get certain connection parameters in that we didn't support, there may be surprises, hard to predict 🤷♂️
Does this change require updates to the API documentation? If so, please update docs/api.yaml as part of this PR.
Not to the API documentation.
But the
centralinstall howto, and the.env.examplefile, should be streamlined with this code. It could also be useful to zombiepost into the various forum posts where people have been asking about DB configuration, so that newcomers searching for info will find the uptodate New Way of Configuring the Database Any Way You Like.Before submitting this PR, please make sure you have:
make testand confirmed all checks still pass OR confirm CircleCI build passes