feat(netbox): initial role

This commit is contained in:
Evelyn Alicke 2024-03-19 18:28:35 +01:00
parent 8221014ea1
commit 403177a77a
No known key found for this signature in database
GPG key ID: 6834780BDA479436
9 changed files with 408 additions and 0 deletions

34
playbooks/netbox.yml Normal file
View file

@ -0,0 +1,34 @@
---
- hosts: [netbox]
become: true
strategy: free
roles:
- role: famedly.base.postgresql_client_access
vars:
postgresql_client_access_users: "{{ netbox_postgresql_users }}"
postgresql_client_access_databases: "{{ netbox_postgresql_databases }}"
postgresql_client_access_hba_entries: "{{ netbox_postgresql_hba_entries }}"
- role: famedly.base.redis
become: true
vars:
redis_prefix: "netbox_"
redis_user: "{{ netbox_redis_username }}"
redis_secret: "{{ netbox_redis_password }}"
redis_docker_ports:
- "{{ famedly_docker_gateway_ip }}:6379:6379"
- role: famedly.services.netbox
vars:
routing_service_name: netbox
routing_server_port: "{{ netbox_container_port }}"
routing_traffic_public_rule: >-
HostRegexp(`{{ netbox_domain }}`, `{subdomain:.+}.{{ netbox_domain }}`)
&& !Path(`/debug/metrics`)
routing_traffic_metrics_rule: Path(`/{{ routing_service_name }}/metrics`)
routing_traffic_metrics_middlewares:
- replacepath
famedly_traefik_middlewares:
replacepath:
replacepath:
path: "/debug/metrics"
netbox_container_labels: "{{ famedly_traefik_labels_flat }}"

3
roles/netbox/README.md Normal file
View file

@ -0,0 +1,3 @@
# famedly.services.netbox
A role for deploying netbox, in a somewhat opinionated way.

View file

@ -0,0 +1,136 @@
---
netbox_path_base: /opt/netbox
netbox_version: "3.7.5"
netbox_user_name: netbox
netbox_fqdn: "https://{{ netbox_domain }}"
netbox_allowed_hosts:
- "{{ netbox_domain }}"
netbox_login_required: true
# Extra Plugins to install
netbox_plugins:
- 'netbox_topology_views'
- 'netbox_inventory'
- 'netbox_bgp'
# Quality of Life
netbox_protection_rules:
"dcim.site":
- "status":
- "eq": "decommisioning"
netbox_path_yaml_config: "{{ netbox_path_base }}/config"
netbox_path_state: "{{ netbox_path_base }}/state"
netbox_path_static: "{{ netbox_path_base }}/netbox/static"
netbox_path_socks: "{{ netbox_path_base }}/socks"
netbox_path_socks_uwsgi: "{{ netbox_path_socks }}/uwsgi.sock"
netbox_path_nginx_config: "{{ netbox_path_base }}/nginx.conf"
netbox_path_uwsgi_config: "{{ netbox_path_base }}/uwsgi.ini"
netbox_file_config_py: "{{ netbox_path_base }}/netbox/netbox/configuration.py"
netbox_container_port: 8000
netbox_container_name: "netbox"
netbox_container_env: {}
netbox_container_ports: []
netbox_container_labels_merged: >-
{{ netbox_container_labels_base |
combine(netbox_container_labels | default({})) }}
netbox_container_labels_base:
version: "{{ netbox_version }}"
netbox_container_volumes_common:
- "{{ netbox_path_base ~ '/configuration.py' ~ ':' ~ netbox_file_config_py }}"
- "{{ netbox_path_yaml_config ~ ':' ~ netbox_path_yaml_config }}"
- "{{ netbox_path_state ~ ':' ~ netbox_path_state }}"
- "{{ netbox_postgres_socket ~ ':' ~ netbox_postgres_socket }}"
- "{{ netbox_path_static ~ ':' ~ netbox_path_static }}"
- "{{ netbox_path_socks ~ ':' ~ netbox_path_socks }}"
- "{{ netbox_path_uwsgi_config ~ ':' ~ netbox_path_uwsgi_config }}"
- "/etc/passwd:/etc/passwd:ro"
netbox_container_volumes_nginx:
- "{{ netbox_path_nginx_config }}:/etc/nginx/conf.d/netbox.conf"
- "{{ netbox_path_state ~ ':' ~ netbox_path_state }}"
- "{{ netbox_path_static ~ ':' ~ netbox_path_static }}"
- "{{ netbox_path_socks ~ ':' ~ netbox_path_socks }}"
netbox_container_restart_policy: "always"
netbox_container_image_state: "present"
netbox_container_image_force_pull: true
netbox_container_image_reference: >-
{{
netbox_container_image_repository
~ ":"
~ netbox_container_image_tag | default('v' ~ netbox_version )
}}
netbox_container_image_repository: >-
{{
(
container_registries[netbox_container_image_registry]
| default(netbox_container_image_registry)
)
~ '/'
~ netbox_container_image_namespace | default('')
~ netbox_container_image_name
}}
netbox_container_nginx_image_reference: >-
{{
netbox_container_nginx_image_repository
~ ":"
~ netbox_container_nginx_image_tag | default('bookworm')
}}
netbox_container_nginx_image_repository: >-
{{
(
container_registries[netbox_container_nginx_image_registry]
| default(netbox_container_nginx_image_registry)
)
~ '/'
~ netbox_container_nginx_image_namespace | default('')
~ netbox_container_nginx_image_name
}}
netbox_container_image_registry: "docker-oss.nexus.famedly.de"
netbox_container_image_name: "netbox"
netbox_container_nginx_image_registry: "docker.io"
netbox_container_nginx_image_name: "nginx"
netbox_postgres_name: "netbox"
netbox_postgres_user: "netbox"
# netbox_postgres_password: ~
netbox_postgres_host: "{{ netbox_postgres_socket }}"
netbox_redis_host: ~
netbox_redis_port: 6379
netbox_redis_username: "netbox"
# netbox_redis_password: ~
netbox_redis_tasks_db: 0
netbox_redis_cache_db: 1
netbox_redis_ssl: false
# netbox_secret_key: ~
netbox_allow_token_retrival: false
netbox_secure_cookies: true
# netbox_oidc_enable: false
# netbox_oidc_admin_group: ~
# netbox_oidc_staff_group: ~
# netbox_oidc_endpoint: ~
# netbox_oidc_key: ~
# netbox_oidc_secret: ~
netbox_metrics_enabled: true
netbox_nginx_listen: 8000
netbox_container_commands:
- { name: "uwsgi", entry: "/opt/netbox/venv/bin/uwsgi {{ netbox_path_uwsgi_config }}" }
- { name: "workers", entry: "/opt/netbox/venv/bin/python /opt/netbox/netbox/manage.py rqworker high default low" }
- { name: "housekeeping", entry: "/opt/netbox/housekeeping.sh" }

View file

@ -0,0 +1,12 @@
import yaml
import os
def load_dir_rec(path):
for node in os.scandir(path):
if node.is_dir():
load_dir(node.path)
else:
for k,v in yaml.safe_load(open(node.path)).items():
globals()[k] = v # we just add *all* the kv pairs to the scope netbox will use to access it's config
load_dir_rec(os.environ.get('NETBOX_YAML_CONFIG_DIR','/opt/netbox/config'))

View file

@ -0,0 +1,28 @@
---
- name: Restart uwsgi
community.docker.docker_container:
name: "{{ netbox_container_name }}_uwsgi"
state: "started"
restart: true
listen: "restart-netbox-web"
- name: Restart redis queue and task workers
community.docker.docker_container:
name: "{{ netbox_container_name }}_workers"
state: "started"
restart: true
listen: "restart-netbox-web"
- name: Restart nginx
community.docker.docker_container:
name: "{{ netbox_container_name }}_nginx"
state: "started"
restart: true
listen: "restart-netbox-nginx"
- name: Restart housekeeping ( and migrate database )
community.docker.docker_container:
name: "{{ netbox_container_name }}_housekeeping"
state: "started"
restart: true
listen: "migrate-netbox"

114
roles/netbox/tasks/main.yml Normal file
View file

@ -0,0 +1,114 @@
---
- name: Add the user "{{ netbox_user_name }}"
ansible.builtin.user:
name: "{{ netbox_user_name }}"
groups: "{{ netbox_user_name }}"
create_home: false
register: netbox_user
become: true
- name: "Create directories for netbox"
ansible.builtin.file:
path: "{{ item }}"
state: directory
mode: "0755"
owner: "{{ netbox_user.name }}"
group: "{{ netbox_user.group }}"
become: true
loop:
- "{{ netbox_path_base }}"
- "{{ netbox_path_yaml_config }}"
- "{{ netbox_path_state }}"
- name: "Write netbox config loader"
ansible.builtin.copy:
src: "loader.py"
dest: "{{ netbox_path_base }}/configuration.py"
mode: "0775"
- name: "Write netbox nginx config"
ansible.builtin.template:
src: "nginx.conf.j2"
dest: "{{ netbox_path_nginx_config }}"
mode: "0775"
notify: ["restart-netbox-nginx"]
- name: "Write netbox uwsgi config"
ansible.builtin.template:
src: "uwsgi.ini.j2"
dest: "{{ netbox_path_uwsgi_config }}"
mode: "0775"
notify: ["restart-netbox-web"]
- name: "Write netbox config"
ansible.builtin.copy:
content: "{{ item.content | ansible.builtin.to_nice_yaml }}"
dest: "{{ netbox_path_yaml_config ~ '/' ~ item.dest }}"
mode: "0666"
loop:
- { content: "{{ netbox_flat_config }}", dest: "flat.yaml" }
notify: ["restart-netbox-web"]
- name: Ensure container image is present locally
community.docker.docker_image:
name: "{{ netbox_container_image_reference }}"
source: "pull"
state: "{{ netbox_container_image_state }}"
force_source: "{{ netbox_container_image_force_pull }}"
register: netbox_container_image_pulled
until: netbox_container_image_pulled is success
retries: 10
delay: 5
become: true
tags: ["deploy", "deploy-netbox"]
notify:
- "migrate-netbox"
- "restart-netbox-web"
- "restart-netbox-nginx"
- name: Ensure container image nginx is present locally
community.docker.docker_image:
name: "{{ netbox_container_nginx_image_reference }}"
source: "pull"
state: "{{ netbox_container_image_state }}"
force_source: "{{ netbox_container_image_force_pull }}"
register: netbox_container_image_pulled
until: netbox_container_image_pulled is success
retries: 10
delay: 5
become: true
tags: ["deploy", "deploy-netbox"]
- name: Ensure container is started
community.docker.docker_container:
image: "{{ netbox_container_image_reference }}"
name: "{{ netbox_container_name ~ '_' ~ item.name }}"
state: "started"
restart_policy: "{{ netbox_container_restart_policy | default(omit) }}"
user: "{{ netbox_user.uid ~ ':' ~ netbox_user.group }}"
volumes: "{{ netbox_container_volumes_common }}"
ports: "{{ netbox_container_ports }}"
env: "{{ netbox_container_env | default(omit) }}"
command: "{{ item.entry }}"
etc_hosts: "{{ netbox_container_etc_hosts | default(omit) }}"
networks: "{{ netbox_container_networks | default(omit) }}"
purge_networks: "{{ netbox_container_purge_networks | default(omit) }}"
become: true
tags: ["deploy", "deploy-netbox"]
loop: "{{ netbox_container_commands }}"
- name: Ensure container nginx is started
community.docker.docker_container:
image: "{{ netbox_container_nginx_image_reference }}"
name: "{{ netbox_container_name }}_nginx"
state: "started"
restart_policy: "{{ netbox_container_restart_policy | default(omit) }}"
volumes: "{{ netbox_container_volumes_nginx }}"
ports: "{{ netbox_container_ports }}"
env: "{{ netbox_container_env | default(omit) }}"
labels: "{{ netbox_container_labels_merged }}"
etc_hosts: "{{ netbox_container_etc_hosts | default(omit) }}"
networks: "{{ netbox_container_networks | default(omit) }}"
purge_networks: "{{ netbox_container_purge_networks | default(omit) }}"
become: true
tags: ["deploy", "deploy-netbox"]

View file

@ -0,0 +1,13 @@
server {
listen {{ netbox_nginx_listen }};
server_name _;
location /static/ {
alias {{ netbox_path_static }}/;
}
location / {
include uwsgi_params;
uwsgi_pass unix://{{ netbox_path_socks_uwsgi }};
}
}

View file

@ -0,0 +1,5 @@
[uwsgi]
chmod-socket = 777
socket = {{ netbox_path_socks_uwsgi }}
chdir = /opt/netbox/netbox
wsgi-file = /opt/netbox/netbox/netbox/wsgi.py

View file

@ -0,0 +1,63 @@
---
netbox_flat_config:
ALLOWED_HOSTS: "{{ netbox_allowed_hosts }}"
DATABASE:
ENGINE: "django.db.backends.postgresql"
NAME: "{{ netbox_postgres_name }}"
USER: "{{ netbox_postgres_user }}"
PASSWORD: "{{ netbox_postgres_password }}"
HOST: "{{ netbox_postgres_host }}"
REDIS:
"tasks":
HOST: "{{ netbox_redis_host }}"
PORT: "{{ netbox_redis_port }}"
USERNAME: "{{ netbox_redis_username }}"
PASSWORD: "{{ netbox_redis_password }}"
DATABASE: "{{ netbox_redis_tasks_db }}"
SSL: "{{ netbox_redis_ssl }}"
"caching":
HOST: "{{ netbox_redis_host }}"
PORT: "{{ netbox_redis_port }}"
USERNAME: "{{ netbox_redis_username }}"
PASSWORD: "{{ netbox_redis_password }}"
DATABASE: "{{ netbox_redis_cache_db }}"
SSL: "{{ netbox_redis_ssl }}"
SECRET_KEY: "{{ netbox_secret_key }}"
ALLOW_TOKEN_RETRIEVAL: "{{ netbox_allow_token_retrival }}"
CSRF_COOKIE_SECURE: "{{ netbox_secure_cookies }}"
SESSION_COOKIE_SECURE: "{{ netbox_secure_cookies }}"
LOGIN_REQUIRED: true
# REMOTE_AUTH_ENABLED: "{{ netbox_oidc_enable }}"
# REMOTE_AUTH_BACKEND: "social_core.backends.oidc.OpenIdConnectAuth"
# REMOTE_AUTH_AUTO_CREATE_GROUPS: true
# REMOTE_AUTH_AUTO_CREATE_USER: true
# REMOTE_AUTH_GROUP_SYNC_ENABLED: true
# REMOTE_AUTH_SUPERUSER_GROUPS:
# - "{{ netbox_oidc_admin_group }}"
# REMOTE_AUTH_STAFF_GROUPS:
# - "{{ netbox_oidc_staff_group }}"
# SOCIAL_AUTH_OIDC_OIDC_ENDPOINT: "{{ netbox_oidc_endpoint}}"
# SOCIAL_AUTH_OIDC_KEY: "{{ netbox_oidc_key}}"
# SOCIAL_AUTH_OIDC_SECRET: "{{ netbox_oidc_secret}}"
# SOCIAL_AUTH_OIDC_SCOPE: [ groups ]
PROTECTION_RULES: "{{ netbox_protection_rules }}"
POWERFEED_DEFAULT_VOLTAGE: 230
CENSUS_REPORTING_ENABLED: false
CHANGELOG_RETENTION: 500
CHANGELOG_SKIP_EMPTY_CHANGES: true
METRICS_ENABLED: "{{ netbox_metrics_enabled | default(true) }}"
PLUGINS: "{{ netbox_plugins }}"