jason-neal / cloud_dev_code_test

Coding test for cloud developer role.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Cloud Code test

This code test is to just fill the blanks of this rather simple (and mostly inane) questionnaire app.

The app is a Django application with 3 views (index, questionnaire and results), running in an Alpine linux container, with Gunicorn as the web server running Django, and just using the default sqlite3 database.

App views:

Index Page

Index page

The index page shows the total number of questionnaires filled, and provides links to the questionnaire and the results.

Questionnaire Page

Questionnaire page

The questionnaire page is a simple web form that POSTs to the view, and is saved in the database.

The question it asks: What is your favourite month, and your favourite day of the week.

Results Page

Results page

The results page will show the following stats about the filled questionnaires:

  • The count of each month picked and what percent from the total that is.
  • The count of each day picked and what percent from the total that is.
  • The most chosen day, based on which month was picked (see picture)
    • e.g. of the people who all liked May, which day did they pick the most often.

Your Tasks

Fill in the blanks

Finish the docker file

The docker file is missing some keep pieces to work (see the TODO notes).

After getting this file done, you should be able to run the docker commands as listed below in the development section, but you'll run into a problem that the next task will solve.

Finish the startup_check.py file

We're missing the part that tells us which migrations need to be run. Find the TODO and fill the missing logic.

Make the database model for the FilledQuestionnaire

Use the Django ORM to define a database model for the FilledQuestionnaires two questions. How you define this model, and how you store the data will affect on how you can process that data later into the results view.

You will also need to make the migration files for this, either using the method as described further down in this read me, or another way.

Build the Questionnaire View

This will be a view that asks for the month, and the day as drops downs in a form. A form POST to the view will save the data into the database model you made earlier.

This view should redirect back to the index when a questionnaire is POSTed and saved.

Make the index view count and display the number of FilledQuestionnaires

Query for the number items in the database, and add that to the context.

Build the results view

This view will need to query for the saved FilledQuestionnaire entries, then do some basic calculations, put the data into some useful collection structures, and the use that context data when rendering the Django template.

Answer some questions

Explain how the config for this app works, and why when using docker compose might this be a good way to configure rather than a config file

Currently the config for the app needs to be passed in on the command line when starting the container with docker run. the -p parameter configures or links the port from the container to the host to enable the app to be accessed from the host. The -v option configures a volume (folder) location on the host to mount the container so that the files (code and data) can be shared between the container and host. One feature of this allows for changes in the code to be immediately realized in the container, allowing for faster app development. The container to run is also specified, in this case local/cloud_test.

Docker compose allows for these configuration values such as port and volume to be stored in docker-compose.yml, without the need to continually type them in the terminal. It also allows for the configuration of multiple containers together, linking any dependencies or interaction, and setting the startup order.

Explain why the startup_check.py file exists and what it does

The startup_check.py exists to configure, prepare, and check django app before it is started. It runs several django management tasks for the app, retrying the steps multiple times if needed.

It checks if database migrations are needed, either for the first time or due to changes in the django models. It locks the database while the migrations are occurring to prevent other process from accessing the database at the same time. It configures the admin superuser with username and password. It also collects together the static files for the app.

Only if startup_check.py runs without fail does the app actually get started.

Explain what the entrypoint.sh file does

entrypoint.sh is the script that is run when docker run local/cloud_test is executed. If extra parameters are passed after the repo name i.e. docker run local/cloud_test param1 param2. The entrypoint.sh script is called with these as entrypoint.sh param1 param2.

entrypoint.sh checks the values of the parameter flags. If the --django-manage or --manage-shell flags are used they allow for configuring the django settings through djangos manage.py.

If --start-service or --hot-reload flags are given then the startup_check.py script is run. If the checks succeeds without failure then Gunicorn is started (with auto-reloading for the --hot-reload flag.)

This allows for different configurations easily from the docker run command.

Testing and evaluation

We will build and run the code as follows:

docker build -t local/cloud_test .
docker run -it --rm -p 8000:8000 --name test_site local/cloud_test

Which will build a clean container for us, and then run it.

We will also be looking through your code, and your commits. Try to commit as you get segments working, or some more changes through rather than one single final commit.

Development environment

Here are some useful things to know about how this app works, or what kind of things to do via the development environment for it.

All docker commands below are run from the root of the repo.

Build docker container

You only need to build/rebuild the container when you change requirements.

docker build -t local/cloud_test .

Run docker container for development

If you have an existing sqlite database, or media files folder, you should place those in the cloud_test_app folder if you want them to be used.

For development you will want to mount all the app files, so that any changes to them are reflected in the running site:

docker run -it --rm -p 8000:8000 --name test_site \
  -v $(pwd)/cloud_test_app:/opt/cloud_test_app \
  local/cloud_test --hot-reload

The --hot-reload directive is passed to Gunicorn, and tells it to reload when code changes.

You can now access the site at http://localhost:8000/ and login to the django admin (if you need or want to) as admin with the password adminpass.

Creating migration files

When you change the python code and need to create new migrations (or check if new ones are needed), you'll want to run the makemigrations command through the docker container environment.

Once you have a local container built, all you need to do is run the following command from the repo root folder:

docker run -it --rm -p 8000:8000 --name test_site \
  -v $(pwd)/cloud_test_app:/opt/cloud_test_app \
  local/cloud_test \
  --django-manage makemigrations

Note: These migrations files will be owned by 'root' because they were created within the scope of the container (using the container's root user). You may want to chown them (or your whole repo folder), but git doesn't really seem to mind, but if you notice any odd permissions issues around these files, this may be why.

Startup checks

To facilitate easier upgrades and container rollovers we wanted each container to be safe to start up on it's own, and attempt to handle new migrations (if needed) and collection of static files.

The code for this is located in this same folder as startup_check.py.

This is run on every container start up and simply ensures that the database is in the state the container needs it to be to run.

Config

Django configuration

# via environment variables:
/opt/cloud_test_app/cloud_test/settings/config.py
# or settings override:
/opt/cloud_test_app/cloud_test/settings/local.py

local.py takes priority over config.py for any overridden variables.

See cloud_test_app/cloud_test/settings/config.py and the documentation therein on how to configure the service with environmental variables. See cloud_test_app/cloud_test/settings/local.py.sample for an example of a local.py file.

Gunicorn configuration

/etc/cloud_test/conf.py

Details for the setting options are here: http://docs.gunicorn.org/en/stable/settings.html

Libraries we are using

Django Bootstrap 4

A useful and simple library for some bootstrap html setup in the templates.

See more: https://django-bootstrap4.readthedocs.io/en/latest/

Django Database Locking

For our startup checks we needed a locking mechanism, and rather than writing our own we're using this existing library.

See more: https://github.com/vikingco/django-db-locking/

About

Coding test for cloud developer role.


Languages

Language:Python 86.1%Language:HTML 9.6%Language:Shell 4.1%Language:CSS 0.1%