-
Notifications
You must be signed in to change notification settings - Fork 114
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
add django-dotenv, and compensate for the removal of drama-free-django runtime features #5133
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.
Overall looks good. Just a few questions/thoughts on environment_candidates
.
cfgov/cfgov/wsgi.py
Outdated
|
||
|
||
def initialize_environment(): | ||
environment_candidates = [ |
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.
Why do we need these 3 possible options? Seems like a chance to have a .env
in more than one place, and mistake which one is actually being used. Seems worth of a comment and/or some docs describing when to use these different locations.
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.
Agree, it'd be nice to standardize on one location for .env. Can we standardize on using the repo root (../.env
), which would also work out to the DFD root during deployments?
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.
That makes sense to me.
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.
it now only looks for '.env' as a sibling of 'cfgov'
cfgov/cfgov/wsgi.py
Outdated
] | ||
|
||
for candidate in environment_candidates: | ||
if os.path.exists(candidate): |
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.
What about when none of the candidates are found? Is that OK? In a Docker world, I'm guessing you wouldn't use a .env
file at all, and would just pass in envvars right to the container?
Perhaps a log statement saying which .env
file is being used, or none at all?
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.
now, instead of searching for candidates, it tries to read ../../env. If it isn't there, the dotenv library will issue a warning
cfgov/manage.py
Outdated
this_dir = os.path.dirname(os.path.abspath(__file__)) | ||
|
||
|
||
def initialize_environment(): |
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.
Same questions as in wsgi.py
.
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.
addressed above
docker/drama-free-django/_test.sh
Outdated
@@ -58,7 +60,8 @@ grep -Eho \ | |||
| xargs touch | |||
|
|||
# Now that we're sure that we have webfont files, we can test collectstatic. | |||
./venv/bin/django-admin collectstatic | |||
#./venv/bin/django-admin collectstatic |
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.
Probably don't need this commented out code here.
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.
fixed!
cfgov/cfgov/settings/base.py
Outdated
@@ -264,6 +265,11 @@ | |||
PROJECT_ROOT.child('templates', 'wagtailadmin') | |||
] | |||
|
|||
if 'DJANGO_STATICFILES_IN' in os.environ: | |||
pattern = os.path.join( | |||
os.environ['DJANGO_STATICFILES_IN'], |
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.
What's the argument over making this configurable vs. just hardcoding use of our current static.in
as the one place we always place these files? We already document this location, for example here.
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.
right now, I don't think the cfgov-refresh version of static.in gets included in the build artifact?
I guess we could make it relative, though-- it will always be a sibling to the cfgov directory.
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.
Is there any reason why not to modify the Jenkins build to use static.in? In my branch modifying the Jenkins job to use the Docker-based build (docker-dfd-build), I use that and it works well. We don't use it in the non-Docker-based build currently.
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 don't see a reason not to do that-- I think they just came about at different times, and for different reasons, and nobody ever connected the dots.
cfgov/cfgov/wsgi.py
Outdated
|
||
|
||
def initialize_environment(): | ||
environment_candidates = [ |
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.
Agree, it'd be nice to standardize on one location for .env. Can we standardize on using the repo root (../.env
), which would also work out to the DFD root during deployments?
cfgov/cfgov/wsgi.py
Outdated
|
||
for candidate in environment_candidates: | ||
if os.path.exists(candidate): | ||
dotenv.read_dotenv(candidate) |
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.
dotenv.read_dotenv(candidate) | |
dotenv.read_dotenv(candidate) |
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've removed that whole function
cfgov/cfgov/wsgi.py
Outdated
for candidate in environment_candidates: | ||
if os.path.exists(candidate): | ||
dotenv.read_dotenv(candidate) | ||
return |
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.
return | |
return |
I note your comment:
Would it make sense to push back loading of .env and instead alter this PR to load from environment.json, essentially pulling in this code from DFD? This would accomplish "stop using DFD at runtime" and allow us to proceed more incrementally, working as-is with the current Ansible code that generates environment.json files. In a subsequent PR (or multiple PRs) we could then further alter cfgov-refresh and the Ansible code to instead generate .env files. |
That's an interesting idea-- I've been pondering a different approach to breaking the dependencies (having ansible deploy both the json and the .env)-- but since this exists now and the ansible changes don't yet, your approach makes more sense. |
@chosak I just pushed an implementation of that |
@rosskarchner, thanks, I'll take another look at this PR. One thing: don't we need to make at least some Ansible changes before this can go live, e.g. setting the |
@chosak what do you think about changing this default, which I don't think we actually use anywhere (outside of Docker experiments, maybe) https://github.com/cfpb/cfgov-refresh/blob/master/cfgov/cfgov/settings/base.py#L244 |
@rosskarchner that seems sensible to me, you mean, to |
Yeah, that's what I meant |
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 notice that this logic in the sample .env file causes these warning messages to appear whenever you run a management command:
$ cfgov/manage.py shell
/Users/chosaka/.virtualenvs/cfgov-refresh/lib/python2.7/site-packages/dotenv.py:115: SyntaxWarning: Line 'if [ $(uname -s) = "Darwin" ]; then' doesn't match format
SyntaxWarning
/Users/chosaka/.virtualenvs/cfgov-refresh/lib/python2.7/site-packages/dotenv.py:115: SyntaxWarning: Line ' export DATABASE_URL=postgres://cfpb@localhost/cfgov' doesn't match format
SyntaxWarning
/Users/chosaka/.virtualenvs/cfgov-refresh/lib/python2.7/site-packages/dotenv.py:115: SyntaxWarning: Line ' export ES_HOST=localhost' doesn't match format
SyntaxWarning
/Users/chosaka/.virtualenvs/cfgov-refresh/lib/python2.7/site-packages/dotenv.py:115: SyntaxWarning: Line 'fi' doesn't match format
SyntaxWarning
This is only an annoyance but it sure feels like it could be a real annoyance for people running management commands constantly. Is there anything we can do about this?
cfgov/cfgov/settings/base.py
Outdated
@@ -264,6 +265,8 @@ | |||
PROJECT_ROOT.child('templates', 'wagtailadmin') | |||
] | |||
|
|||
static_in = REPOSITORY_ROOT.child('static.in') | |||
STATICFILES_DIRS += [str(d) for d in static_in.listdir(filter=DIRS)] |
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 you add this logic into the base settings, can you also remove this duplicative line from local settings?
cfgov/cfgov/wsgi.py
Outdated
environmentdotjson_path = os.path.join(this_dir, '../../environment.json') | ||
|
||
if os.path.exists(envfile_path): | ||
dotenv.read_dotenv(envfile_path) |
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.
Do we want to use override=True
here (see docs)? That would make the .env file override any existing variables already in the environment. I think we do want that behavior, and that's how environment.json works now.
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'd say I'm mildly uncomfortable with that-- when I read about it, it seemed like an elegant way to recognize that if a variable has been set through some other mechanism, it reflects somebody's intent.
That said, I don't feel too strongly. I'll go ahead and make the change.
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 think I found the reason not to use override=True: if .env takes precedence, then we can't set environment variables in docker-compose.
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 think I found the reason not to use override=True: if .env takes precedence, then we can't set environment variables in docker-compose.
docker-compose itself has an env_file
attribute, and it supports the same KEY=value
format as django-dotenv. So, maybe the better option for compose, is to not load the .env
file in-container, and let compose inject those envvars itself?
We'll have to do something similar in a production environment. We don't want to bake in env-specific .env
files at image build time, and we won't be able to map in a .env
at runtime, so the app will have to support just having those envvars already there at container start. I think that's fine in the current logic, since it doesn't fail if neither .env
nor environment.json
are present.
Also, is the plan to update .env_SAMPLE
to the KEY=value
style syntax? Or do we need it to be an actual shell script for other purposes?
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've removed override=True, so variables set via Docker, Linux, Compose, or tox will always take precedence.
cfgov/manage.py
Outdated
envfile_path = os.path.join(this_dir, '../.env') | ||
environmentdotjson_path = os.path.join(this_dir, '../environment.json') | ||
if os.path.exists(envfile_path): | ||
dotenv.read_dotenv(envfile_path) |
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.
See above comment re override=True
.
docker/drama-free-django/_test.sh
Outdated
@@ -45,6 +45,8 @@ export DJANGO_SETTINGS_MODULE=cfgov.settings.production | |||
# commands do nothing. | |||
mkdir -p static.in/0/fonts | |||
|
|||
export DJANGO_STATICFILES_IN=/tmp/current/static.in |
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.
Is this a legacy addition that can now be removed since we're using local static.in?
One other thought about this PR: if you were to remove these changes in _build.sh, and these changes in _test.sh, could this PR be merged as-is and have things continue to work using the existing master version of drama-free-django? Essentially, the variables would get loaded again, with no change. That'd let us move ahead with this change even while the DFD changes are still under review. Another thing: the docs [currently suggest using autoenv to load the variables, here and here. Can we change that if we want to move to auto-loading? |
Do you know what that's for? We could:
|
Yes. It's because when running using a local virtualenv, the database host and Elasticsearch host are both |
Those commands (specifically activate-virtualenv.sh) could just be moved into a separate file that gets invoked. I agree with andy that defaulting them to localhost is probably the right path |
One wrinkle: these changes don't help with That's kind of the reason my initial inclination was a seperate DFD pull request, just for adding the manage.py wrapper (that PR would need to be updated to use the runpy.run_path approach)
I think so? |
Hm. Well, frankly, the original thought behind adding the collectstatic call to _test.sh was because I wanted to test collectstatic on Travis (#5110). But because of some bugginess of that approach, and a hesitancy to add it as a potential blocker to all cfgov-refresh PRs, that got rolled back (#5119). So that code isn't being invoked by anything right now. So if it would make things simpler to just remove that call to collectstatic, maybe just for now, we could just do that here. I'll also take a look at your open DFD PR as well, of course. |
While chipping away at getting this working under mod_wsgi, I discovered that variables set via Apache's SetEnv were not available to the wsgi.py script. After tinkering with some work-arounds, I decide that a simpler solution was to just add a new, production WSGI file, that unambiguously sets DJANGO_SETTINGS_MODULE to cfgov.settings.production. Deployment will need to be updated to use cfgov/cfgov/production_wsgi.py. We are already working on changing that, since DFD will no longer include the current /current/wsgi.py |
use django-dotenv to load environment variables
Co-Authored-By: Andy Chosak <[email protected]>
Also, remove some redundencies.
b8d11fd
to
1122b4b
Compare
These changes compensate for the removal of the "runtime" customizations in Drama Free Django, proposed here. This means that cfgov-refresh needs to do a little more work:
Additions
Testing
docker/drama-free-django/build.sh && docker/drama-free-django/test.sh
should work as expectedTodos
Checklist
Testing checklist
Browsers
Accessibility
Other