Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/lae/ansible-role-netbox

Cross-platform Ansible role for deploying NetBox, a DCIM/IPAM tool, in a production environment.
https://github.com/lae/ansible-role-netbox

ansible dcim inventory-management ipam netbox

Last synced: about 1 month ago
JSON representation

Cross-platform Ansible role for deploying NetBox, a DCIM/IPAM tool, in a production environment.

Awesome Lists containing this project

README

        

:role-author: lae
:role-name: netbox
:role: {role-author}.{role-name}
:gh-name: {role-author}/ansible-role-{role-name}
:netbox-version: 3.7.3
= {role}
:toc:
:toc-placement: preamble
ifdef::env-github[]
:tip-caption: :bulb:
:warning-caption: :warning:
endif::[]

ifdef::env-github[]
image:https://img.shields.io/badge/role-{role}-blue?style=for-the-badge[Ansible Galaxy Role,link=https://galaxy.ansible.com/{role-author}/{role-name}]
endif::env-github[]

Deploys and configures https://github.com/netbox-community/netbox[NetBox], an IP address management (IPAM) and data center infrastructure management (DCIM) tool.

This role will deploy NetBox within its own virtualenv either by release tarball or via git using uWSGI as the application server.

Supports CentOS 7,8 / RHEL 9 / Debian 9,10,11,12 / Ubuntu 16, 18, 20 and 22.

Note that this role is slightly opinionated and differs from installation instructions from the NetBox documentation.
The main differences are:

* Uses distro-provided systemd instead of supervisord
* Uses uWSGI as an application server instead of gunicorn
* Hardens the NetBox/uWSGI service (see `templates/netbox.service.j2`)
* Will hot reload on upgrades and configuration changes

== Quickstart

Provided you have Ansible installed and are using defaults:

[source,bash,subs="attributes"]
----
ansible-galaxy install geerlingguy.postgresql davidwittman.redis {role}
ansible-galaxy collection install community.postgresql
ansible-playbook -i your.server.fqdn, ~/.ansible/roles/{role}/examples/playbook_single_host_deploy.yml -K
----

This will deploy NetBox and PostgreSQL on `your.server.fqdn`; once complete it
should be accessible on port 80. Modify if needed. Read below for more insight.

You can also use Vagrant, if you prefer, to bring up NetBox at `localhost:8080`:

[source,bash,subs="attributes"]
----
ansible-galaxy install geerlingguy.postgresql davidwittman.redis {role}
ansible-galaxy collection install community.postgresql
cd ~/.ansible/roles/{role}/
vagrant up
----

== Support/Contributing

If you would like to contribute to this role, please read `DEVELOPING.md` for
this repository's workflow and (optional) instructions on setting up a
development environment. This role uses the `lae.travis-lxc` role when testing
under Travis CI, which you can find definitions for in the `tests/` directory.

ifeval::["{role-author}" == "lae"]
For support or if you'd like to contribute to this role but want guidance, feel
free to ask in @lae's Discord server: https://discord.gg/cjqr6Fg

endif::[]
== Prerequisites

=== PostgreSQL

This role does not setup a PostgreSQL server (but will create a database if needed), so you'll need to setup a PostgreSQL server and create a database user separate from this role.
Take a look at the _Example Playbook_ section.

In addition, for Ansible 2.10+, you may need to install the `community.postgresql` collection.
It is recommended to specify this in your playbook's `requirements.yml` file.
For example:

[source,yaml]
----
---
collections:
- name: community.postgresql
version: 3.4.0
----

WARNING: NetBox v2.2.0+ require PostgreSQL 9.4 at the minimum, which may not be available in your distribution's repos.
You may want to use a role for this.

=== Redis

This role does not setup or manage a Redis instance. You may want to either
install `redis-server` via a task in `pre_tasks` within your playbook or use a
Redis installation role such as
https://galaxy.ansible.com/davidwittman/redis[DavidWittman.redis].

WARNING: NetBox v2.9.0+ require Redis 4.0 at the minimum. The role suggested
above defaults to a 2.8 version, so make sure you specify a newer version in a
role variable or deploy Redis 4.0+ another way.

== Role Variables

TIP: See `examples/` for some playbooks you could write for different scenarios.

WARNING: A few role variables are mandatory. Look for the bold *required* below.

[source,yaml]
----
netbox_stable: false
netbox_git: false
----

It's *required* to set one of the above variables to `true`. `netbox_stable`
tells the role to deploy by extracting tarball releases from GitHub, while
`netbox_git` tells the role to clone a NetBox git repository - they're mutually
exclusive.

[source,yaml,subs="attributes"]
----
netbox_stable_version: {netbox-version}
netbox_stable_uri: "https://github.com/netbox-community/netbox/archive/v{{ netbox_stable_version }}.tar.gz"
----

These can be configured to pin a version (e.g. increment to trigger an upgrade)
or deploy using a tarball located somewhere else. Useful for when you need to
modify something in a release or are deploying locally behind a firewall.

[source,yaml]
----
netbox_git_version: develop
netbox_git_uri: "https://github.com/netbox-community/netbox.git"
----

`netbox_git_version` can be any valid ref within a git repository.
`netbox_git_uri` can be used to point to e.g. an on-premise repo or a fork.

[source,yaml]
----
netbox_superuser_enabled: true
netbox_superuser_username: admin
#netbox_superuser_password: changeme
netbox_superuser_email: admin@localhost
netbox_superuser_create_token: false
----

These variables are used to configure a local superuser account. Disable this
if you do not want to create one (when using LDAP for example - though having a
local superuser may still be beneficial in that case). When enabled, it is
*required* to set the superuser password. This role will create a new superuser
if the user does not exist, or will modify an existing user if they're not a
superuser/have a different email or password. (Yes, you can use this to reset
your superuser password if you forget it.) `netbox_superuser_create_token` can
be used to generate a random API token for the superuser, if needed.

[source,yaml]
----
netbox_database: netbox
netbox_database_user: netbox
#netbox_database_password: changeme
#netbox_database_host: localhost
netbox_database_port: 5432
#netbox_database_socket: /var/run/postgresql
----

It is *required* to configure either a socket directory (to communicate over
UNIX sockets) or a host/password (to use TCP/IP). See the _Example Playbook_
section for more information on configuring the database.

Note that these are used to configure `DATABASE` in `configuration.py`.

[source,yaml]
----
netbox_database_conn_age: 300
----

To configure Netbox to keep database connections open longer than a single requests,
set `netbox_database_conn_age` to your preferred maximum connection age, in seconds.
300 seconds (5 minutes) is typically a good number to start with.

[source,yaml]
----
netbox_database_maintenance: postgres
----

If the postgres database is configured to only allow access to specific tables of the DB for the user configured with Netbox, you can set `netbox_database_maintenance` to replace the default database used for connection checking to a different table than the default `postgres`. This is an empty table in every postgres database by default, but some configurations might block access to this table, so a different table (i.e. `netbox_prod`) can be used here instead.

[source,yaml]
----
# Example usage, default is empty dict
netbox_database_options:
sslmode: require
isolation_level: 3
----

If you need to set any other PostgreSQL parameter key words you can do
so here. For cases like https://docs.djangoproject.com/en/3.1/ref/databases/#isolation-level[isolation levels] the numerical value must be used
instead of the constant:
`psycopg2.extensions.ISOLATION_LEVEL_SERIALIZABLE` vs `3`.
Only add things here if you really know what you're doing.

[source,yaml]
----
netbox_redis_host: 127.0.0.1
netbox_redis_port: 6379
netbox_redis_password: ''
netbox_redis_database: 0
netbox_redis_default_timeout: 300
netbox_redis_ssl_enabled: false
netbox_redis_insecure_skip_tls_verify: false

netbox_redis_cache_host: "{{ netbox_redis_host }}"
netbox_redis_cache_port: "{{ netbox_redis_port }}"
netbox_redis_cache_database: 1
netbox_redis_cache_password: "{{ netbox_redis_password }}"
netbox_redis_cache_default_timeout: "{{ netbox_redis_default_timeout }}"
netbox_redis_cache_ssl_enabled: "{{ netbox_redis_ssl_enabled }}"
netbox_redis_cache_insecure_skip_tls_verify: "{{ netbox_redis_insecure_skip_tls_verify }}"
----

This populates the `REDIS` config dictionary in `configuration.py`. Use the
second set of variables if you wish to split your cache database from your
webhooks database.

[source,yaml]
----
netbox_redis_sentinels:
- { host: '192.168.0.1', port: '5000' },
- { host: '192.168.0.2', port: '5000' }
netbox_redis_sentinel_service: 'netbox'
netbox_redis_password: ''
netbox_redis_database: 0
netbox_redis_default_timeout: 300
netbox_redis_ssl_enabled: false

netbox_redis_cache_sentinels: "{{ netbox_redis_sentinels }}"
netbox_redis_cache_sentinel_service: "{{ netbox_redis_sentinel_service }}"
netbox_redis_cache_database: 1
netbox_redis_cache_password: "{{ netbox_redis_password }}"
netbox_redis_cache_default_timeout: "{{ netbox_redis_default_timeout }}"
netbox_redis_cache_ssl_enabled: "{{ netbox_redis_ssl_enabled }}"
----

Use this syntax if your redis is installed with sentinet architecture (multiple nodes). Use
the second set of variables if you wish to split your cache database from your
webhooks database.

[source,yaml]
----
netbox_rqworker_processes: 1
----

Specify how many request queue workers should be started by the systemd service.
You can leave this at the default of 1, unless you have a large number of reports,
scripts and other background tasks.

[source,yaml]
----
netbox_config:
#SECRET_KEY:
ALLOWED_HOSTS:
- localhost
- 127.0.0.1
#NAPALM_USERNAME:
#NAPALM_PASSWORD:
MEDIA_ROOT: "{{ netbox_shared_path }}/media"
REPORTS_ROOT: "{{ netbox_shared_path }}/reports"
SCRIPTS_ROOT: "{{ netbox_shared_path }}/scripts"
----

This is a dictionary of settings used to template NetBox's `configuration.py`.
See http://netbox.readthedocs.io/en/stable/configuration/mandatory-settings/[Mandatory Settings]
and http://netbox.readthedocs.io/en/stable/configuration/optional-settings/[Optional Settings]
from the NetBox documentation for more details, as well as
`examples/netbox_config.yml` in this repository.

It is not necessary to define `SECRET_KEY` here - this role will automatically
create one for you at `{{ netbox_shared_path }}/generated_secret_key`. The
`SECRET_KEY` will then be read from this file on subsequent runs, unless you
later do set this in your playbook. Note that you should define the
`SECRET_KEY` if you are deploying multiple NetBox instances behind one load
balancer.

If you have enabled NAPALM integration in this role, you will need to configure
NAPALM credentials here as well.

`MEDIA_ROOT`/`REPORTS_ROOT`/`SCRIPTS_ROOT`, while not mandatory in the NetBox
documentation, is mandatory in this role to prevent losing these files during
upgrades (this role does not upgrade NetBox in-place). It should be set to a
directory that is permanent and not lost on upgrade (the default, listed above,
can be used without issue). This role will attempt to create these directories
and change their ownership to whatever `netbox_user` is set to.

[source,yaml]
----
netbox_scripts: []
netbox_reports: []
----

https://netbox.readthedocs.io/en/stable/additional-features/custom-scripts/[Scripts]
and https://netbox.readthedocs.io/en/stable/additional-features/reports/[Reports]
to upload for use within NetBox. These should be lists of dictionaries with a
`src` attribute, specifying the local path to the script or report, and a
`name` attribute, specifying the module name (script/report name). For example:

[source,yaml]
----
## Example
netbox_scripts:
- src: netbox_scripts/migrate_application.py
name: migrate_application
netbox_reports:
- src: netbox_reports/devices.py
name: devices
----

This will copy `netbox_scripts/migrate_application.py` from your playbook
directory to `{{ netbox_config.SCRIPTS_ROOT }}/migrate_application.py` and
`netbox_reports/devices.py` to `{{ netbox.config.REPORTS_ROOT }}/devices.py`.

[source,yaml]
----
netbox_pip_packages: []

## Example:
netbox_pip_packages:
- https://github.com/steffann/netbox-example-plugin.git
- netbox-topology-views
----

This is a list of extra packages to install via `pip` within NetBox'
virtualenv. You can specify any valid artifact that `pip` understands.

If you list any plugins here, be sure to include the appropriate plugin
configurations within the `netbox_config` role variable. Read
https://netbox.readthedocs.io/en/stable/plugins/[Plugins] for more info.

[source,yaml]
----
netbox_user: netbox
netbox_group: netbox
netbox_home: /srv/netbox
netbox_releases_path: "{{ netbox_home }}/releases"
netbox_git_repo_path: "{{ netbox_releases_path }}/git-repo"
netbox_git_deploy_path: "{{ netbox_releases_path }}/git-deploy"
netbox_stable_path: "{{ netbox_releases_path }}/netbox-{{ netbox_stable_version }}"
netbox_current_path: "{{ netbox_home }}/current"
netbox_shared_path: "{{ netbox_home }}/shared"
----

These are all deployment details that you can modify to change the application
user and application storage locations. `netbox_releases_path` stores all
NetBox releases you've ever deployed. `netbox_git_repo_path` is where the Git
repository will be cloned to and should remain untouched - whilst
`netbox_git_deploy_path` is where a `git archive` using the ref
`netbox_git_version` will be extracted to. `netbox_stable_path` is the
extracted folder from a release tarball. `netbox_current_path` will be
symlinked to the selected release and used in service/configuration files as
the location NetBox is installed. `netbox_shared_path` is intended to store
configuration files and other "shared" content, like logs.

[source,yaml]
----
netbox_socket: "127.0.0.1:8000"
netbox_protocol: http
netbox_processes: "{{ ansible_processor_vcpus }}"
----

`netbox_socket` defines what the uWSGI service will bind to and can be set to
any valid https://www.freedesktop.org/software/systemd/man/systemd.socket.html#ListenStream=[ListenStream]
address (systemd socket). Set `netbox_protocol` to `uwsgi` if you want uWSGI to
speak WSGI (for instance if you're running nginx as a load balancer).
`netbox_processes` defines how many NetBox workers uWSGI will bring up to serve
requests.

[source,yaml]
----
netbox_application_log: "file:{{ netbox_shared_path }}/application.log"
netbox_requests_log: "file:{{ netbox_shared_path }}/requests.log"
----

These define where logs will be stored. You can use external logging facilities
instead of local files if you wish,
http://uwsgi-docs.readthedocs.io/en/latest/Logging.html#pluggable-loggers[as
long as uWSGI supports it]. Application log correlates to `logger` and
requests log to `req-logger`.

[source,yaml]
----
netbox_ldap_enabled: false
netbox_ldap_config_template: netbox_ldap_config.py.j2
----

Toggle `netbox_ldap_enabled` to `true` to configure LDAP authentication for
NetBox. `netbox_ldap_config_template` should be the path to your template - by
default, Ansible will search your playbook's `templates/` directory for this.
You can find an example in `examples/`. You will also need to set
`netbox_config.REMOTE_AUTH_BACKEND` to `netbox.authentication.LDAPBackend`.

TIP: By default, a local (non-LDAP) superuser will still be created by this
role. If this is undesirable, consider toggling `netbox_superuser_enabled`.

[source,yaml]
----
netbox_napalm_enabled: false
netbox_napalm_packages:
- napalm
----

Toggle `netbox_napalm_enabled` to enable NAPALM integration in NetBox. You must
define `NAPALM_USERNAME` and `NAPALM_PASSWORD` in the `netbox_config` variable
to be able to use NAPALM. Add extra NAPALM python libraries by listing them in
`netbox_napalm_packages` (e.g. `napalm-eos`).

[source,yaml]
netbox_metrics_enabled: false

Toggle `netbox_metrics_enabled` to `true` to enable application metrics (via
https://github.com/korfuri/django-prometheus[django-prometheus]). This adds
relevant pieces of configuration for proper metrics handling.
(https://netbox.readthedocs.io/en/stable/additional-features/prometheus-metrics/[more
info]).

[source,yaml]
----
netbox_metrics_dir: netbox_metrics
netbox_metrics_path: "/run/{{ netbox_metrics_dir }}"
----

The directory name where the metrics files are stored can be set with
`netbox_metrics_dir`. However, `netbox_metrics_path` must remain the default
(seen above) in order to work with `systemd` and the `RuntimeDirectory`
parameter (which only points to `/run`).

[source,yaml]
netbox_keep_uwsgi_updated: false

Toggle `netbox_keep_uwsgi_updated` to `true` if you wish to ensure your uwsgi
server is the latest release, otherwise uwsgi will not be updated on subsequent
runs of your playbook.

[source,yaml]
netbox_uwsgi_options: {}

Specify extra configuration options to insert into `uwsgi.ini` here. This is
expected to be a dictionary of key/value pairs, e.g. `buffer-size: 65535`.

[source,yaml]
netbox_uwsgi_in_venv: false

Toggle `netbox_uwsgi_in_venv` to `true` if you want `uwsgi` to be installed in the same virtual environment as NetBox.
Otherwise, it will be installed system-wide into the library path of the python version used to created the virtual environment (normal/legacy behavior).

WARNING: There's a possibility that this may become the default in a later version of this role (I think after further cross-platform testing).
See https://github.com/lae/ansible-role-netbox/issues/144[issue #144] for further details.

[source,yaml]
netbox_install_epel: true

Toggle `netbox_install_epel` to `false` if you do not want this role to install
the Fedora EPEL for you. This can be useful for enterprise environments where
the system's repositories are managed/mirrored by the enterprise.

[source,yaml]
----
netbox_packages: []
netbox_python_packages: []
netbox_python_binary: /usr/bin/python{{ some version }}
netbox_ldap_packages: []
----

These variables are dynamically generated based on the target distribution. You
can check the defaults for these underneath the `vars/` directory. You can use
these variables to target an unsupported operating system (although feel free
to open a PR to add in support!) or to specify a custom Python interpreter
(such as PyPy) to be used for deployment. Although, please note that support by
this role may be limited for alternative Python installations.

== Example Playbook

The following installs PostgreSQL and creates a user with @geerlingguy's robust
Postgres role, then proceeds to deploy and configure NetBox using a local unix
socket to talk to the Postgres server with the default netbox database user.

[source,yaml,subs="attributes"]
----
- hosts: netbox.idolactiviti.es
become: yes
roles:
- geerlingguy.postgresql
- davidwittman.redis
- {role}
vars:
netbox_stable: true
netbox_database_socket: "{{ postgresql_unix_socket_directories[0] }}"
netbox_superuser_password: netbox
netbox_socket: "0.0.0.0:80"
netbox_config:
ALLOWED_HOSTS:
- netbox.idolactiviti.es
MEDIA_ROOT: "{{ netbox_shared_path }}/media"
REPORTS_ROOT: "{{ netbox_shared_path }}/reports"
SCRIPTS_ROOT: "{{ netbox_shared_path }}/scripts"
postgresql_users:
- name: "{{ netbox_database_user }}"
role_attr_flags: CREATEDB,NOSUPERUSER
redis_bind: 127.0.0.1
redis_version: 6.0.9
redis_checksum: sha256:dc2bdcf81c620e9f09cfd12e85d3bc631c897b2db7a55218fd8a65eaa37f86dd
----

Note the `CREATEDB` attribute.

Assuming you have a PG server already running with the user `netbox_prod_user`
created, it owns a database called `netbox_prod`, and it allows the host you're
installing NetBox on to authenticate with it over TCP:

[source,yaml,subs="attributes"]
----
- hosts: netbox.idolactiviti.es
become: yes
roles:
- davidwittman.redis
- {role}
vars:
netbox_stable: true
netbox_superuser_password: netbox
netbox_socket: "0.0.0.0:80"
netbox_config:
ALLOWED_HOSTS:
- "{{ inventory_hostname }}"
MEDIA_ROOT: "{{ netbox_shared_path }}/media"
REPORTS_ROOT: "{{ netbox_shared_path }}/reports"
SCRIPTS_ROOT: "{{ netbox_shared_path }}/scripts"
netbox_database_host: pg-netbox.idolactiviti.es
netbox_database_port: 15432
netbox_database: netbox_prod
netbox_database_user: netbox_prod_user
netbox_database_password: "very_secure_password_for_prod"
netbox_database_maintenance: netbox_prod
redis_bind: 127.0.0.1
redis_version: 6.0.9
redis_checksum: sha256:dc2bdcf81c620e9f09cfd12e85d3bc631c897b2db7a55218fd8a65eaa37f86dd
----

See the `examples/` directory for more.

== Troubleshooting

=== uWSGI resetting TCP connections
When `netbox_protocol` is set to `http`, uWSGI might exhibit strange behaviour
and reset TCP connections seemingly at random. This can manifest in a
"connection reset by peer" error, for example when working with the API using
https://github.com/netbox-community/pynetbox[pynetbox]. If you are affected by
this, try switching `netbox_protocol` to `uwsgi` and using a loadbalancer, or
adjusting your `netbox_uwsgi_options` as follows. See https://github.com/lae/ansible-role-netbox/issues/130#issuecomment-847571006[this GitHub issue]
for a related discussion
[source,yaml,subs="attributes"]
----
netbox_uwsgi_options:
http-keepalive: "true"
http-auto-chunked: "true"
add-header: "Connection: Close"
----