diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 000000000..461f6a63c --- /dev/null +++ b/.dockerignore @@ -0,0 +1,26 @@ +# Docker related +environments/Dockerfile +environments/docker-compose*.yml +environments/*.env +*.env + +# Python +**/*.pyc +**/*.pyo +**/__pycache__/ +**/.pytest_cache/ +**/.venv/ + + +# Other +docs/_build +FAQ.md +.git/ +.gitignore +.github +tasks.py +LICENSE +**/*.log +**/.vscode/ +invoke*.yml +tasks.py diff --git a/.gitignore b/.gitignore index acd5d035b..b1475bb5e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,9 @@ +# Ansible Retry Files +*.retry + +# Swap files +*.swp + # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] @@ -132,4 +138,169 @@ certs/nginx-selfsigned.crt certs/nginx-selfsigned.key # Override URLs -*override.yml \ No newline at end of file +*override.yml + +### macOS ### +# General +.DS_Store +.AppleDouble +.LSOverride + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### Windows ### +# Windows thumbnail cache files +Thumbs.db +Thumbs.db:encryptable +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +### PyCharm ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### PyCharm Patch ### +# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 + +# *.iml +# modules.xml +# .idea/misc.xml +# *.ipr + +# Sonarlint plugin +# https://plugins.jetbrains.com/plugin/7973-sonarlint +.idea/**/sonarlint/ + +# SonarQube Plugin +# https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin +.idea/**/sonarIssues.xml + +# Markdown Navigator plugin +# https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced +.idea/**/markdown-navigator.xml +.idea/**/markdown-navigator-enh.xml +.idea/**/markdown-navigator/ + +# Cache file creation bug +# See https://youtrack.jetbrains.com/issue/JBR-2257 +.idea/$CACHE_FILE$ + +# CodeStream plugin +# https://plugins.jetbrains.com/plugin/12206-codestream +.idea/codestream.xml + +### vscode ### +.vscode/* +*.code-workspace + +# Rando +creds.env + + +# Invoke overrides +invoke.yml \ No newline at end of file diff --git a/Dockerfile-LDAP b/Dockerfile-LDAP deleted file mode 100644 index 4f7211694..000000000 --- a/Dockerfile-LDAP +++ /dev/null @@ -1,33 +0,0 @@ -ARG PYTHON_VER=3.9 - -ARG NAUTOBOT_VERSION=1.5.9 - -FROM networktocode/nautobot:${NAUTOBOT_VERSION}-py${PYTHON_VER} as base - -USER 0 -RUN apt-get update -y && apt-get install -y libldap2-dev libsasl2-dev libssl-dev - -# --------------------------------- -# Stage: Builder -# --------------------------------- -FROM base as builder - -RUN apt-get install -y gcc && \ - apt-get autoremove -y && \ - apt-get clean all && \ - rm -rf /var/lib/apt/lists/* - -RUN pip3 install --upgrade pip wheel && pip3 install django-auth-ldap - -# --------------------------------- -# Stage: Final -# --------------------------------- -FROM base as final -ARG PYTHON_VER -USER 0 - -COPY --from=builder /usr/local/lib/python${PYTHON_VER}/site-packages /usr/local/lib/python${PYTHON_VER}/site-packages -COPY --from=builder /usr/local/bin /usr/local/bin -USER nautobot - -WORKDIR /opt/nautobot diff --git a/README.md b/README.md index 84573fd1f..b73796d23 100644 --- a/README.md +++ b/README.md @@ -4,83 +4,189 @@ Network to Code has an existing published Nautobot Docker Image on Docker Hub. S ![Container Stack](docs/img/container_stack.png) -By default, this project deploys the Nautobot application, a single worker container, Redis containers, and PostgresQL. It does not deploy NGINX, SSL, or any Nautobot plugins. However, the project is extensible to allow users to tailor to their specific requirements. For example, if you need to deploy [SSL](docs/create_ssl_cert.md) or [plugins](docs/plugins.md), see the docs linked. The web server used on the application is [pyuwsgi](https://uwsgi-docs.readthedocs.io/en/latest/). +By default, this project deploys the Nautobot application, a single worker container, Redis containers, and PostgreSQL. It does not deploy NGINX, SSL, or any Nautobot plugins. However, the project is extensible to allow users to tailor it to their specific requirements. For example, if you need to deploy [SSL](docs/create_ssl_cert.md) or [plugins](docs/plugins.md), see the docs linked. The web server used on the application is [pyuwsgi](https://uwsgi-docs.readthedocs.io/en/latest/). +## Docker Compose -## Environment Variable Controls +This documentation is now written assuming the latest Docker Compose methodology of using the Docker Compose Plugin instead of the independent docker-compose executable. See the [Docker Compose Plugin installation notes](https://docs.docker.com/compose/install/) -There are two variables that should be set for the Docker-Compose file. The following table covers the environment variables, default setting, and what it does. +## Why Poetry? -| Environment Variable | Default | Notes | -| -------------------- | ------- | -------------------------------------------------------------------------------------------- | -| PYTHON_VER | 3.9 | This sets the Python version within the container version. 3.6 - 3.9 are initially supported | -| NAUTOBOT_IMAGE | 1.5.9 | The version of Nautobot to use in the container image | +Poetry was chosen to replace both **requirements.txt** and **setup.py**. Poetry uses the `pyproject.toml` file to define package details, main package dependencies, development dependencies, and tool-related configurations. Poetry resolves dependencies and stores the hashes and metadata within the `poetry.lock` file (similar to performing a `pip freeze > requirements.txt`). The `poetry.lock` is what is used to provide consistency for package versions across the project to make sure anyone who is developing on it is using the same Python dependency versions. Poetry also provides virtual environments by simply being in the same directory as the `pyproject.toml` and `poetry.lock` files and executing the `poetry shell` command. -## NOTE - Celery Worker +## Why Invoke? -This docker-compose includes the Celery worker that was introduced with Nautobot 1.1.0. Please comment out or remove the celery worker in the `docker-compose.yml` if you are using a pre-1.1.0 release. +Invoke is a Python replacement for Make. Invoke looks for a `tasks.py` file that contains functions decorated by `@task` that provide the equivalents of **Make targets**. -## NOTE - MySQL +The reason it was chosen over Makefile was due to our collective familiarity with Python and the ability to organize and re-use Invoke tasks across Cookiecutter templates. It also makes managing your Nautobot project vastly simpler by issuing simple commands instead of long command strings that can be confusing. -This documentation is now written assuming the latest Docker Compose methodology of using the Docker Compose Plugin instead of the independent docker-compose executable. See the [Docker Compose Plugin installation notes](https://docs.docker.com/compose/install/) -If you want to use MySQL for the database instead of postgres, In step 7 below instead use +## How to use this repo -``` -docker compose -f docker-compose.yml -f docker-compose.mysql.yml up +This repo is designed to provide a custom build of Nautobot to include a set of plugins which can then be used in a development environment or deployed in production. Included in this repo is a skeleton Nautobot plugin which is designed only to provide a quick example of how a plugin could be developed. Plugins should ultimately be built as packages, published to a PyPI style repository and added to the poetry `pyproject.toml` in this repo. The plugin code should be hosted in their own repositories with their own CI pipelines and not included here. + +## Install Docker + +Before beginning, install Docker and verify its operation by running `docker run hello-world`. If you encounter any issues connecting to the Docker service, check that your local user account is permitted to run Docker. **Note:** `docker` v1.10.0 or later is required. + +## Install Poetry + +It is recommended to follow one of the [installation methods detailed in their documentation](https://python-poetry.org/docs/#installation). It's advised to install poetry as a system-level dependency and not inside a virtual environment. Once Poetry has been installed you can create the Poetry virtual environment with a few simple commands: + +1. `poetry shell` +2. `poetry lock` +3. `poetry install` + +The last command, `poetry install`, will install all of the project dependencies for you to manage your Nautobot project. This includes installing the `invoke` Python project. + +## Build and start Nautobot + +You can build, deploy and populate Nautobot with the following steps + +1. `invoke build` +2. `invoke start` or `invoke debug` + +> The standard way of starting the containers is to use `invoke start`. If you wish to see the logs from the containers while running Nautobot use the `invoke debug` command. Be aware that exiting debug mode will stop all the containers. + +Nautobot will be available on port 8080 locally http://localhost:8080 + +## Cleanup Everything and start from scratch + +1. `invoke destroy` +2. `invoke build` +3. `invoke db-import` +4. `invoke start` + +> The `invoke db-import` command will only work if you have a previous backup of your database. + +## Export current database + +While the database is already running + +* `invoke db-export` + +### Docker Compose Files + +Several Docker Compose files are provided as [overrides](https://docs.docker.com/compose/extends/) to allow for various development configurations, these can be thought of as layers to Docker Compose, each Compose file is described below: + +* `docker-compose.postgres.yml` - Starts the prerequisite PostgreSQL service if using PostgreSQL as your database. +* `docker-compose.mysql.yml` - Starts the prerequisite MySQL service if using MySQL as your database is desired. +* `docker-compose.base.yml` - Defines the default Nautobot, Celery worker, Celery beats scheduler, and Redis services and how they should be run and built. +* `docker-compose.ldap.yml` - Duplicate of `docker-compose.base.yml` file but points to LDAP-specific Dockerfile. This is done to make building an LDAP-supported installation easier. +* `docker-compose.local.yml` - Defines how the Nautobot and Celery worker containers should run locally with port mappings and volume mounts. This is helpful as an example when you wish to create another instance, for example, a production instance, and you want to have the volume mounts and port mappings done differently. + +> Only `docker-compose.postgres.yml` or `docker-compose.mysql.com` should be used as they are mutually exclusive and providing the same database backend service. + +### Environment Files + +Environment files (.env) are the standard way of providing configuration information or secrets in Docker containers. This project includes two example environment files that each serve a specific purpose: + +* `local.example.env` - The local environment file is intended to store all relevant configurations that are safe to be stored in git. This would typically be things like specifying the database user or whether debug is enabled or not. Do not store secrets, ie passwords or tokens, in this file! + +* `creds.example.env` - The creds environment file is intended to store all configuration information that you wish to keep out of git. The `creds.env` file is in `.gitignore` and thus will not be pushed to git by default. This is essential to keep passwords and tokens from being leaked accidentally. + +To use the provided environment files it's suggested that you copy the file to the same name without the `example` keyword, ie: + +```bash +cp environments/local.example.env environments/local.env +cp environments/creds.example.env environments/creds.env ``` -## Docker Compose +## CLI Helper Commands + +The project comes with a CLI helper based on [invoke](http://www.pyinvoke.org/) to help manage the Nautobot environment. The commands are listed below in 2 categories `environment` and `utility`. + +Each command can be executed with a simple `invoke `. Each command also has its own help `invoke --help`. -The provided Docker Compose makes use of environment variables to control what is to be used. This is tightly coupled with the Docker image that is provided on Docker Hub. +### Manage Nautobot environment -## Getting Started - Plugins +```bash + build Build all docker images. + debug Start Nautobot and its dependencies in debug mode. + destroy Destroy all containers and volumes. + start Start Nautobot and its dependencies in detached mode. + stop Stop Nautobot and its dependencies. + db-export Export Database data to nautobot_backup.dump. + db-import Import test data. +``` + +### Utility -The installation of plugins has a slightly more involved getting started process. See see the [Plugin documentation.](docs/plugins.md). +```bash + cli Launch a bash shell inside the running Nautobot container. + migrate Run database migrations in Django. + nbshell Launch a nbshell session. +``` ## Getting Started -1. Have [Docker](https://docs.docker.com/get-docker/) and [Docker Compose](https://docs.docker.com/compose/install/) installed on the host +> **NOTE**: Please be aware that you must be in the Poetry virtual environment before issuing any invoke commands. The steps to do this are detailed above. + +1. Have [Docker](https://docs.docker.com/get-docker/) installed on the host. 2. Clone this repository to your Nautobot host into the current user directory. -``` +```bash git clone https://github.com/nautobot/nautobot-docker-compose.git ``` -3. Navigate to the new directory from the git clone +3. Navigate to the new directory from the git clone. -``` +```bash cd nautobot-docker-compose ``` -4. Copy `local.env.example` to `local.env` +4. Copy the `local.env.example` file to `local.env` and `creds.example.env` file to `creds.env` in the environments folder. -``` -cp local.env.example local.env +```bash +cp environments/local.example.env environments/local.env +cp environments/creds.example.env environments/creds.env ``` -5. Update the `.env` file for your environment. **THESE SHOULD BE CHANGED** for proper security! +5. Update the `.env` files for your environment. **THESE SHOULD BE CHANGED** for proper security and the `creds.env` file should never be synchronized to git as it should contain all secrets for the environment! -``` -vi local.env +```bash +vi environments/local.env +vi environments/creds.env ``` -6. Update the `.env` to be only available for the current user +6. Update the `local.env` and `creds.env` files to be only available for the current user. +```bash +chmod 0600 environments/local.env environments/creds.env ``` -chmod 0600 local.env + +7. Copy the `invoke.example.yml` file to `invoke.yml`: + +```bash +cp invoke.example.yml invoke.yml ``` -7. Run `docker-compose up` to start the environment +8. Run `invoke build start` to build the containers and start the environment. +```bash +invoke build start ``` -docker-compose up + +### NOTE - MySQL + +If you want to use MySQL for the database instead of PostgreSQL, perform the below step in place for step #7 above: + +```bash +cp invoke.mysql.yml invoke.yml ``` +### Getting Started - LDAP + +The use of LDAP requires the installation of some additional libraries and some configuration in `nautobot_config.py`. See the [LDAP documentation](docs/ldap.md). + +### Getting Started - Plugins + +The installation of plugins has a slightly more involved getting-started process. See the [Plugin documentation](docs/plugins.md). + ## Super User Account ### Create Super User via Environment -The Docker container has a Docker entrypoint script that allows you to create a super user by the usage of Environment variables. This can be done by updating the example `.env` file environment option of `NAUTOBOT_CREATE_SUPERUSER` to `True`. This will then use the information supplied to create the super user. +The Docker container has a Docker entry point script that allows you to create a super user by the usage of Environment variables. This can be done by updating the `creds.env` file environment option of `NAUTOBOT_CREATE_SUPERUSER` to `True`. This will then use the information supplied to create the specified superuser. ### Create Super User via Container @@ -88,40 +194,31 @@ After the containers have started: 1. Verify the containers are running: -``` +```bash docker container ls ``` Example Output: -``` +```bash ❯ docker container ls CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES -143f10daa229 networktocode/nautobot:latest "nautobot-server rqw…" 2 minutes ago Up 2 minutes (healthy) nautobot-docker-compose_nautobot-worker_1 +143f10daa229 networktocode/nautobot:latest "nautobot-server rqw…" 2 minutes ago Up 2 minutes (healthy) nautobot-docker-compose_celery_worker_1 bb29124d7acb networktocode/nautobot:latest "/docker-entrypoint.…" 2 minutes ago Up 2 minutes (healthy) 0.0.0.0:8080->8080/tcp, :::8080->8080/tcp, 0.0.0.0:8443->8443/tcp, :::8443->8443/tcp nautobot-docker-compose_nautobot_1 -ad57ac1749b3 redis:alpine "docker-entrypoint.s…" 2 minutes ago Up 2 minutes 6379/tcp nautobot-docker-compose_redis-queue_1 +ad57ac1749b3 redis:alpine "docker-entrypoint.s…" 2 minutes ago Up 2 minutes 6379/tcp nautobot-docker-compose_redis_1 5ab83264e6fe postgres:10 "docker-entrypoint.s…" 2 minutes ago Up 2 minutes 5432/tcp nautobot-docker-compose_postgres_1 -a9ec61ce5e30 redis:alpine "docker-entrypoint.s…" 2 minutes ago Up 2 minutes 6379/tcp nautobot-docker-compose_redis-cacheops_1 -a84a89169300 76e40881ecc6 "docker-entrypoint.s…" 5 weeks ago Up 5 hours 5432/tcp nautobot_plugin_chatops_ansible_postgres_1 -60ef800be813 redis:5-alpine "docker-entrypoint.s…" 5 weeks ago Up 5 hours 6379/tcp nautobot_plugin_chatops_ansible_redis_1 ``` -2. Enter the bash shell for the `nautobot-docker-compose_nautobot_1` container as indicated by the name in the last column for the Nautobot container that has ports listed +2. Execute Create Super User Command and follow the prompts -``` -docker exec -it nautobot-docker-compose_nautobot_1 bash -``` - -3. Execute Create Super User Command and follow the prompts - -``` -nautobot-server createsuperuser +```bash +invoke createsuperuser ``` Example Prompts: -``` -nautobot@bb29124d7acb:~$ nautobot-server createsuperuser +```bash +nautobot@bb29124d7acb:~$ invoke createsuperuser Username: administrator Email address: Password: diff --git a/config/nautobot_config.py b/config/nautobot_config.py new file mode 100644 index 000000000..6b7cea97f --- /dev/null +++ b/config/nautobot_config.py @@ -0,0 +1,43 @@ +"""Nautobot development configuration file.""" + +# pylint: disable=invalid-envvar-default +import os +import sys + +from nautobot.core.settings import * # noqa: F403 # pylint: disable=wildcard-import,unused-wildcard-import +from nautobot.core.settings_funcs import parse_redis_connection, is_truthy + +# +# Debug +# + +DEBUG = is_truthy(os.getenv("NAUTOBOT_DEBUG", False)) + +TESTING = len(sys.argv) > 1 and sys.argv[1] == "test" + +# +# Logging +# + +LOG_LEVEL = "DEBUG" if DEBUG else "INFO" + +# +# Redis +# + +# Redis Cacheops +CACHEOPS_REDIS = parse_redis_connection(redis_database=1) + +# +# Celery settings are not defined here because they can be overloaded with +# environment variables. By default they use `CACHES["default"]["LOCATION"]`. +# + +# Enable installed plugins. Add the name of each plugin to the list. +PLUGINS = ["nautobot_example_plugin"] + +# Plugins configuration settings. These settings are used by various plugins that the user may have installed. +# Each key in the dictionary is the name of an installed plugin and its value is a dictionary of settings. +PLUGINS_CONFIG = { + "nautobot_example_plugin": {}, +} diff --git a/config/nautobot_config.py.ldap b/config/nautobot_config.py.ldap index 1703fa74d..6ddfd11bc 100644 --- a/config/nautobot_config.py.ldap +++ b/config/nautobot_config.py.ldap @@ -1,84 +1,53 @@ +"""Nautobot development configuration file.""" +# pylint: disable=invalid-envvar-default import os import sys -from nautobot.core.settings import * # noqa F401,F403 -from nautobot.core.settings_funcs import is_truthy +from nautobot.core.settings import * # noqa: F403 # pylint: disable=wildcard-import,unused-wildcard-import +from nautobot.core.settings_funcs import parse_redis_connection, is_truthy -######################### -# # -# Required settings # -# # -######################### -# This is a list of valid fully-qualified domain names (FQDNs) for the Nautobot server. Nautobot will not permit write -# access to the server via any other hostnames. The first FQDN in the list will be treated as the preferred name. # -# Example: ALLOWED_HOSTS = ['nautobot.example.com', 'nautobot.internal.local'] -ALLOWED_HOSTS = os.getenv("NAUTOBOT_ALLOWED_HOSTS").split(",") - -# PostgreSQL database configuration. See the Django documentation for a complete list of available parameters: -# https://docs.djangoproject.com/en/stable/ref/settings/#databases -DATABASES = { - "default": { - "NAME": os.getenv("NAUTOBOT_DB_NAME", "nautobot"), # Database name - "USER": os.getenv("NAUTOBOT_DB_USER", ""), # Database username - "PASSWORD": os.getenv("NAUTOBOT_DB_PASSWORD", ""), # Database password - "HOST": os.getenv("NAUTOBOT_DB_HOST", "localhost"), # Database server - "PORT": os.getenv("NAUTOBOT_DB_PORT", ""), # Database port (leave blank for default) - "CONN_MAX_AGE": os.getenv("NAUTOBOT_DB_TIMEOUT", 300), # Database timeout - "ENGINE": "django.db.backends.postgresql", # Database driver (Postgres only supported!) - } -} +# Debug +# -# Nautobot uses RQ for task scheduling. These are the following defaults. -# For detailed configuration see: https://github.com/rq/django-rq#installation -# These defaults utilize the Django `CACHES` setting defined above for django-redis. -# See: https://github.com/rq/django-rq#support-for-django-redis-and-django-redis-cache -RQ_QUEUES = { - "default": { - "USE_REDIS_CACHE": "default", - }, - "check_releases": { - "USE_REDIS_CACHE": "default", - }, - "custom_fields": { - "USE_REDIS_CACHE": "default", - }, - "webhooks": { - "USE_REDIS_CACHE": "default", - }, -} +DEBUG = is_truthy(os.getenv("NAUTOBOT_DEBUG", False)) -# Nautobot uses Cacheops for database query caching. These are the following defaults. -# For detailed configuration see: https://github.com/Suor/django-cacheops#setup -# Set Cache Ops variables -redis_protocol = "rediss" if is_truthy(os.getenv("NAUTOBOT_REDIS_SSL", False)) else "redis" -cache_ops_pwd = os.getenv("NAUTOBOT_REDIS_PASSWORD") -cache_ops_host = os.getenv("NAUTOBOT_REDIS_HOST", "localhost") -cache_ops_user = os.getenv("NAUTOBOT_REDIS_USER") -cache_ops_port = int(os.getenv("NAUTOBOT_REDIS_PORT", 6379)) +TESTING = len(sys.argv) > 1 and sys.argv[1] == "test" -CACHEOPS_REDIS = os.getenv("NAUTOBOT_CACHEOPS_REDIS", f"{redis_protocol}://:{cache_ops_pwd}@{cache_ops_host}:{cache_ops_port}/1") +# +# Redis +# -# The django-redis cache is used to establish concurrent locks using Redis. The -# django-rq settings will use the same instance/database by default. +# The django-redis cache is used to establish concurrent locks using Redis. +# CACHES = { "default": { "BACKEND": "django_redis.cache.RedisCache", - "LOCATION": f"{redis_protocol}://:{cache_ops_pwd}@{cache_ops_host}:{cache_ops_port}/0", + "LOCATION": parse_redis_connection(redis_database=0), "TIMEOUT": 300, "OPTIONS": { "CLIENT_CLASS": "django_redis.client.DefaultClient", - "PASSWORD": "", }, } } -# This key is used for secure generation of random numbers and strings. It must never be exposed outside of this file. -# For optimal security, SECRET_KEY should be at least 50 characters in length and contain a mix of letters, numbers, and -# symbols. Nautobot will not run without this defined. For more information, see -# https://docs.djangoproject.com/en/stable/ref/settings/#std:setting-SECRET_KEY -SECRET_KEY = os.getenv("NAUTOBOT_SECRET_KEY", "v8b0_x=$*xk#(qyy#0^&z6a$l=3#i8ohm5guu%yf@dtxh3rub%") +# Redis Cacheops +CACHEOPS_REDIS = parse_redis_connection(redis_database=1) + +# +# Celery settings are not defined here because they can be overloaded with +# environment variables. By default they use `CACHES["default"]["LOCATION"]`. +# + +# Enable installed plugins. Add the name of each plugin to the list. +PLUGINS = ["nautobot_example_plugin"] + +# Plugins configuration settings. These settings are used by various plugins that the user may have installed. +# Each key in the dictionary is the name of an installed plugin and its value is a dictionary of settings. +PLUGINS_CONFIG = { + "nautobot_example_plugin": {}, +} ######################### # # @@ -125,244 +94,3 @@ AUTH_LDAP_USER_ATTR_MAP = { "last_name": "sn", "email": "mail" } - - -######################### -# # -# Optional settings # -# # -######################### - -# Specify one or more name and email address tuples representing Nautobot administrators. These people will be notified of -# application errors (assuming correct email settings are provided). -ADMINS = [ - # ['John Doe', 'jdoe@example.com'], -] - -# URL schemes that are allowed within links in Nautobot -ALLOWED_URL_SCHEMES = ( - "file", - "ftp", - "ftps", - "http", - "https", - "irc", - "mailto", - "sftp", - "ssh", - "tel", - "telnet", - "tftp", - "vnc", - "xmpp", -) - -# Optionally display a persistent banner at the top and/or bottom of every page. HTML is allowed. To display the same -# content in both banners, define BANNER_TOP and set BANNER_BOTTOM = BANNER_TOP. -BANNER_TOP = os.getenv("NAUTOBOT_BANNER_TOP", "") -BANNER_BOTTOM = os.getenv("NAUTOBOT_BANNER_BOTTOM", "") - -# Text to include on the login page above the login form. HTML is allowed. -BANNER_LOGIN = os.getenv("NAUTOBOT_BANNER_LOGIN", "") - -# Cache timeout in seconds. Cannot be 0. Defaults to 900 (15 minutes). To disable caching, set CACHEOPS_ENABLED to False -CACHEOPS_DEFAULTS = {"timeout": int(os.getenv("NAUTOBOT_CACHEOPS_TIMEOUT", 900))} - -# Set to False to disable caching with cacheops. (Default: True) -CACHEOPS_ENABLED = is_truthy(os.getenv("NAUTOBOT_CACHEOPS_ENABLED", True)) - -# Maximum number of days to retain logged changes. Set to 0 to retain changes indefinitely. (Default: 90) -CHANGELOG_RETENTION = int(os.getenv("NAUTOBOT_CHANGELOG_RETENTION", 90)) - -# If True, all origins will be allowed. Other settings restricting allowed origins will be ignored. -# Defaults to False. Setting this to True can be dangerous, as it allows any website to make -# cross-origin requests to yours. Generally you'll want to restrict the list of allowed origins with -# CORS_ALLOWED_ORIGINS or CORS_ALLOWED_ORIGIN_REGEXES. -CORS_ALLOW_ALL_ORIGINS = is_truthy(os.getenv("NAUTOBOT_CORS_ALLOW_ALL_ORIGINS", False)) - -# A list of origins that are authorized to make cross-site HTTP requests. Defaults to []. -CORS_ALLOWED_ORIGINS = [ - # 'https://hostname.example.com', -] - -# A list of strings representing regexes that match Origins that are authorized to make cross-site -# HTTP requests. Defaults to []. -CORS_ALLOWED_ORIGIN_REGEXES = [ - # r'^(https?://)?(\w+\.)?example\.com$', -] - -# FQDNs that are considered trusted origins for secure, cross-domain, requests such as HTTPS POST. -# If running Nautobot under a single domain, you may not need to set this variable; -# if running on multiple domains, you *may* need to set this variable to more or less the same as ALLOWED_HOSTS above. -# https://docs.djangoproject.com/en/stable/ref/settings/#csrf-trusted-origins -CSRF_TRUSTED_ORIGINS = [] - -# Set to True to enable server debugging. WARNING: Debugging introduces a substantial performance penalty and may reveal -# sensitive information about your installation. Only enable debugging while performing testing. Never enable debugging -# on a production system. -DEBUG = is_truthy(os.getenv("NAUTOBOT_DEBUG", False)) - -# Enforcement of unique IP space can be toggled on a per-VRF basis. To enforce unique IP space -# within the global table (all prefixes and IP addresses not assigned to a VRF), set -# ENFORCE_GLOBAL_UNIQUE to True. -ENFORCE_GLOBAL_UNIQUE = is_truthy(os.getenv("NAUTOBOT_ENFORCE_GLOBAL_UNIQUE", False)) - -# Exempt certain models from the enforcement of view permissions. Models listed here will be viewable by all users and -# by anonymous users. List models in the form `.`. Add '*' to this list to exempt all models. -EXEMPT_VIEW_PERMISSIONS = [ - # 'dcim.site', - # 'dcim.region', - # 'ipam.prefix', -] - -# Global 3rd-party authentication settings -EXTERNAL_AUTH_DEFAULT_GROUPS = [] -EXTERNAL_AUTH_DEFAULT_PERMISSIONS = {} - -# If hosting Nautobot in a subdirectory, you must set this value to match the base URL prefix configured in your HTTP server (e.g. `/nautobot/`). When not set, URLs will default to being prefixed by `/`. -FORCE_SCRIPT_NAME = None - -# When set to `True`, users with limited permissions will only be able to see items in the UI they have access too. -HIDE_RESTRICTED_UI = is_truthy(os.getenv("NAUTOBOT_HIDE_RESTRICTED_UI", False)) - -# HTTP proxies Nautobot should use when sending outbound HTTP requests (e.g. for webhooks). -# HTTP_PROXIES = { -# 'http': 'http://10.10.1.10:3128', -# 'https': 'http://10.10.1.10:1080', -# } - -# IP addresses recognized as internal to the system. The debugging toolbar will be available only to clients accessing -# Nautobot from an internal IP. -INTERNAL_IPS = ("127.0.0.1", "::1") - -# Setting this to True will display a "maintenance mode" banner at the top of every page. -MAINTENANCE_MODE = is_truthy(os.getenv("NAUTOBOT_MAINTENANCE_MODE", False)) - -# An API consumer can request an arbitrary number of objects =by appending the "limit" parameter to the URL (e.g. -# "?limit=1000"). This setting defines the maximum limit. Setting it to 0 or None will allow an API consumer to request -# all objects by specifying "?limit=0". -MAX_PAGE_SIZE = int(os.getenv("NAUTOBOT_MAX_PAGE_SIZE", 1000)) - -# The file path where uploaded media such as image attachments are stored. A trailing slash is not needed. Note that -# the default value of this setting is within the invoking user's home directory -# MEDIA_ROOT = os.path.expanduser('~/.nautobot/media') - -# By default uploaded media is stored on the local filesystem. Using Django-storages is also supported. Provide the -# class path of the storage driver in STORAGE_BACKEND and any configuration options in STORAGE_CONFIG. For example: -# STORAGE_BACKEND = 'storages.backends.s3boto3.S3Boto3Storage' -# STORAGE_CONFIG = { -# 'AWS_ACCESS_KEY_ID': 'Key ID', -# 'AWS_SECRET_ACCESS_KEY': 'Secret', -# 'AWS_STORAGE_BUCKET_NAME': 'nautobot', -# 'AWS_S3_REGION_NAME': 'eu-west-1', -# } - -# Expose Prometheus monitoring metrics at the HTTP endpoint '/metrics' -METRICS_ENABLED = is_truthy(os.getenv("NAUTOBOT_METRICS_ENABLED", False)) - -# Credentials that Nautobot will uses to authenticate to devices when connecting via NAPALM. -NAPALM_USERNAME = os.getenv("NAUTOBOT_NAPALM_USERNAME", "") -NAPALM_PASSWORD = os.getenv("NAUTOBOT_NAPALM_PASSWORD", "") - -# NAPALM timeout (in seconds). (Default: 30) -NAPALM_TIMEOUT = int(os.getenv("NAUTOBOT_NAPALM_TIMEOUT", 30)) - -# NAPALM optional arguments (see https://napalm.readthedocs.io/en/latest/support/#optional-arguments). Arguments must -# be provided as a dictionary. -NAPALM_ARGS = {} - -# Determine how many objects to display per page within a list. (Default: 50) -PAGINATE_COUNT = int(os.getenv("NAUTOBOT_PAGINATE_COUNT", 50)) - -# Enable installed plugins. Add the name of each plugin to the list. -PLUGINS = ["nautobot_device_onboarding"] - -# Plugins configuration settings. These settings are used by various plugins that the user may have installed. -# Each key in the dictionary is the name of an installed plugin and its value is a dictionary of settings. -# PLUGINS_CONFIG = { -# 'my_plugin': { -# 'foo': 'bar', -# 'buzz': 'bazz' -# } -# } - -# When determining the primary IP address for a device, IPv6 is preferred over IPv4 by default. Set this to True to -# prefer IPv4 instead. -PREFER_IPV4 = is_truthy(os.getenv("NAUTOBOT_PREFER_IPV4", False)) - -# Rack elevation size defaults, in pixels. For best results, the ratio of width to height should be roughly 10:1. -RACK_ELEVATION_DEFAULT_UNIT_HEIGHT = int(os.getenv("NAUTOBOT_RACK_ELEVATION_DEFAULT_UNIT_HEIGHT", 22)) -RACK_ELEVATION_DEFAULT_UNIT_WIDTH = int(os.getenv("NAUTOBOT_RACK_ELEVATION_DEFAULT_UNIT_WIDTH", 220)) - -# Remote auth backend settings -REMOTE_AUTH_AUTO_CREATE_USER = False -REMOTE_AUTH_HEADER = "HTTP_REMOTE_USER" - -# This determines how often the GitHub API is called to check the latest release of Nautobot. Must be at least 1 hour. -RELEASE_CHECK_TIMEOUT = int(os.getenv("NAUTOBOT_RELEASE_CHECK_TIMEOUT", 24 * 3600)) - -# This repository is used to check whether there is a new release of Nautobot available. Set to None to disable the -# version check or use the URL below to check for release in the official Nautobot repository. -RELEASE_CHECK_URL = os.getenv("NAUTOBOT_RELEASE_CHECK_URL", None) -# RELEASE_CHECK_URL = 'https://api.github.com/repos/nautobot/nautobot/releases' - -# The length of time (in seconds) for which a user will remain logged into the web UI before being prompted to -# re-authenticate. (Default: 1209600 [14 days]) -SESSION_COOKIE_AGE = int(os.getenv("NAUTOBOT_SESSION_COOKIE_AGE", 1209600)) # 2 weeks, in seconds - -# By default, Nautobot will store session data in the database. Alternatively, a file path can be specified here to use -# local file storage instead. (This can be useful for enabling authentication on a standby instance with read-only -# database access.) Note that the user as which Nautobot runs must have read and write permissions to this path. -SESSION_FILE_PATH = os.getenv("NAUTOBOT_SESSION_FILE_PATH", None) - -# Configure SSO, for more information see docs/configuration/authentication/sso.md -SOCIAL_AUTH_POSTGRES_JSONFIELD = False - -# Time zone (default: UTC) -TIME_ZONE = os.getenv("NAUTOBOT_TIME_ZONE", "UTC") - -# Date/time formatting. See the following link for supported formats: -# https://docs.djangoproject.com/en/stable/ref/templates/builtins/#date -DATE_FORMAT = os.getenv("NAUTOBOT_DATE_FORMAT", "N j, Y") -SHORT_DATE_FORMAT = os.getenv("NAUTOBOT_SHORT_DATE_FORMAT", "Y-m-d") -TIME_FORMAT = os.getenv("NAUTOBOT_TIME_FORMAT", "g:i a") -SHORT_TIME_FORMAT = os.getenv("NAUTOBOT_SHORT_TIME_FORMAT", "H:i:s") -DATETIME_FORMAT = os.getenv("NAUTOBOT_DATETIME_FORMAT", "N j, Y g:i a") -SHORT_DATETIME_FORMAT = os.getenv("NAUTOBOT_SHORT_DATETIME_FORMAT", "Y-m-d H:i") - -# A list of strings designating all applications that are enabled in this Django installation. Each string should be a dotted Python path to an application configuration class (preferred), or a package containing an application. -# https://nautobot.readthedocs.io/en/latest/configuration/optional-settings/#extra-applications -EXTRA_INSTALLED_APPS = [] -LOG_LEVEL = "DEBUG" if DEBUG else "INFO" -LOGGING = { - "version": 1, - "disable_existing_loggers": False, - "formatters": { - "normal": { - "format": "%(asctime)s.%(msecs)03d %(levelname)-7s %(name)s :\n %(message)s", - "datefmt": "%H:%M:%S", - }, - "verbose": { - "format": "%(asctime)s.%(msecs)03d %(levelname)-7s %(name)-20s %(filename)-15s %(funcName)30s() :\n %(message)s", - "datefmt": "%H:%M:%S", - }, - }, - "handlers": { - "normal_console": { - "level": "DEBUG", - "class": "rq.utils.ColorizingStreamHandler", - "formatter": "normal", - }, - }, - "loggers": { - "django": {"handlers": ["normal_console"], "level": LOG_LEVEL}, - "nautobot": { - "handlers": ["normal_console"], - "level": LOG_LEVEL, - }, - "rq.worker": { - "handlers": ["normal_console"], - "level": LOG_LEVEL, - }, - }, -} diff --git a/docker-compose.ldap.yml b/docker-compose.ldap.yml deleted file mode 100644 index b71fedb21..000000000 --- a/docker-compose.ldap.yml +++ /dev/null @@ -1,63 +0,0 @@ ---- -version: "3.7" -services: - nautobot: - image: "companyname/nautobot-ldap" - build: - args: - PYTHON_VER: "${PYTHON_VER:-3.9}" - context: "./" - dockerfile: "Dockerfile-LDAP" - target: "final" - env_file: - - "local.env" - ports: - - "8443:8443" - - "8080:8080" - restart: "unless-stopped" - depends_on: - - "postgres" - - "redis" - # ---------------------------------- - # Celery worker must only be used in > 1.1.0 installs. If setting to a previous install, remove this worker - # ---------------------------------- - celery_worker: - build: - args: - PYTHON_VER: "${PYTHON_VER:-3.9}" - context: "./" - dockerfile: "Dockerfile-LDAP" - target: "final" - image: "companyname/nautobot-ldap" - entrypoint: "sh -c 'nautobot-server celery worker -l $$NAUTOBOT_LOG_LEVEL'" - healthcheck: - interval: "30s" - timeout: "10s" - start_period: "30s" - retries: 3 - test: ["CMD", "bash", "-c", "nautobot-server celery inspect ping --destination celery@$$HOSTNAME"] ## $$ because of docker-compose - depends_on: - - "nautobot" - - "redis" - env_file: - - "./local.env" - tty: true - # --------------------------------- - redis: - image: "redis:alpine" - env_file: - - "local.env" - command: - - "sh" - - "-c" # this is to evaluate the $REDIS_PASSWORD from the env - - "redis-server --appendonly yes --requirepass $$NAUTOBOT_REDIS_PASSWORD" ## $$ because of docker-compose - restart: "unless-stopped" - postgres: - image: "postgres:13" - env_file: - - "local.env" - volumes: - - "postgres_data:/var/lib/postgresql/data" - restart: "unless-stopped" -volumes: - postgres_data: diff --git a/docker-compose.mysql.yml b/docker-compose.mysql.yml deleted file mode 100644 index b175095d8..000000000 --- a/docker-compose.mysql.yml +++ /dev/null @@ -1,14 +0,0 @@ ---- -version: "3.7" -services: - db: - image: "mysql" - env_file: - - "local.env" - environment: - NAUTOBOT_DB_ENGINE: "django.db.backends.mysql" - volumes: - - "db_data:/var/lib/mysql" - restart: "unless-stopped" -volumes: - db_data: diff --git a/docker-compose.yml b/docker-compose.yml deleted file mode 100644 index 7274bd292..000000000 --- a/docker-compose.yml +++ /dev/null @@ -1,68 +0,0 @@ ---- -version: "3.7" -services: - nautobot: - image: "networktocode/nautobot:${NAUTOBOT_IMAGE:-1.5.11}-py${PYTHON_VER:-3.9}" - env_file: - - "local.env" - ports: - - "8443:8443" - - "8080:8080" - restart: "unless-stopped" - # ---------------------------------- - # Celery worker must only be used in > 1.1.0 installs. If setting to a previous install, remove this worker - # ---------------------------------- - celery_worker: - image: "networktocode/nautobot:${NAUTOBOT_IMAGE:-1.5.11}-py${PYTHON_VER:-3.9}" - entrypoint: "sh -c 'nautobot-server celery worker -l $$NAUTOBOT_LOG_LEVEL'" - healthcheck: - interval: "5s" - timeout: "5s" - start_period: "5s" - retries: 3 - test: ["CMD", "nautobot-server", "health_check"] - depends_on: - - "nautobot" - - "redis" - env_file: - - "./local.env" - tty: true - # ---------------------------------- - # Celery beat must only be used in > 1.2.0 installs. If setting to a previous install, remove this worker - # ---------------------------------- - celery_beat: - image: "networktocode/nautobot:${NAUTOBOT_IMAGE:-1.5.11}-py${PYTHON_VER:-3.9}" - entrypoint: "sh -c 'nautobot-server celery beat -l $$NAUTOBOT_LOG_LEVEL'" - healthcheck: - interval: "5s" - timeout: "5s" - start_period: "5s" - retries: 3 - test: ["CMD", "nautobot-server", "health_check"] - depends_on: - - "nautobot" - - "redis" - env_file: - - "./local.env" - tty: true - redis: - image: "redis:alpine" - env_file: - - "local.env" - command: - - "sh" - - "-c" # this is to evaluate the $REDIS_PASSWORD from the env - - "redis-server --appendonly yes --requirepass $$NAUTOBOT_REDIS_PASSWORD" ## $$ because of docker-compose - restart: "unless-stopped" - db: - image: "postgres:13" - # Apple Silicon has issues with Postgres14, there is no needed functions to get to Postgres14 for Nautobot to work. - env_file: - - "local.env" - environment: - NAUTOBOT_DB_ENGINE: "django.db.backends.postgres" - volumes: - - "db_data:/var/lib/postgresql/data" - restart: "unless-stopped" -volumes: - db_data: diff --git a/docs/create_ssl_cert.md b/docs/create_ssl_cert.md index 6e2f77892..ca2093771 100644 --- a/docs/create_ssl_cert.md +++ b/docs/create_ssl_cert.md @@ -12,8 +12,8 @@ By default the Docker image comes with a self signed certificate that is valid f - "8080:8080" restart: "unless-stopped" volumes: - - path/to/your/nautobot.key /opt/nautobot/nautobot.key - - path/to/your/nautobot.crt /opt/nautobot/nautobot.crt + - "./nautobot.key:/opt/nautobot/nautobot.key:ro" + - "./nautobot.crt:/opt/nautobot/nautobot.crt:ro" ``` ## Make Own Cert Options (Not Required) @@ -27,7 +27,8 @@ If you do not have your own self signed certificate, you may generate them by us OpenSSL is included with many UNIX operating systems, but may need to be installed on your system first. Check to see if OpenSSL is installed on your system -``` + +```bash user@ntc# openssl version LibreSSL 2.8.3 ``` @@ -37,12 +38,14 @@ If you do not have OpenSSL installed, please follow the [installation guidelines #### Example Self Sign Cert Once OpenSSL is installed, run the following command to generate the certificates. -``` -sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout ./certs/nautobot.key -out ./certs/nautobot.crt + +```bash +sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout ./environments/nautobot.key -out ./environments/nautobot.crt ``` You will be prompted with information to fill out for your certificate. -``` + +```bash Country Name (2 letter code) [AU]:US State or Province Name (full name) [Some-State]:New York Locality Name (eg, city) []:New York City @@ -53,7 +56,8 @@ Email Address []:admin@your_domain.com ``` Finally, ensure your newly generated certificates are in the correct location. -``` -user@ntc# ls ./certs/ + +```bash +user@ntc# ls ./environments/ nautobot.crt nautobot.key ``` diff --git a/docs/ldap.md b/docs/ldap.md index 2988bbadf..6b9e3df81 100644 --- a/docs/ldap.md +++ b/docs/ldap.md @@ -4,66 +4,38 @@ The LDAP container image has a different base image than the primary Docker file ## Getting Started Using LDAP Container -1. Have [Docker](https://docs.docker.com/get-docker/) and [Docker Compose](https://docs.docker.com/compose/install/) installed on the host -2. Clone this repository to your Nautobot host into the current user directory. -``` -git clone https://github.com/nautobot/nautobot-docker-compose.git -``` - -3. Copy `.env.example` to `.env` -``` -cp local.env.example local.env -``` +1. Follow the steps in the README to get your Poetry environment created and confirm you can build containers. For step #7 use `invoke.ldap.yml` instead of `invoke.example.yml`. This will ensure that the LDAP Compose file will be used when building your containers. -4. Make update to the `local.env` file for your environment. Updates are IMPORTANT! -``` -vi local.env -``` - -5. Update the `local.env` to be only available for the Nautobot user -``` -chmod 0600 local.env -``` +2. Copy the LDAP configuration file from `config/nautobot_config.py.ldap` to `config/nautobot_config.py` -6. Copy the LDAP configuration file from `config/nautobot_config.py.ldap` to `config/nautobot_config.py` - -``` +```bash cp config/nautobot_config.py.ldap config/nautobot_config.py ``` -7. Update settings in the LDAP configuration to match your environment, based on the documentation from [Nautobot docs](https://nautobot.readthedocs.io) +3. Update settings in the LDAP configuration to match your environment, based on the documentation from [Nautobot docs](https://nautobot.readthedocs.io) -``` +```bash vi config/nautobot_config.py ``` -8. Update environment vars in the `local.env` file for the configuration file: +4. Update environment variables in the `local.env` file for the configuration file: * NAUTOBOT_AUTH_LDAP_SERVER_URI * NAUTOBOT_AUTH_LDAP_BIND_DN * NAUTOBOT_AUTH_LDAP_BIND_PASSWORD -``` +```bash vi local.env ``` -1. Run `docker-compose -f docker-compose.ldap.yml build --no-cache` to build the `companyname/Dockerfile-LDAP` (from the file `docker-compose.ldap.yml`) -> You may want to update `companyname` to your organization/company name +5. Build your containers and ensure that the LDAP packages are installed: -``` -docker-compose -f docker-compose.ldap.yml build --no-cache +```bash +invoke build --no-cache ``` -7. Run `docker-compose -f docker-compose.ldap.yml up` to have the containers spun up and seeing the logs +6. Assuming that your containers are not already running, you'll want to start them: +```bash +invoke start ``` -docker-compose -f docker-compose.ldap.yml up -``` - -## Environment Controls - -There are two environment variables that will control the environment for the container. - -### Python Version - -The version of Python used in the Dockerfile defaults to Python3.9 diff --git a/docs/plugins.md b/docs/plugins.md index 4f9e924a7..686e062bd 100644 --- a/docs/plugins.md +++ b/docs/plugins.md @@ -1,110 +1,57 @@ -# PLUGINS +# App Installation -To add plugins you will need to build a custom container with the plugin installed. +To add Apps you will need to build a custom container with the App(s) installed. There are multiple ways to add an App to your environment but this document will show the standard method pulling from PyPI. -## Getting Started Using Plugins +## Getting Started Using Apps -1. Have [Docker](https://docs.docker.com/get-docker/) and [Docker Compose](https://docs.docker.com/compose/install/) installed on the host -2. Clone this repository to your Nautobot host into the current user directory. +1. Follow the steps in the README to create your Poetry environment and ensure you can build a container. +2. There are two methods by which to add a specific App to your environment with Poetry: -``` -git clone https://github.com/nautobot/nautobot-docker-compose.git -``` +- Use the `poetry add` command. -3. Copy `local.env.example` to `local.env` +For example, to add the Device Onboarding App you would do the following: +```bash +poetry add nautobot-device-onboarding ``` -cp local.env.example local.env -``` - -4. Make update to the `local.env` file for your environment. Updates are IMPORTANT! -``` -vi local.env -``` +This command should automatically trigger Poetry to see the versions you've specified for Nautobot and your other dependencies in the `pyproject.toml` file and find the most compatible version that is within the limits of the versions defined in your `pyproject.toml`. -5. Update the `.env` to be only available for the Nautobot user +- To specify a particular version you can append that to the command like so: +```bash +poetry add nautobot-device-onboarding==3.0.1 ``` -chmod 0600 local.env -``` - -6. Move the files from the `plugin_example` directory -``` -cp -r plugin_example/* ./ -``` +If for some reason this version doesn't conform to the limits set in your `pyproject.toml` you will need to modify the versions specified by your other dependencies. Poetry should provide some feedback at the command prompt once you've issued the add command if there are limits that restrict you from using that version. Poetry should also update your `poetry.lock` file with the specific pinned version of that App. -7. Update the file `config/nautobot_config.py` settings of `PLUGINS` and `PLUGINS_CONFIG` to match your configuration updates for the plugins (PLUGINS_CONFIG is optional, if not adjusting from the default settings). See the [example PLUGIN configuration](#nautobot-configuration). +3. Once your `poetry.lock` file is updated by Poetry you will need to update the file `config/nautobot_config.py` settings of `PLUGINS` and `PLUGINS_CONFIG` to match your configuration updates for the plugins (PLUGINS_CONFIG is optional, if not adjusting from the default settings). See the [example PLUGIN configuration](#nautobot-configuration). -``` +```bash vi config/nautobot_config.py ``` -8. Update the `./plugin_requirements.txt` file with the Python packages that need to be installed. These will be installed via the `pip install -r plugin_requirements.txt` command (This example file has the Nautobot Onboarding Plugin) - -``` -vi plugin_requirements.txt -``` - -9. Complete the [Docker Compose Override Update](#docker-compose-override) section. - -10. Create the custom Docker Container, see [Custom Docker Container](#custom-docker-container) -11. Run `docker-compose build --no-cache` to build the Dockerfile-Plugins (from the file `docker-compose.override.yml`, see below for more details) - -``` -docker-compose build --no-cache -``` - -12. Run `docker-compose up` to have the compose file executed and bring up the containers. - -``` -docker-compose up -``` - -## Custom Docker Container +4. Finally, you should simply need to rebuild your containers with an `invoke build --no-cache` to build the new custom container. -The first step is to create a custom Docker container that will handle the installation of the packages. The recommendation is to use `Dockerfile-Plugins` as the file name. It can be whatever is meaningful and is not a requirement. The Dockerfile then looks like: - -```docker -ARG PYTHON_VER -ARG NAUTOBOT_VERSION=1.5.9 -FROM networktocode/nautobot:${NAUTOBOT_VERSION}-py${PYTHON_VER} - -COPY ./plugin_requirements.txt /opt/nautobot/ -RUN pip install --no-warn-script-location -r /opt/nautobot/plugin_requirements.txt - -COPY config/nautobot_config.py /opt/nautobot/nautobot_config.py -``` - -## Docker Compose Override - -First move the example override file to the current file (after the copy of the directory is completed) - -```no-highlight -mv docker-compose.override.yml.example docker-compose.override.yml +```bash +invoke build --no-cache ``` -The `docker-compose.override.yml` overrides settings from the primary docker-compose file. In this case there needs to be a new Docker image file that is used to provide the Nautobot container. The key within the `docker-compose.override.yml` file is: +5. Once your new containers are built you should simply need to start them if not already started, or restart them with the following: -```yaml -image: "companyname/nautobot-plugins:latest" -build: - context: . - dockerfile: Dockerfile-Plugins +```bash +invoke stop start ``` -This indicates to build the image name `companyname/nautobot-plugins:latest` from the Dockerfile `Dockerfile-Plugins`. Then that image is what is used for the Nautobot container image. Substitute `companyname` with something that is meaningful to your organization. - ## Nautobot Configuration -The configuration file is the same file that is used by the Dockerfile in the Nautobot repo. This file should be updated to match what is required for each of the plugins. An example update for the Onboarding Plugin looks like: +The configuration file is the same file that is used by the Dockerfile in the Nautobot repo. This file should be updated to match what is required for each of the Apps. An example update for the Onboarding App looks like: ```python -# Enable installed plugins. Add the name of each plugin to the list. +# Enable installed Apps. Add the name of each App to the list. PLUGINS = ["nautobot_device_onboarding"] -# Plugins configuration settings. These settings are used by various plugins that the user may have installed. -# Each key in the dictionary is the name of an installed plugin and its value is a dictionary of settings. +# App configuration settings. These settings are used by various Apps that the user may have installed. +# Each key in the dictionary is the name of an installed App and its value is a dictionary of settings. PLUGINS_CONFIG = {} ``` diff --git a/environments/Dockerfile b/environments/Dockerfile new file mode 100644 index 000000000..ad3e50c3d --- /dev/null +++ b/environments/Dockerfile @@ -0,0 +1,67 @@ +ARG NAUTOBOT_VERSION +ARG PYTHON_VER +FROM ghcr.io/nautobot/nautobot:${NAUTOBOT_VERSION}-py${PYTHON_VER} as nautobot-base + +USER 0 + +RUN apt-get update && \ + apt-get upgrade -y && \ + apt-get autoremove -y && \ + apt-get clean all && \ + rm -rf /var/lib/apt/lists/* && \ + pip --no-cache-dir install --upgrade pip wheel + +FROM ghcr.io/nautobot/nautobot-dev:${NAUTOBOT_VERSION}-py${PYTHON_VER} as builder + +CMD ["nautobot-server", "runserver", "0.0.0.0:8080", "--insecure"] + +RUN apt-get update && \ + apt-get upgrade -y && \ + apt-get autoremove -y && \ + apt-get clean all && \ + rm -rf /var/lib/apt/lists/* + +COPY ../pyproject.toml ../poetry.lock /source/ +COPY ../plugins /source/plugins +# COPY ../packages /source/packages + +# Install the nautobot project to include Nautobot +RUN cd /source && \ + poetry install --no-interaction --no-ansi && \ + mkdir /tmp/dist && \ + poetry export --without-hashes -o /tmp/dist/requirements.txt + +# ------------------------------------------------------------------------------------- +# Build Apps in plugins folder +# ------------------------------------------------------------------------------------- +RUN for plugin in /source/plugins/*; do \ + cd $plugin && \ + poetry build && \ + cp dist/*.whl /tmp/dist; \ + done + +COPY ../jobs /opt/nautobot/jobs +# COPY ../metrics /opt/nautobot/metrics +COPY ../config/nautobot_config.py /opt/nautobot/nautobot_config.py + +WORKDIR /source + +################################### + +# ------------------------------------------------------------------------------------- +# Final Image +# ------------------------------------------------------------------------------------- +FROM nautobot-base as nautobot + +# Copy from base the required python libraries and binaries +COPY --from=builder /tmp/dist /tmp/dist +COPY --from=builder /opt/nautobot /opt/nautobot +# COPY ../packages /source/packages + +RUN grep -v /source/plugins /tmp/dist/requirements.txt > /tmp/dist/new_requirements.txt && \ + pip install -r /tmp/dist/new_requirements.txt && \ + pip install /tmp/dist/*.whl && \ + rm -rf /source /tmp/dist && \ + chown -R nautobot:nautobot /opt/nautobot + +USER nautobot diff --git a/environments/Dockerfile-LDAP b/environments/Dockerfile-LDAP new file mode 100644 index 000000000..a62f22c86 --- /dev/null +++ b/environments/Dockerfile-LDAP @@ -0,0 +1,76 @@ +ARG NAUTOBOT_VERSION +ARG PYTHON_VER +FROM ghcr.io/nautobot/nautobot:${NAUTOBOT_VERSION}-py${PYTHON_VER} as nautobot-base + +USER 0 + +RUN apt-get update && \ + apt-get upgrade -y && \ + apt-get autoremove -y && \ + apt-get clean all && \ + rm -rf /var/lib/apt/lists/* && \ + pip --no-cache-dir install --upgrade pip wheel + +FROM ghcr.io/nautobot/nautobot-dev:${NAUTOBOT_VERSION}-py${PYTHON_VER} as builder + +CMD ["nautobot-server", "runserver", "0.0.0.0:8080", "--insecure"] + +RUN apt-get update && \ + apt-get upgrade -y && \ + apt-get autoremove -y && \ + apt-get clean all && \ + rm -rf /var/lib/apt/lists/* + +RUN apt-get install -y libldap2-dev libsasl2-dev libssl-dev + +COPY ./pyproject.toml ./poetry.lock /source/ +COPY ../plugins /source/plugins +# COPY ./packages /source/packages + +# Install the nautobot project to include Nautobot +RUN cd /source && \ + poetry install --no-interaction --no-ansi && \ + mkdir /tmp/dist && \ + poetry export --without-hashes -o /tmp/dist/requirements.txt + +RUN pip3 install --upgrade pip wheel && pip3 install django-auth-ldap + +# ------------------------------------------------------------------------------------- +# Install all included plugins +# ------------------------------------------------------------------------------------- +RUN for plugin in /source/plugins/*; do \ + cd $plugin && \ + poetry build && \ + cp dist/*.whl /tmp/dist; \ + done + +COPY ./jobs /opt/nautobot/jobs +# COPY ./metrics /opt/nautobot/metrics +COPY ../config/nautobot_config.py.ldap /opt/nautobot/nautobot_config.py + +WORKDIR /source + +################################### + +# ------------------------------------------------------------------------------------- +# Final Image +# ------------------------------------------------------------------------------------- +FROM nautobot-base as nautobot +ARG PYTHON_VER + +# Copy from base the required python libraries and binaries +COPY --from=builder /tmp/dist /tmp/dist +COPY --from=builder /usr/local/lib/python${PYTHON_VER}/site-packages /usr/local/lib/python${PYTHON_VER}/site-packages +COPY --from=builder /usr/local/bin /usr/local/bin +COPY --from=builder /opt/nautobot /opt/nautobot +# COPY ./packages /source/packages + +RUN grep -v /source/plugins /tmp/dist/requirements.txt > /tmp/dist/new_requirements.txt && \ + pip install -r /tmp/dist/new_requirements.txt && \ + pip install /tmp/dist/*.whl && \ + rm -rf /source /tmp/dist && \ + chown -R nautobot:nautobot /opt/nautobot + +USER nautobot + +WORKDIR /opt/nautobot diff --git a/environments/creds.example.env b/environments/creds.example.env new file mode 100644 index 000000000..5386d7e38 --- /dev/null +++ b/environments/creds.example.env @@ -0,0 +1,24 @@ +NAUTOBOT_CREATE_SUPERUSER=false +NAUTOBOT_DB_PASSWORD=changeme +NAUTOBOT_NAPALM_USERNAME='' +NAUTOBOT_NAPALM_PASSWORD='' +NAUTOBOT_REDIS_PASSWORD=changeme +NAUTOBOT_SECRET_KEY=012345678901234567890123456789012345678901234567890123456789 +NAUTOBOT_SUPERUSER_NAME=admin +NAUTOBOT_SUPERUSER_EMAIL=admin@example.com +NAUTOBOT_SUPERUSER_PASSWORD=admin +# API token length must be exactly 40 characters +NAUTOBOT_SUPERUSER_API_TOKEN=0123456789abcdef0123456789abcdef01234567 + +NAUTOBOT_CACHEOPS_REDIS=redis://:${NAUTOBOT_REDIS_PASSWORD}@redis:6379/1 + +# Postgres +POSTGRES_PASSWORD=${NAUTOBOT_DB_PASSWORD} +PGPASSWORD=${NAUTOBOT_DB_PASSWORD} + +# MySQL + +MYSQL_PASSWORD=${NAUTOBOT_DB_PASSWORD} +MYSQL_ROOT_PASSWORD=${NAUTOBOT_DB_PASSWORD} + + diff --git a/environments/docker-compose.base.yml b/environments/docker-compose.base.yml new file mode 100644 index 000000000..2b5fbd65a --- /dev/null +++ b/environments/docker-compose.base.yml @@ -0,0 +1,65 @@ +--- +version: "3.8" +x-nautobot-build: &nautobot-build + build: + args: + NAUTOBOT_VERSION: "${NAUTOBOT_VERSION}" + PYTHON_VER: "${PYTHON_VER}" + context: "../" + target: "nautobot" + dockerfile: "environments/Dockerfile" +x-nautobot-base: &nautobot-base + image: "yourrepo/nautobot-docker-compose:local" + env_file: + - "local.env" + - "creds.env" + tty: true + +services: + nautobot: + depends_on: + - "db" + - "redis" + <<: [*nautobot-base, *nautobot-build] + # volumes: + # - "./nautobot.key:/opt/nautobot/nautobot.key:ro" + # - "./nautobot.crt:/opt/nautobot/nautobot.crt:ro" + celery_worker: + entrypoint: + - "sh" + - "-c" # this is to evaluate the $NAUTOBOT_LOG_LEVEL from the env + - "nautobot-server celery worker -l $$NAUTOBOT_LOG_LEVEL --events" ## $$ because of docker-compose + depends_on: + - "nautobot" + healthcheck: + interval: "30s" + timeout: "10s" + start_period: "30s" + retries: 3 + test: + [ + "CMD", + "bash", + "-c", + "nautobot-server celery inspect ping --destination celery@$$HOSTNAME" ## $$ because of docker-compose + ] + <<: *nautobot-base + celery_beat: + entrypoint: + - "sh" + - "-c" # this is to evaluate the $NAUTOBOT_LOG_LEVEL from the env + - "nautobot-server celery beat -l $$NAUTOBOT_LOG_LEVEL" ## $$ because of docker-compose + depends_on: + - "nautobot" + healthcheck: + disable: true + <<: *nautobot-base + redis: + image: "redis:6-alpine" + command: + - "sh" + - "-c" # this is to evaluate the $NAUTOBOT_REDIS_PASSWORD from the env + - "redis-server --appendonly yes --requirepass $$NAUTOBOT_REDIS_PASSWORD" + env_file: + - "local.env" + - "creds.env" diff --git a/environments/docker-compose.ldap.yml b/environments/docker-compose.ldap.yml new file mode 100644 index 000000000..e7841f4d0 --- /dev/null +++ b/environments/docker-compose.ldap.yml @@ -0,0 +1,67 @@ +--- +version: "3.8" +x-nautobot-build: &nautobot-build + build: + args: + NAUTOBOT_VERSION: "${NAUTOBOT_VERSION}" + PYTHON_VER: "${PYTHON_VER}" + context: "../" + target: "nautobot" + dockerfile: "environments/Dockerfile-LDAP" +x-nautobot-base: &nautobot-base + image: "companyname/nautobot-ldap" + env_file: + - "local.env" + - "creds.env" + tty: true + +services: + nautobot: + depends_on: + - "db" + - "redis" + <<: [*nautobot-base, *nautobot-build] + # volumes: + # - "./nautobot.key:/opt/nautobot/nautobot.key:ro" + # - "./nautobot.crt:/opt/nautobot/nautobot.crt:ro" + celery_worker: + entrypoint: + - "sh" + - "-c" # this is to evaluate the $NAUTOBOT_LOG_LEVEL from the env + - "nautobot-server celery worker -l $$NAUTOBOT_LOG_LEVEL --events" ## $$ because of docker-compose + depends_on: + - "nautobot" + healthcheck: + interval: "30s" + timeout: "10s" + start_period: "30s" + retries: 3 + test: + [ + "CMD", + "bash", + "-c", + "nautobot-server celery inspect ping --destination celery@$$HOSTNAME" ## $$ because of docker-compose + ] + <<: *nautobot-base + celery_beat: + entrypoint: + - "sh" + - "-c" # this is to evaluate the $NAUTOBOT_LOG_LEVEL from the env + - "nautobot-server celery beat -l $$NAUTOBOT_LOG_LEVEL" ## $$ because of docker-compose + depends_on: + - "nautobot" + healthcheck: + disable: true + <<: *nautobot-base + # --------------------------------- + redis: + image: "redis:alpine" + env_file: + - "local.env" + - "creds.env" + command: + - "sh" + - "-c" # this is to evaluate the $REDIS_PASSWORD from the env + - "redis-server --appendonly yes --requirepass $$NAUTOBOT_REDIS_PASSWORD" ## $$ because of docker-compose + restart: "unless-stopped" diff --git a/environments/docker-compose.local.yml b/environments/docker-compose.local.yml new file mode 100644 index 000000000..05bbfca77 --- /dev/null +++ b/environments/docker-compose.local.yml @@ -0,0 +1,20 @@ +--- +version: "3.8" +services: + nautobot: + command: "nautobot-server runserver 0.0.0.0:8080" + ports: + - "8080:8080" + volumes: + - "../config/nautobot_config.py:/opt/nautobot/nautobot_config.py" + - "../jobs:/opt/nautobot/jobs" + healthcheck: + interval: "30s" + timeout: "10s" + start_period: "60s" + retries: 3 + test: ["CMD", "true"] # Due to layering, disable: true won't work. Instead, change the test + celery_worker: + volumes: + - "../config/nautobot_config.py:/opt/nautobot/nautobot_config.py" + - "../jobs:/opt/nautobot/jobs" diff --git a/environments/docker-compose.mysql.yml b/environments/docker-compose.mysql.yml new file mode 100644 index 000000000..5527aa1f2 --- /dev/null +++ b/environments/docker-compose.mysql.yml @@ -0,0 +1,36 @@ +--- +version: "3.8" +services: + nautobot: + environment: + - "NAUTOBOT_DB_ENGINE=django.db.backends.mysql" + env_file: + - "local.env" + - "creds.env" + celery_worker: + environment: + - "NAUTOBOT_DB_ENGINE=django.db.backends.mysql" + env_file: + - "local.env" + - "creds.env" + db: + image: "mysql:8" + command: + - "--authentication_policy=caching_sha2_password" + - "--max_connections=1000" + env_file: + - "local.env" + - "creds.env" + volumes: + - "mysql_data:/var/lib/mysql" + healthcheck: + test: + - "CMD" + - "mysqladmin" + - "ping" + - "-h" + - "localhost" + timeout: "20s" + retries: 10 +volumes: + mysql_data: {} diff --git a/environments/docker-compose.postgres.yml b/environments/docker-compose.postgres.yml new file mode 100644 index 000000000..6c9125f03 --- /dev/null +++ b/environments/docker-compose.postgres.yml @@ -0,0 +1,22 @@ +--- +version: "3.8" +services: + db: + image: "postgres:13-alpine" + env_file: + - "local.env" + - "creds.env" + command: + - "-c" + - "max_connections=1000" + volumes: + # - "./nautobot.sql:/tmp/nautobot.sql" + - "postgres_data:/var/lib/postgresql/data" + healthcheck: + test: "pg_isready --username=$$POSTGRES_USER --dbname=$$POSTGRES_DB" + interval: "10s" + timeout: "5s" + retries: 10 + +volumes: + postgres_data: {} diff --git a/environments/local.example.env b/environments/local.example.env new file mode 100644 index 000000000..ca121e1af --- /dev/null +++ b/environments/local.example.env @@ -0,0 +1,39 @@ +# This should be limited to the hosts that are going to be the web app. +# https://docs.djangoproject.com/en/3.2/ref/settings/#allowed-hosts +NAUTOBOT_ALLOWED_HOSTS=* +NAUTOBOT_BANNER_TOP="Local" +NAUTOBOT_CHANGELOG_RETENTION=0 +NAUTOBOT_CONFIG=/opt/nautobot/nautobot_config.py +NAUTOBOT_DB_HOST=db +NAUTOBOT_DB_NAME=nautobot +NAUTOBOT_DB_USER=nautobot +NAUTOBOT_DEBUG=True +NAUTOBOT_DJANGO_EXTENSIONS_ENABLED=False +NAUTOBOT_DJANGO_TOOLBAR_ENABLED=False +NAUTOBOT_HIDE_RESTRICTED_UI=True +NAUTOBOT_LOG_LEVEL=WARNING +NAUTOBOT_METRICS_ENABLED=True +NAUTOBOT_NAPALM_TIMEOUT=5 +NAUTOBOT_MAX_PAGE_SIZE=0 + +# Postgres Container +POSTGRES_USER=${NAUTOBOT_DB_USER} +POSTGRES_DB=${NAUTOBOT_DB_NAME} + +# NAUTOBOT REDIS SETTINGS +# When updating NAUTOBOT_REDIS_PASSWORD, make sure to update the password in +# the NAUTOBOT_CACHEOPS_REDIS line as well! +# +NAUTOBOT_REDIS_HOST=redis +NAUTOBOT_REDIS_PORT=6379 +# Uncomment REDIS_SSL if using SSL +# NAUTOBOT_REDIS_SSL=True + +# Needed for MySQL, should match the values for Nautobot above +MYSQL_USER=nautobot +MYSQL_DATABASE=nautobot + +# LDAP environment variables +NAUTOBOT_AUTH_LDAP_SERVER_URI="changeme" +NAUTOBOT_AUTH_LDAP_BIND_DN="changeme" +NAUTOBOT_AUTH_LDAP_BIND_PASSWORD="changeme" diff --git a/invoke.example.yml b/invoke.example.yml new file mode 100644 index 000000000..e4420f2c5 --- /dev/null +++ b/invoke.example.yml @@ -0,0 +1,10 @@ +--- +nautobot_docker_compose: + project_name: "nautobot-docker-compose" + python_ver: "3.9" + local: false + compose_dir: "environments/" + compose_files: + - "docker-compose.postgres.yml" + - "docker-compose.base.yml" + - "docker-compose.local.yml" diff --git a/invoke.ldap.yml b/invoke.ldap.yml new file mode 100644 index 000000000..81031fbfa --- /dev/null +++ b/invoke.ldap.yml @@ -0,0 +1,10 @@ +--- +nautobot_docker_compose: + project_name: "nautobot-docker-compose" + python_ver: "3.9" + local: false + compose_dir: "environments/" + compose_files: + - "docker-compose.postgres.yml" + - "docker-compose.ldap.yml" + - "docker-compose.local.yml" diff --git a/invoke.mysql.yml b/invoke.mysql.yml new file mode 100644 index 000000000..b60e29efa --- /dev/null +++ b/invoke.mysql.yml @@ -0,0 +1,10 @@ +--- +nautobot_docker_compose: + project_name: "nautobot-docker-compose" + python_ver: "3.9" + local: false + compose_dir: "environments/" + compose_files: + - "docker-compose.mysql.yml" + - "docker-compose.base.yml" + - "docker-compose.local.yml" diff --git a/jobs/__init__.py b/jobs/__init__.py new file mode 100644 index 000000000..580522528 --- /dev/null +++ b/jobs/__init__.py @@ -0,0 +1 @@ +"""Jobs for nautobot_docker_compose.""" diff --git a/local.env.example b/local.env.example deleted file mode 100644 index 53e2516db..000000000 --- a/local.env.example +++ /dev/null @@ -1,48 +0,0 @@ -# --------------------- -# PYTHON_VER is used for which version of Python to use. Check hub.docker.com for the available versions -# --------------------- -PYTHON_VER=3.9 - -# This should be limited to the hosts that are going to be the web app. -# https://docs.djangoproject.com/en/3.2/ref/settings/#allowed-hosts -NAUTOBOT_ALLOWED_HOSTS=* -NAUTOBOT_CHANGELOG_RETENTION=0 -NAUTOBOT_CONFIG=/opt/nautobot/nautobot_config.py -NAUTOBOT_DB_HOST=db -NAUTOBOT_DB_NAME=nautobot -NAUTOBOT_DB_PASSWORD=decinablesprewad -NAUTOBOT_DB_USER=nautobot -NAUTOBOT_MAX_PAGE_SIZE=0 -NAUTOBOT_NAPALM_TIMEOUT=5 - -# NAUTOBOT REDIS SETTINGS -# When updating NAUTOBOT_REDIS_PASSWORD, make sure to update the password in -# the NAUTOBOT_CACHEOPS_REDIS line as well! -# -NAUTOBOT_REDIS_HOST=redis -NAUTOBOT_REDIS_PASSWORD=decinablesprewad -NAUTOBOT_CACHEOPS_REDIS=redis://:decinablesprewad@redis:6379/1 -NAUTOBOT_REDIS_PORT=6379 -# Uncomment REDIS_SSL if using SSL -# NAUTOBOT_REDIS_SSL=True -NAUTOBOT_SECRET_KEY=012345678901234567890123456789012345678901234567890123456789 -# Needed for Postgres should match the values for Nautobot above -PGPASSWORD=decinablesprewad -POSTGRES_DB=nautobot -POSTGRES_PASSWORD=decinablesprewad -POSTGRES_USER=nautobot - -# Needed for MariaDB, should match the values for Nautobot above -MYSQL_USER=nautobot -MYSQL_PASSWORD=decinablesprewad -MYSQL_DATABASE=nautobot -MYSQL_ROOT_PASSWORD=decinablesprewad - -NAUTOBOT_HIDE_RESTRICTED_UI=True -NAUTOBOT_LOG_LEVEL=WARNING - -NAUTOBOT_CREATE_SUPERUSER=false -NAUTOBOT_SUPERUSER_NAME=admin -NAUTOBOT_SUPERUSER_EMAIL=admin@example.com -NAUTOBOT_SUPERUSER_PASSWORD=admin -NAUTOBOT_SUPERUSER_API_TOKEN=0123456789abcdef0123456789abcdef01234567 \ No newline at end of file diff --git a/plugin_example/Dockerfile-Plugins b/plugin_example/Dockerfile-Plugins deleted file mode 100644 index 08f8f36a7..000000000 --- a/plugin_example/Dockerfile-Plugins +++ /dev/null @@ -1,11 +0,0 @@ -ARG PYTHON_VER - -ARG NAUTOBOT_VERSION=1.5.9 -FROM networktocode/nautobot:${NAUTOBOT_VERSION}-py${PYTHON_VER} - -RUN pip install --upgrade pip wheel - -COPY ./plugin_requirements.txt /opt/nautobot/ -RUN pip install --no-warn-script-location -r /opt/nautobot/plugin_requirements.txt - -COPY config/nautobot_config.py /opt/nautobot/nautobot_config.py diff --git a/plugin_example/config/nautobot_config.py b/plugin_example/config/nautobot_config.py deleted file mode 100644 index 720a7e0ad..000000000 --- a/plugin_example/config/nautobot_config.py +++ /dev/null @@ -1,322 +0,0 @@ -import os -import sys - -from nautobot.core.settings import * # noqa F401,F403 -from nautobot.core.settings_funcs import is_truthy - -######################### -# # -# Required settings # -# # -######################### - -# This is a list of valid fully-qualified domain names (FQDNs) for the Nautobot server. Nautobot will not permit write -# access to the server via any other hostnames. The first FQDN in the list will be treated as the preferred name. -# -# Example: ALLOWED_HOSTS = ['nautobot.example.com', 'nautobot.internal.local'] -ALLOWED_HOSTS = os.getenv("NAUTOBOT_ALLOWED_HOSTS").split(",") - -# PostgreSQL database configuration. See the Django documentation for a complete list of available parameters: -# https://docs.djangoproject.com/en/stable/ref/settings/#databases -DATABASES = { - "default": { - "NAME": os.getenv("NAUTOBOT_DB_NAME", "nautobot"), # Database name - "USER": os.getenv("NAUTOBOT_DB_USER", ""), # Database username - "PASSWORD": os.getenv("NAUTOBOT_DB_PASSWORD", ""), # Database password - "HOST": os.getenv("NAUTOBOT_DB_HOST", "localhost"), # Database server - "PORT": os.getenv("NAUTOBOT_DB_PORT", ""), # Database port (leave blank for default) - "CONN_MAX_AGE": os.getenv("NAUTOBOT_DB_TIMEOUT", 300), # Database timeout - "ENGINE": "django.db.backends.postgresql", # Database driver (Postgres only supported!) - } -} - -# Nautobot uses RQ for task scheduling. These are the following defaults. -# For detailed configuration see: https://github.com/rq/django-rq#installation -# These defaults utilize the Django `CACHES` setting defined above for django-redis. -# See: https://github.com/rq/django-rq#support-for-django-redis-and-django-redis-cache -RQ_QUEUES = { - "default": { - "USE_REDIS_CACHE": "default", - }, - "check_releases": { - "USE_REDIS_CACHE": "default", - }, - "custom_fields": { - "USE_REDIS_CACHE": "default", - }, - "webhooks": { - "USE_REDIS_CACHE": "default", - }, -} - -# Nautobot uses Cacheops for database query caching. These are the following defaults. -# For detailed configuration see: https://github.com/Suor/django-cacheops#setup -# Set Cache Ops variables -redis_protocol = "rediss" if is_truthy(os.getenv("NAUTOBOT_REDIS_SSL", False)) else "redis" -cache_ops_pwd = os.getenv("NAUTOBOT_REDIS_PASSWORD") -cache_ops_host = os.getenv("NAUTOBOT_REDIS_HOST", "localhost") -cache_ops_user = os.getenv("NAUTOBOT_REDIS_USER") -cache_ops_port = int(os.getenv("NAUTOBOT_REDIS_PORT", 6379)) - -CACHEOPS_REDIS = os.getenv("NAUTOBOT_CACHEOPS_REDIS", f"{redis_protocol}://:{cache_ops_pwd}@{cache_ops_host}:{cache_ops_port}/1") - -# The django-redis cache is used to establish concurrent locks using Redis. The -# django-rq settings will use the same instance/database by default. -CACHES = { - "default": { - "BACKEND": "django_redis.cache.RedisCache", - "LOCATION": f"{redis_protocol}://:{cache_ops_pwd}@{cache_ops_host}:{cache_ops_port}/0", - "TIMEOUT": 300, - "OPTIONS": { - "CLIENT_CLASS": "django_redis.client.DefaultClient", - "PASSWORD": "", - }, - } -} - -# This key is used for secure generation of random numbers and strings. It must never be exposed outside of this file. -# For optimal security, SECRET_KEY should be at least 50 characters in length and contain a mix of letters, numbers, and -# symbols. Nautobot will not run without this defined. For more information, see -# https://docs.djangoproject.com/en/stable/ref/settings/#std:setting-SECRET_KEY -SECRET_KEY = os.getenv("NAUTOBOT_SECRET_KEY", "v8b0_x=$*xk#(qyy#0^&z6a$l=3#i8ohm5guu%yf@dtxh3rub%") - - -######################### -# # -# Optional settings # -# # -######################### - -# Specify one or more name and email address tuples representing Nautobot administrators. These people will be notified of -# application errors (assuming correct email settings are provided). -ADMINS = [ - # ['John Doe', 'jdoe@example.com'], -] - -# URL schemes that are allowed within links in Nautobot -ALLOWED_URL_SCHEMES = ( - "file", - "ftp", - "ftps", - "http", - "https", - "irc", - "mailto", - "sftp", - "ssh", - "tel", - "telnet", - "tftp", - "vnc", - "xmpp", -) - -# Optionally display a persistent banner at the top and/or bottom of every page. HTML is allowed. To display the same -# content in both banners, define BANNER_TOP and set BANNER_BOTTOM = BANNER_TOP. -BANNER_TOP = os.getenv("NAUTOBOT_BANNER_TOP", "") -BANNER_BOTTOM = os.getenv("NAUTOBOT_BANNER_BOTTOM", "") - -# Text to include on the login page above the login form. HTML is allowed. -BANNER_LOGIN = os.getenv("NAUTOBOT_BANNER_LOGIN", "") - -# Cache timeout in seconds. Cannot be 0. Defaults to 900 (15 minutes). To disable caching, set CACHEOPS_ENABLED to False -CACHEOPS_DEFAULTS = {"timeout": int(os.getenv("NAUTOBOT_CACHEOPS_TIMEOUT", 900))} - -# Set to False to disable caching with cacheops. (Default: True) -CACHEOPS_ENABLED = is_truthy(os.getenv("NAUTOBOT_CACHEOPS_ENABLED", True)) - -# Maximum number of days to retain logged changes. Set to 0 to retain changes indefinitely. (Default: 90) -CHANGELOG_RETENTION = int(os.getenv("NAUTOBOT_CHANGELOG_RETENTION", 90)) - -# If True, all origins will be allowed. Other settings restricting allowed origins will be ignored. -# Defaults to False. Setting this to True can be dangerous, as it allows any website to make -# cross-origin requests to yours. Generally you'll want to restrict the list of allowed origins with -# CORS_ALLOWED_ORIGINS or CORS_ALLOWED_ORIGIN_REGEXES. -CORS_ALLOW_ALL_ORIGINS = is_truthy(os.getenv("NAUTOBOT_CORS_ALLOW_ALL_ORIGINS", False)) - -# A list of origins that are authorized to make cross-site HTTP requests. Defaults to []. -CORS_ALLOWED_ORIGINS = [ - # 'https://hostname.example.com', -] - -# A list of strings representing regexes that match Origins that are authorized to make cross-site -# HTTP requests. Defaults to []. -CORS_ALLOWED_ORIGIN_REGEXES = [ - # r'^(https?://)?(\w+\.)?example\.com$', -] - -# FQDNs that are considered trusted origins for secure, cross-domain, requests such as HTTPS POST. -# If running Nautobot under a single domain, you may not need to set this variable; -# if running on multiple domains, you *may* need to set this variable to more or less the same as ALLOWED_HOSTS above. -# https://docs.djangoproject.com/en/stable/ref/settings/#csrf-trusted-origins -CSRF_TRUSTED_ORIGINS = [] - -# Set to True to enable server debugging. WARNING: Debugging introduces a substantial performance penalty and may reveal -# sensitive information about your installation. Only enable debugging while performing testing. Never enable debugging -# on a production system. -DEBUG = is_truthy(os.getenv("NAUTOBOT_DEBUG", False)) - -# Enforcement of unique IP space can be toggled on a per-VRF basis. To enforce unique IP space -# within the global table (all prefixes and IP addresses not assigned to a VRF), set -# ENFORCE_GLOBAL_UNIQUE to True. -ENFORCE_GLOBAL_UNIQUE = is_truthy(os.getenv("NAUTOBOT_ENFORCE_GLOBAL_UNIQUE", False)) - -# Exempt certain models from the enforcement of view permissions. Models listed here will be viewable by all users and -# by anonymous users. List models in the form `.`. Add '*' to this list to exempt all models. -EXEMPT_VIEW_PERMISSIONS = [ - # 'dcim.site', - # 'dcim.region', - # 'ipam.prefix', -] - -# Global 3rd-party authentication settings -EXTERNAL_AUTH_DEFAULT_GROUPS = [] -EXTERNAL_AUTH_DEFAULT_PERMISSIONS = {} - -# If hosting Nautobot in a subdirectory, you must set this value to match the base URL prefix configured in your HTTP server (e.g. `/nautobot/`). When not set, URLs will default to being prefixed by `/`. -FORCE_SCRIPT_NAME = None - -# When set to `True`, users with limited permissions will only be able to see items in the UI they have access too. -HIDE_RESTRICTED_UI = is_truthy(os.getenv("NAUTOBOT_HIDE_RESTRICTED_UI", False)) - -# HTTP proxies Nautobot should use when sending outbound HTTP requests (e.g. for webhooks). -# HTTP_PROXIES = { -# 'http': 'http://10.10.1.10:3128', -# 'https': 'http://10.10.1.10:1080', -# } - -# IP addresses recognized as internal to the system. The debugging toolbar will be available only to clients accessing -# Nautobot from an internal IP. -INTERNAL_IPS = ("127.0.0.1", "::1") - -# Setting this to True will display a "maintenance mode" banner at the top of every page. -MAINTENANCE_MODE = is_truthy(os.getenv("NAUTOBOT_MAINTENANCE_MODE", False)) - -# An API consumer can request an arbitrary number of objects =by appending the "limit" parameter to the URL (e.g. -# "?limit=1000"). This setting defines the maximum limit. Setting it to 0 or None will allow an API consumer to request -# all objects by specifying "?limit=0". -MAX_PAGE_SIZE = int(os.getenv("NAUTOBOT_MAX_PAGE_SIZE", 1000)) - -# The file path where uploaded media such as image attachments are stored. A trailing slash is not needed. Note that -# the default value of this setting is within the invoking user's home directory -# MEDIA_ROOT = os.path.expanduser('~/.nautobot/media') - -# By default uploaded media is stored on the local filesystem. Using Django-storages is also supported. Provide the -# class path of the storage driver in STORAGE_BACKEND and any configuration options in STORAGE_CONFIG. For example: -# STORAGE_BACKEND = 'storages.backends.s3boto3.S3Boto3Storage' -# STORAGE_CONFIG = { -# 'AWS_ACCESS_KEY_ID': 'Key ID', -# 'AWS_SECRET_ACCESS_KEY': 'Secret', -# 'AWS_STORAGE_BUCKET_NAME': 'nautobot', -# 'AWS_S3_REGION_NAME': 'eu-west-1', -# } - -# Expose Prometheus monitoring metrics at the HTTP endpoint '/metrics' -METRICS_ENABLED = is_truthy(os.getenv("NAUTOBOT_METRICS_ENABLED", False)) - -# Credentials that Nautobot will uses to authenticate to devices when connecting via NAPALM. -NAPALM_USERNAME = os.getenv("NAUTOBOT_NAPALM_USERNAME", "") -NAPALM_PASSWORD = os.getenv("NAUTOBOT_NAPALM_PASSWORD", "") - -# NAPALM timeout (in seconds). (Default: 30) -NAPALM_TIMEOUT = int(os.getenv("NAUTOBOT_NAPALM_TIMEOUT", 30)) - -# NAPALM optional arguments (see https://napalm.readthedocs.io/en/latest/support/#optional-arguments). Arguments must -# be provided as a dictionary. -NAPALM_ARGS = {} - -# Determine how many objects to display per page within a list. (Default: 50) -PAGINATE_COUNT = int(os.getenv("NAUTOBOT_PAGINATE_COUNT", 50)) - -# Enable installed plugins. Add the name of each plugin to the list. -PLUGINS = ["nautobot_device_onboarding"] - -# Plugins configuration settings. These settings are used by various plugins that the user may have installed. -# Each key in the dictionary is the name of an installed plugin and its value is a dictionary of settings. -# PLUGINS_CONFIG = { -# 'my_plugin': { -# 'foo': 'bar', -# 'buzz': 'bazz' -# } -# } - -# When determining the primary IP address for a device, IPv6 is preferred over IPv4 by default. Set this to True to -# prefer IPv4 instead. -PREFER_IPV4 = is_truthy(os.getenv("NAUTOBOT_PREFER_IPV4", False)) - -# Rack elevation size defaults, in pixels. For best results, the ratio of width to height should be roughly 10:1. -RACK_ELEVATION_DEFAULT_UNIT_HEIGHT = int(os.getenv("NAUTOBOT_RACK_ELEVATION_DEFAULT_UNIT_HEIGHT", 22)) -RACK_ELEVATION_DEFAULT_UNIT_WIDTH = int(os.getenv("NAUTOBOT_RACK_ELEVATION_DEFAULT_UNIT_WIDTH", 220)) - -# Remote auth backend settings -REMOTE_AUTH_AUTO_CREATE_USER = False -REMOTE_AUTH_HEADER = "HTTP_REMOTE_USER" - -# This determines how often the GitHub API is called to check the latest release of Nautobot. Must be at least 1 hour. -RELEASE_CHECK_TIMEOUT = int(os.getenv("NAUTOBOT_RELEASE_CHECK_TIMEOUT", 24 * 3600)) - -# This repository is used to check whether there is a new release of Nautobot available. Set to None to disable the -# version check or use the URL below to check for release in the official Nautobot repository. -RELEASE_CHECK_URL = os.getenv("NAUTOBOT_RELEASE_CHECK_URL", None) -# RELEASE_CHECK_URL = 'https://api.github.com/repos/nautobot/nautobot/releases' - -# The length of time (in seconds) for which a user will remain logged into the web UI before being prompted to -# re-authenticate. (Default: 1209600 [14 days]) -SESSION_COOKIE_AGE = int(os.getenv("NAUTOBOT_SESSION_COOKIE_AGE", 1209600)) # 2 weeks, in seconds - -# By default, Nautobot will store session data in the database. Alternatively, a file path can be specified here to use -# local file storage instead. (This can be useful for enabling authentication on a standby instance with read-only -# database access.) Note that the user as which Nautobot runs must have read and write permissions to this path. -SESSION_FILE_PATH = os.getenv("NAUTOBOT_SESSION_FILE_PATH", None) - -# Configure SSO, for more information see docs/configuration/authentication/sso.md -SOCIAL_AUTH_POSTGRES_JSONFIELD = False - -# Time zone (default: UTC) -TIME_ZONE = os.getenv("NAUTOBOT_TIME_ZONE", "UTC") - -# Date/time formatting. See the following link for supported formats: -# https://docs.djangoproject.com/en/stable/ref/templates/builtins/#date -DATE_FORMAT = os.getenv("NAUTOBOT_DATE_FORMAT", "N j, Y") -SHORT_DATE_FORMAT = os.getenv("NAUTOBOT_SHORT_DATE_FORMAT", "Y-m-d") -TIME_FORMAT = os.getenv("NAUTOBOT_TIME_FORMAT", "g:i a") -SHORT_TIME_FORMAT = os.getenv("NAUTOBOT_SHORT_TIME_FORMAT", "H:i:s") -DATETIME_FORMAT = os.getenv("NAUTOBOT_DATETIME_FORMAT", "N j, Y g:i a") -SHORT_DATETIME_FORMAT = os.getenv("NAUTOBOT_SHORT_DATETIME_FORMAT", "Y-m-d H:i") - -# A list of strings designating all applications that are enabled in this Django installation. Each string should be a dotted Python path to an application configuration class (preferred), or a package containing an application. -# https://nautobot.readthedocs.io/en/latest/configuration/optional-settings/#extra-applications -EXTRA_INSTALLED_APPS = [] -LOG_LEVEL = "DEBUG" if DEBUG else "INFO" -LOGGING = { - "version": 1, - "disable_existing_loggers": False, - "formatters": { - "normal": { - "format": "%(asctime)s.%(msecs)03d %(levelname)-7s %(name)s :\n %(message)s", - "datefmt": "%H:%M:%S", - }, - "verbose": { - "format": "%(asctime)s.%(msecs)03d %(levelname)-7s %(name)-20s %(filename)-15s %(funcName)30s() :\n %(message)s", - "datefmt": "%H:%M:%S", - }, - }, - "handlers": { - "normal_console": { - "level": "DEBUG", - "class": "rq.utils.ColorizingStreamHandler", - "formatter": "normal", - }, - }, - "loggers": { - "django": {"handlers": ["normal_console"], "level": LOG_LEVEL}, - "nautobot": { - "handlers": ["normal_console"], - "level": LOG_LEVEL, - }, - "rq.worker": { - "handlers": ["normal_console"], - "level": LOG_LEVEL, - }, - }, -} diff --git a/plugin_example/docker-compose.override.yml.example b/plugin_example/docker-compose.override.yml.example deleted file mode 100644 index 6f2c85eb5..000000000 --- a/plugin_example/docker-compose.override.yml.example +++ /dev/null @@ -1,36 +0,0 @@ ---- -version: "3.7" -services: - nautobot: - image: "yourrepo/nautobot-plugins:latest" - build: - context: "." - dockerfile: "Dockerfile-Plugins" - args: - PYTHON_VER: "${PYTHON_VER:-3.9}" - env_file: - - "local.env" - ports: - - "8443:8443" - - "8080:8080" - restart: "unless-stopped" - nautobot-worker: - image: "yourrepo/nautobot-plugins:latest" - build: - context: "." - dockerfile: "Dockerfile-Plugins" - args: - PYTHON_VER: "${PYTHON_VER:-3.9}" - env_file: - - "local.env" - restart: "unless-stopped" - celery_worker: - image: "yourrepo/nautobot-plugins:latest" - build: - context: "." - dockerfile: "Dockerfile-Plugins" - args: - PYTHON_VER: "${PYTHON_VER:-3.9}" - env_file: - - "local.env" - restart: "unless-stopped" diff --git a/plugin_example/plugin_requirements.txt b/plugin_example/plugin_requirements.txt deleted file mode 100644 index f2cd426bc..000000000 --- a/plugin_example/plugin_requirements.txt +++ /dev/null @@ -1 +0,0 @@ -nautobot-device-onboarding \ No newline at end of file diff --git a/plugins/plugin_example/nautobot_example_plugin/__init__.py b/plugins/plugin_example/nautobot_example_plugin/__init__.py new file mode 100644 index 000000000..9a4cade1f --- /dev/null +++ b/plugins/plugin_example/nautobot_example_plugin/__init__.py @@ -0,0 +1,21 @@ +"""Nautobot plugin for example.""" +__version__ = "0.1.0" + +from nautobot.extras.plugins import PluginConfig + + +class ExampleConfig(PluginConfig): + """Plugin configuration for the nautobot_example plugin.""" + + name = "nautobot_example_plugin" + verbose_name = "Simple project for example" + version = "0.1.1" + author = "Network to Code" + description = "" + base_url = "example" + required_settings = [] + default_settings = {} + caching_config = {} + + +config = ExampleConfig # pylint: disable=invalid-name diff --git a/plugins/plugin_example/pyproject.toml b/plugins/plugin_example/pyproject.toml new file mode 100644 index 000000000..a7cee818b --- /dev/null +++ b/plugins/plugin_example/pyproject.toml @@ -0,0 +1,48 @@ +[tool.poetry] +name = "nautobot_example_plugin" +version = "0.1.0" +description = "" +authors = ["Network to Code "] + +[tool.poetry.dependencies] +python = "^3.8,<3.12" +nautobot = "^2.0.0" +nautobot-device-onboarding = "^3.0.0" + +[tool.poetry.dev-dependencies] +bandit = "*" +black = "*" +invoke = "*" +pydocstyle = "*" +pylint = "*" +pylint-django = "*" +pytest = "*" +requests_mock = "*" +yamllint = "*" + +[tool.black] +line-length = 120 +target-version = ['py36'] +include = '\.pyi?$' +exclude = ''' +( + /( + \.eggs # exclude a few common directories in the + | \.git # root of the project + | \.hg + | \.mypy_cache + | \.tox + | \.venv + | _build + | buck-out + | build + | dist + )/ + | settings.py # This is where you define files that should not be stylized by black + # the root of the project +) +''' + +[build-system] +requires = ["poetry-core>=1.0.0"] +build-backend = "poetry.core.masonry.api" \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 000000000..c3943fb27 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,18 @@ +[tool.poetry] +name = "nautobot-docker-compose" +version = "0.1.1" +description = "" +authors = ["John Doe "] + +[tool.poetry.dependencies] +python = ">=3.9,<3.12" +nautobot = "2.1.1" +nautobot-example-plugin = {path = "plugins/plugin_example", develop = true} + +[tool.poetry.dev-dependencies] +invoke = "*" +toml = "*" + +[build-system] +requires = ["poetry-core>=1.0.0"] +build-backend = "poetry.core.masonry.api" diff --git a/tasks.py b/tasks.py new file mode 100644 index 000000000..36286526b --- /dev/null +++ b/tasks.py @@ -0,0 +1,275 @@ +"""Development Tasks.""" +from distutils.util import strtobool +from time import sleep +import os +import toml +from invoke import Collection, task as invoke_task + + +def is_truthy(arg): + """Convert "truthy" strings into Booleans. + + Examples: + >>> is_truthy('yes') + True + Args: + arg (str): Truthy string (True values are y, yes, t, true, on and 1; false values are n, no, + f, false, off and 0. Raises ValueError if val is anything else. + """ + if isinstance(arg, bool): + return arg + return bool(strtobool(arg)) + + +# Use pyinvoke configuration for default values, see http://docs.pyinvoke.org/en/stable/concepts/configuration.html +# Variables may be overwritten in invoke.yml or by the environment variables INVOKE_NAUTOBOT_xxx +namespace = Collection("nautobot_docker_compose") +namespace.configure( + { + "nautobot-docker-compose": { + "project_name": "nautobot_docker_compose", + "python_ver": "3.8", + "local": False, + "use_django_extensions": True, + "compose_dir": os.path.join(os.path.dirname(__file__), "environments/"), + "compose_files": [ + "docker-compose.postgres.yml", + "docker-compose.base.yml", + "docker-compose.local.yml", + ], + } + } +) + +with open("pyproject.toml", "r", encoding="utf8") as pyproject: + parsed_toml = toml.load(pyproject) + +NAUTOBOT_VERSION = parsed_toml["tool"]["poetry"]["dependencies"]["nautobot"] + + +def task(function=None, *args, **kwargs): # pylint: disable=keyword-arg-before-vararg + """Task decorator to override the default Invoke task decorator.""" + + def task_wrapper(function=None): + """Wrap invoke.task to add the task to the namespace as well.""" + if args or kwargs: + task_func = invoke_task(*args, **kwargs)(function) + else: + task_func = invoke_task(function) + namespace.add_task(task_func) + return task_func + + if function: + # The decorator was called with no arguments + return task_wrapper(function) + # The decorator was called with arguments + return task_wrapper + + +def docker_compose(context, command, **kwargs): + """Run a specific docker-compose command with all appropriate parameters and environment. + + Args: + context (obj): Used to run specific commands + command (str): Command string to append to the "docker-compose ..." command, such as "build", "up", etc. + **kwargs: Passed through to the context.run() call. + """ + compose_env = { + "PYTHON_VER": context.nautobot_docker_compose.python_ver, + "NAUTOBOT_VERSION": NAUTOBOT_VERSION, + } + compose_command = f'docker compose --project-name {context.nautobot_docker_compose.project_name} --project-directory "{context.nautobot_docker_compose.compose_dir}"' + for compose_file in context.nautobot_docker_compose.compose_files: + compose_file_path = os.path.join( + context.nautobot_docker_compose.compose_dir, compose_file + ) + compose_command += f' -f "{compose_file_path}"' + compose_command += f" {command}" + print(f'Running docker compose command "{command}"') + return context.run(compose_command, env=compose_env, **kwargs) + + +def run_command(context, command, **kwargs): + """Run a command locally or inside the nautobot container.""" + if is_truthy(context.nautobot_docker_compose.local): + context.run(command) + else: + # Check if nautobot is running, no need to start another nautobot container to run a command + docker_compose_status = "ps --services --filter status=running" + results = docker_compose(context, docker_compose_status, hide="out") + if "nautobot" in results.stdout: + compose_command = f"exec nautobot {command}" + else: + compose_command = f"run --entrypoint '{command}' nautobot" + + docker_compose(context, compose_command, pty=True) + + +# ------------------------------------------------------------------------------ +# BUILD +# ------------------------------------------------------------------------------ +@task( + help={ + "force_rm": "Always remove intermediate containers", + "cache": "Whether to use Docker's cache when building the image (defaults to enabled)", + } +) +def build(context, force_rm=False, cache=True): + """Build Nautobot docker image.""" + command = "build" + + if not cache: + command += " --no-cache" + if force_rm: + command += " --force-rm" + + print( + f"Building Nautobot {NAUTOBOT_VERSION} with Python {context.nautobot_docker_compose.python_ver}..." + ) + docker_compose(context, command) + + +# ------------------------------------------------------------------------------ +# START / STOP / DEBUG +# ------------------------------------------------------------------------------ +@task +def debug(context): + """Start Nautobot and its dependencies in debug mode.""" + print("Starting Nautobot in debug mode...") + docker_compose(context, "up") + + +@task +def start(context): + """Start Nautobot and its dependencies in detached mode.""" + print("Starting Nautobot in detached mode...") + docker_compose(context, "up --detach") + + +@task +def restart(context): + """Gracefully restart all containers.""" + print("Restarting Nautobot...") + docker_compose(context, "restart") + + +@task +def stop(context): + """Stop Nautobot and its dependencies.""" + print("Stopping Nautobot...") + docker_compose(context, "down") + + +@task +def destroy(context): + """Destroy all containers and volumes.""" + print("Destroying Nautobot...") + docker_compose(context, "down --volumes") + + +# ------------------------------------------------------------------------------ +# ACTIONS +# ------------------------------------------------------------------------------ +@task +def nbshell(context): + """Launch an interactive nbshell session.""" + if context.nautobot_docker_compose.use_django_extensions: + command = "nautobot-server shell_plus" + else: + command = "nautobot-server nbshell" + + run_command(context, command, pty=True) + + +@task +def cli(context): + """Launch a bash shell inside the running Nautobot container.""" + run_command(context, "bash") + + +@task( + help={ + "user": "name of the superuser to create (default: admin)", + } +) +def createsuperuser(context, user="admin"): + """Create a new Nautobot superuser account (default: "admin"), will prompt for password.""" + command = f"nautobot-server createsuperuser --username {user}" + + run_command(context, command) + + +@task +def migrate(context): + """Perform migrate operation in Django.""" + command = "nautobot-server migrate" + + run_command(context, command) + + +@task +def post_upgrade(context): + """ + Nautobot common post-upgrade operations using a single entrypoint. + + This will run the following management commands with default settings, in order: + + - migrate + - trace_paths + - collectstatic + - remove_stale_contenttypes + - clearsessions + - invalidate all + """ + command = "nautobot-server post_upgrade" + + run_command(context, command) + + +@task +def import_nautobot_data(context): + """Import nautobot_data.json.""" + # This task expects to be run in the docker container for now + context.nautobot_docker_compose.local = False + copy_cmd = f"docker cp nautobot_data.json {context.nautobot_docker_compose.project_name}_nautobot_1:/tmp/nautobot_data.json" + import_cmd = "nautobot-server import_nautobot_json /tmp/nautobot_data.json 2.10.4" + print("Starting Nautobot") + start(context) + print("Copying Nautobot data to container") + context.run(copy_cmd) + print("Starting Import") + print(import_cmd) + run_command(context, import_cmd) + + +@task +def db_export(context): + """Export the database from the dev environment to nautobot.sql.""" + docker_compose(context, "up -d postgres") + sleep(2) # Wait for the database to be ready + + print("Exporting the database as an SQL dump...") + export_cmd = 'exec postgres sh -c "pg_dump -h localhost -d \${NAUTOBOT_DB_NAME} -U \${NAUTOBOT_DB_USER} > /tmp/nautobot.sql"' # noqa: W605 pylint: disable=anomalous-backslash-in-string + docker_compose(context, export_cmd, pty=True) + + copy_cmd = f"docker cp {context.nautobot_docker_compose.project_name}_postgres_1:/tmp/nautobot.sql dev/nautobot.sql" + print("Copying the SQL Dump locally...") + context.run(copy_cmd) + + +@task +def db_import(context): + """Install the backup of Nautobot db into development environment.""" + print("Importing Database into Development...\n") + + print("Starting Postgres for DB import...\n") + docker_compose(context, "up -d postgres") + sleep(2) + + print("Copying DB Dump to DB container...\n") + copy_cmd = f"docker cp dev/nautobot.sql {context.nautobot_docker_compose.project_name}_postgres_1:/tmp/nautobot.sql" + context.run(copy_cmd) + + print("Importing DB...\n") + import_cmd = 'exec postgres sh -c "psql -h localhost -U \${NAUTOBOT_DB_USER} < /tmp/nautobot.sql"' # noqa: W605 pylint: disable=anomalous-backslash-in-string + docker_compose(context, import_cmd, pty=True)