Skip to content

Commit

Permalink
Merge pull request #528 from GovReady/dockertweaks
Browse files Browse the repository at this point in the history
various Docker improvements
  • Loading branch information
gregelin committed Jun 28, 2018
2 parents 36b606f + 6706c16 commit 11434c6
Show file tree
Hide file tree
Showing 9 changed files with 88 additions and 19 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,17 @@ GovReady-Q Release Notes
In Development
--------------

Application changes:

* Javascript and CSS static assets of compliance apps may have had the wrong MIME type set.

Deployment changes:

* The HTTP Content-Security-Policy header is now set to prevent the loading of third-party assets.
* A CentOS 7-based Vagrantfile has been added to the source distribution for those looking to deploy using a VM.
* Added some outputs to Docker launches to see the Q version and the container user during build and at the very start of container startup.
* We're now publishing version tags to Docker Hub so that past versions of GovReady-Q remain available when we publish a new release.
* With Docker, email environment variable settings were ignored since the last (-rc3) release.

Developer changes:

Expand Down
1 change: 1 addition & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ RUN mkdir -p /mnt/apps
RUN groupadd application && \
useradd -g application -d /home/application -s /sbin/nologin -c "application process" application && \
chown -R application:application /home/application
RUN echo -n "the non-root user is: " && grep ^application /etc/passwd

# Give the non-root user access to scratch space.
RUN mkdir -p local
Expand Down
8 changes: 7 additions & 1 deletion deployment/docker/docker_image_build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,15 @@ cat VERSION
echo

# Build the image.
docker image build --tag govready/govready-q:${TAG-latest} .
docker image build --tag govready/govready-q:$VERSION .
rm -f VERSION # it's for Docker only

# Show push commands.
echo
echo "To publish, run:"
echo "docker image push govready/govready-q:$VERSION"
echo "docker image tag govready/govready-q:$VERSION govready/govready-q:latest && docker image push govready/govready-q:latest"

# Show warning again.
if [ $WARNINGS -gt 0 ]; then
echo
Expand Down
28 changes: 27 additions & 1 deletion deployment/docker/dockerfile_exec.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,32 @@

set -euf -o pipefail # abort script on error

# Show the version immediately, which might help diagnose problems
# from console output.
echo "This is GovReady-Q."
cat VERSION

# Show filesystem information because the root filesystem might be
# read-only and other paths might be mounted with tmpfs and that's
# helpful to know for debugging.
echo
echo Filesystem information:
cat /proc/mounts | egrep -v "^proc|^cgroup| /proc| /dev| /sys"
echo

# Check that we're running as the 'application' user. Our Dockerfile
# specifies to run containers as that user. But cluster environments
# can override the start user and might do so to enforce running as
# a non-root user, so this process might have started up as the wrong
# user.
if [ "$(whoami)" != "application" ]; then
echo "The container is running as the wrong UNIX user."
id
echo "Should be:"
id application
echo
fi

# What's the address (and port, if not 80) that end users
# will access the site at? If the HOST and PORT environment
# variables are set (and PORT is not 80), take the values
Expand Down Expand Up @@ -62,7 +88,7 @@ if [ ! -z "${BRANDING-}" ]; then
fi

# Write out the settings that indicate where we think the site is running at.
echo "Starting GovReady-Q at ${ADDRESS} with HTTPS ${HTTPS-false}."
echo "Starting at ${ADDRESS} with HTTPS ${HTTPS-false}."

# Run checks.
python3.6 manage.py check --deploy
Expand Down
8 changes: 6 additions & 2 deletions docs/source/deploy_docker.md
Original file line number Diff line number Diff line change
Expand Up @@ -207,9 +207,13 @@ The container's console, which can be accessed with

docker container logs govready-q

shows the output of container's start-up commands including database migrations and process startup. Additional log files are stored in /var/log (in particular, /var/log/supervisor) within the container. A special management command can be used to follow the log files:
shows the output of container's start-up commands including database migrations and process startup.

docker container exec govready-q tail_logs -f
Additional log files are stored in /var/log within the container. These files contain access logs and other program output, including logs for unhandled error messages that appear as 500 Internal Server Error pages to end users. A special management command can be used to see the log files:

docker container exec govready-q tail_logs

`tail_logs` takes the same arguments as Unix `tail`. For instance, add `-n 1000` to see the most recent 1,000 log lines, or add `-f` to continue to output the logs as the log files grow.

The log files can also be accessed by mounting `/var/log` with a Docker bind-mount or as a volume (and that's the only way to see the logs if `docker container exec` cannot be used in your environment).

Expand Down
11 changes: 11 additions & 0 deletions guidedmodules/module_sources.py
Original file line number Diff line number Diff line change
Expand Up @@ -991,4 +991,15 @@ def load_module_assets_into_database(app):
# Add to the pack.
pack.assets.add(asset)

mime_types = {
"css": "text/css",
"js": "text/javascript",
}
mime_type = mime_types.get(file_path.rsplit(".", 1)[-1])
if mime_type:
from dbstorage.models import StoredFile
StoredFile.objects\
.filter(path=asset.file.name)\
.update(mime_type=mime_type)

return pack
5 changes: 5 additions & 0 deletions guidedmodules/validate_module_specification.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ def __str__(self):
return self.context + ": " + self.message

def validate_module(spec, is_authoring_tool=False):
# The module must have a title.
for field in ("title",):
if field not in spec:
raise ValidationError("module specification", "Missing '%s' field." % field)

# Validate that the introduction and output documents are renderable.
if "introduction" in spec:
if not isinstance(spec["introduction"], dict):
Expand Down
34 changes: 19 additions & 15 deletions siteapp/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -362,15 +362,9 @@ def apps_catalog_item(request, source_slug, app_name):
else:
raise Http404()

if request.method == "GET":
# Show the "app" page.
error = None

return render(request, "app-store-item.html", {
"first": not ProjectMembership.objects.filter(user=request.user, project__organization=request.organization).exists(),
"app": app_catalog_info,
})

else:
if request.method == "POST":
# Start the app.

if not request.GET.get("q"):
Expand Down Expand Up @@ -401,15 +395,25 @@ def apps_catalog_item(request, source_slug, app_name):
if not app_satifies_interface(app_catalog_info, q):
raise ValueError("Invalid protocol.")

project = start_app(app_catalog_info, request.organization, request.user, folder, task, q)
from guidedmodules.module_sources import ValidationError
try:
project = start_app(app_catalog_info, request.organization, request.user, folder, task, q)
except ValidationError as e:
error = str(e)
else:
if task and q:
# Redirect to the task containing the question that was just answered.
from urllib.parse import urlencode
return HttpResponseRedirect(task.get_absolute_url() + "#" + urlencode({ "q": q.key, "t": project.root_task.id }))

if task and q:
# Redirect to the task containing the question that was just answered.
from urllib.parse import urlencode
return HttpResponseRedirect(task.get_absolute_url() + "#" + urlencode({ "q": q.key, "t": project.root_task.id }))
# Redirect to the new project.
return HttpResponseRedirect(project.get_absolute_url())

# Redirect to the new project.
return HttpResponseRedirect(project.get_absolute_url())
# Show the "app" page.
return render(request, "app-store-item.html", {
"app": app_catalog_info,
"error": error,
})


def start_app(app_catalog_info, organization, user, folder, task, q):
Expand Down
5 changes: 5 additions & 0 deletions templates/app-store-item.html
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@
<div class="row">
<div class="col-sm-9 col-sm-push-3">
<h1><small>{{app.vendor}}</small><br/>{{app.title}}</h1>

{% if error %}
<p class="text-danger">{{error}}</p>
{% endif %}

<div class="body">
{{app.description.long|safe}}
</div>
Expand Down

0 comments on commit 11434c6

Please sign in to comment.