Using devcontainers for NAV development

NAV provides a devcontainer definition to simplify the process of creating a complete environment for running and developing NAV. This should integrate smoothly with popular IDEs like PyCharm and VS Code. There are also command line tools to interact with devcontainers for those who prefer not to use IDEs for development, but we don’t yet have any experience with these.

What is provided by the NAV devcontainer

The devcontainer definition resides in the .devcontainer/ directory and uses Docker Compose to provide three containers:

  1. The main devcontainer, nav, which should be provisioned with all dependencies normally required to build and run NAV from source code.

  2. A PostgreSQL service container (db) to provide relational database services to NAV.

  3. A Graphite service container (graphite) to provide both the back-end (carbon) and front-end (graphite-web) components that provide time series database services to NAV.

Working efficiently with the nav devcontainer

Tools like PyCharm and VS Code should automatically detect the devcontainer definitions when you open the NAV project in them. They should typically prompt you and ask if you want to start the devcontainer and re-open the IDE inside it.

The devcontainer only provides an environment for development, it doesn’t do much magic in the background.

TL;DR

  1. Open a terminal inside the devcontainer. Issue these commands to start the web server:

    navsyncdb
    django-admin runserver
    
  2. Open a second terminal inside the devcontainer. Issue this command to start all NAV background processes:

    sudo nav start
    
  3. Open a third terminal inside the devcontainer. Issue this command to automatically build all CSS stylesheets when the SASS sources change:

    make sasswatch
    
  4. Open a fourth terminal inside the devcontainer. Issue this command to automatically build the HTML documentation output when the source file change:

    make docwatch
    

Python environment

The Python environment inside the devcontainer is a virtualenv located in /home/vscode/.venv, and the /home/vscode/.venv/bin/ directory is automatically pre-pended to the container’s PATH environment variable, so that any program inside this environment is available and automatically executed within said environment.

The environment is built at container startup by uv, using the uv sync --all-extras command. This ensures that all runtime requirements and development dependency groups mentioned in NAV’s pyproject.toml should be installed into the environment.

Using uv sync also ensures that all NAV command line programs are available on the PATH search path, and that changes you make to their source code is immediately reflected when running them. If you add new NAV command programs, however, you may need to run uv sync --all-extras over again, to ensure their stubs are installed in the environment’s bin/ directory.

Configuring NAV

At startup, the container installs all of NAV’s example configuration files into the /home/vscode/.venv/etc/nav/ directory. This can be confirmed at any time by issuing the nav config where command in a terminal inside the container.

NAV’s db.conf configuration file is automatically imbued with the options necessary to let NAV connect to the PostgreSQL server in the db container.

The container also provides common text editors like vim and nano, which should enable you to edit the configuration files if necessary.

Preparing the database schema

When you start the devcontainer for the first time, the database may be completely empty. You will need to run the navsyncdb command in order to initialize and/or migrate NAV’s database schema, before any NAV programs are usable within the container.

Running the NAV web interface

When developing, the NAV web interface is best served by the built-in Django development web server, using this command in a terminal: django-admin runserver.

This server will serve on port 8000 inside the container. After running this command, your IDE may prompt you to forward this port to your host machine, so you will be able to browse the web site from your desktop browser (in some cases, it may automatically forward port 8000 also to your localhost).

Logging in to the NAV web interface

The admin user ships with the default password admin. If you need to test with unprivileged users, more can be added using the User and API Administration tool in the toolbox.

User accounts and passwords can also be manipulated on the command line using the navuser program (see navuser usage docs for details).

Running NAV programs

NAV command line programs (those specified by the project.scripts section of pyproject.toml) are all available on PATH and can be run directly if need be. The nav process control command is also available, so that all background daemons and cron jobs can be started by issuing the sudo nav start command.

During certain development tasks, it may be preferable to manually run specific daemon programs in the foreground rather than using the nav command, e.g. ipdevpolld -f -s instead of nav start ipdevpolld.

(Re)building CSS stylesheets from SASS sources

If you make changes to the SASS definitions, you will have to execute make sassbuild to rebuild the CSS assets that are served by the web server.

More effectively, you may want to use the make sasswatch command, which will monitor all the SASS source files for changes and automatically rebuild the stylesheets on every change.

(Re)building NAV’s Sphinx documentation

NAV’s documentation sources reside in the doc/ directory. These can be manually built into HTML using the make doc command. The output directory is automatically served by the Django development web server on the /doc/ URI.

More effectively, you may want to use the make docwatch command, which will monitor all the documentation source files for changes and automatically rebuild the HTML output on every change.

Installing Python packages manually

If you want to install extra Python packages that are not specified in pyproject.toml, use uv pip install package_name to do so.

Please be aware, though, that these packages will potentially be removed any time uv sync is rerun. If a package is a new runtime dependency for code you’re working on, it should be added to the project.dependencies list of pyproject.toml ASAP. If it’s a development tool that is nice or necessary to have, it should be added to the relevant dependency groups in the dependency-groups section of pyproject.toml.

Dumping/loading data from remote production server

For some development tasks, it is useful to initialize the development database with a database snapshot from a production server. You can read more about Migrating a production database to a development environment.

PyCharm oddities

PyCharm seems to have problems with properly detecting the correct Python interpreter when running inside the devcontainer. When started, it lists the project as having no interpreter, and the only way to fix it is to manually select an existing interpreter (specifically, /home/vscode/.venv/bin/python). Unfortunately, this choice does not seem to be persisted anywhere, so every time PyCharm is re-opened inside the container, this interpreter selection procedure needs to be repeated.