Browse Source

use-right-docker-images

pull/16/head
fedy95 4 years ago
parent
commit
33362a408b
  1. 28
      .drone.yml
  2. 1
      .gitignore
  3. 28
      Makefile
  4. 3
      README.md
  5. 79
      docker-compose.yml
  6. 57
      env/netbox.env-dist
  7. 1
      env/redis-cache.env-dist
  8. 1
      env/redis.env-dist
  9. 2
      etc/.gitignore
  10. 248
      etc/netbox/etc/netbox/config/configuration.py
  11. 55
      etc/netbox/etc/netbox/config/extra.py
  12. 84
      etc/netbox/etc/netbox/config/ldap/ldap_config.py
  13. 46
      etc/netbox/etc/netbox/reports/devices.py.example
  14. 0
      etc/netbox/etc/netbox/scripts/__init__.py
  15. 6
      etc/netbox/opt/netbox/initializers/aggregates.yml
  16. 2
      etc/netbox/opt/netbox/initializers/cluster_types.yml
  17. 5
      etc/netbox/opt/netbox/initializers/clusters.yml
  18. 97
      etc/netbox/opt/netbox/initializers/custom_fields.yml
  19. 18
      etc/netbox/opt/netbox/initializers/dcim_interfaces.yml
  20. 15
      etc/netbox/opt/netbox/initializers/device_roles.yml
  21. 23
      etc/netbox/opt/netbox/initializers/device_types.yml
  22. 44
      etc/netbox/opt/netbox/initializers/devices.yml
  23. 35
      etc/netbox/opt/netbox/initializers/groups.yml
  24. 44
      etc/netbox/opt/netbox/initializers/ip_addresses.yml
  25. 2
      etc/netbox/opt/netbox/initializers/manufacturers.yml
  26. 15
      etc/netbox/opt/netbox/initializers/platforms.yml
  27. 2
      etc/netbox/opt/netbox/initializers/prefix_vlan_roles.yml
  28. 29
      etc/netbox/opt/netbox/initializers/prefixes.yml
  29. 3
      etc/netbox/opt/netbox/initializers/rack_groups.yml
  30. 12
      etc/netbox/opt/netbox/initializers/rack_roles.yml
  31. 41
      etc/netbox/opt/netbox/initializers/racks.yml
  32. 4
      etc/netbox/opt/netbox/initializers/regions.yml
  33. 9
      etc/netbox/opt/netbox/initializers/rirs.yml
  34. 32
      etc/netbox/opt/netbox/initializers/sites.yml
  35. 4
      etc/netbox/opt/netbox/initializers/tenant_groups.yml
  36. 5
      etc/netbox/opt/netbox/initializers/tenants.yml
  37. 23
      etc/netbox/opt/netbox/initializers/users.yml
  38. 28
      etc/netbox/opt/netbox/initializers/virtual_machines.yml
  39. 12
      etc/netbox/opt/netbox/initializers/virtualization_interfaces.yml
  40. 6
      etc/netbox/opt/netbox/initializers/vlan_groups.yml
  41. 19
      etc/netbox/opt/netbox/initializers/vlans.yml
  42. 8
      etc/netbox/opt/netbox/initializers/vrfs.yml
  43. 23
      etc/netbox/opt/netbox/startup_scripts/000_users.py
  44. 23
      etc/netbox/opt/netbox/startup_scripts/010_groups.py
  45. 54
      etc/netbox/opt/netbox/startup_scripts/020_custom_fields.py
  46. 26
      etc/netbox/opt/netbox/startup_scripts/030_regions.py
  47. 41
      etc/netbox/opt/netbox/startup_scripts/040_sites.py
  48. 14
      etc/netbox/opt/netbox/startup_scripts/050_manufacturers.py
  49. 51
      etc/netbox/opt/netbox/startup_scripts/060_device_types.py
  50. 23
      etc/netbox/opt/netbox/startup_scripts/070_rack_roles.py
  51. 25
      etc/netbox/opt/netbox/startup_scripts/075_rack_groups.py
  52. 52
      etc/netbox/opt/netbox/startup_scripts/080_racks.py
  53. 24
      etc/netbox/opt/netbox/startup_scripts/090_device_roles.py
  54. 26
      etc/netbox/opt/netbox/startup_scripts/100_platforms.py
  55. 14
      etc/netbox/opt/netbox/startup_scripts/110_tenant_groups.py
  56. 39
      etc/netbox/opt/netbox/startup_scripts/120_tenants.py
  57. 59
      etc/netbox/opt/netbox/startup_scripts/130_devices.py
  58. 14
      etc/netbox/opt/netbox/startup_scripts/140_cluster_types.py
  59. 14
      etc/netbox/opt/netbox/startup_scripts/150_rirs.py
  60. 42
      etc/netbox/opt/netbox/startup_scripts/160_aggregates.py
  61. 51
      etc/netbox/opt/netbox/startup_scripts/170_clusters.py
  62. 42
      etc/netbox/opt/netbox/startup_scripts/180_vrfs.py
  63. 14
      etc/netbox/opt/netbox/startup_scripts/190_prefix_vlan_roles.py
  64. 40
      etc/netbox/opt/netbox/startup_scripts/200_vlan_groups.py
  65. 45
      etc/netbox/opt/netbox/startup_scripts/210_vlans.py
  66. 46
      etc/netbox/opt/netbox/startup_scripts/220_prefixes.py
  67. 56
      etc/netbox/opt/netbox/startup_scripts/230_virtual_machines.py
  68. 38
      etc/netbox/opt/netbox/startup_scripts/240_virtualization_interfaces.py
  69. 38
      etc/netbox/opt/netbox/startup_scripts/250_dcim_interfaces.py
  70. 69
      etc/netbox/opt/netbox/startup_scripts/260_ip_addresses.py
  71. 43
      etc/netbox/opt/netbox/startup_scripts/270_primary_ips.py
  72. 29
      etc/netbox/opt/netbox/startup_scripts/__main__.py
  73. 2
      etc/netbox/opt/netbox/startup_scripts/startup_script_utils/__init__.py
  74. 10
      etc/netbox/opt/netbox/startup_scripts/startup_script_utils/load_yaml.py
  75. 18
      etc/netbox/opt/netbox/startup_scripts/startup_script_utils/permissions.py

28
.drone.yml

@ -9,34 +9,6 @@ steps:
- name: lint yaml
image: registry.fedy95.com/baseimage-yamllint:latest
commands:
- yamllint -c /yamllint/relaxed.yaml etc/netbox/opt/netbox/initializers/aggregates.yml
- yamllint -c /yamllint/relaxed.yaml etc/netbox/opt/netbox/initializers/cluster_types.yml
- yamllint -c /yamllint/relaxed.yaml etc/netbox/opt/netbox/initializers/clusters.yml
- yamllint -c /yamllint/relaxed.yaml etc/netbox/opt/netbox/initializers/custom_fields.yml
- yamllint -c /yamllint/relaxed.yaml etc/netbox/opt/netbox/initializers/dcim_interfaces.yml
- yamllint -c /yamllint/relaxed.yaml etc/netbox/opt/netbox/initializers/device_roles.yml
- yamllint -c /yamllint/relaxed.yaml etc/netbox/opt/netbox/initializers/device_types.yml
- yamllint -c /yamllint/relaxed.yaml etc/netbox/opt/netbox/initializers/devices.yml
- yamllint -c /yamllint/relaxed.yaml etc/netbox/opt/netbox/initializers/groups.yml
- yamllint -c /yamllint/relaxed.yaml etc/netbox/opt/netbox/initializers/ip_addresses.yml
- yamllint -c /yamllint/relaxed.yaml etc/netbox/opt/netbox/initializers/manufacturers.yml
- yamllint -c /yamllint/relaxed.yaml etc/netbox/opt/netbox/initializers/platforms.yml
- yamllint -c /yamllint/relaxed.yaml etc/netbox/opt/netbox/initializers/prefix_vlan_roles.yml
- yamllint -c /yamllint/relaxed.yaml etc/netbox/opt/netbox/initializers/prefixes.yml
- yamllint -c /yamllint/relaxed.yaml etc/netbox/opt/netbox/initializers/rack_groups.yml
- yamllint -c /yamllint/relaxed.yaml etc/netbox/opt/netbox/initializers/rack_roles.yml
- yamllint -c /yamllint/relaxed.yaml etc/netbox/opt/netbox/initializers/racks.yml
- yamllint -c /yamllint/relaxed.yaml etc/netbox/opt/netbox/initializers/regions.yml
- yamllint -c /yamllint/relaxed.yaml etc/netbox/opt/netbox/initializers/rirs.yml
- yamllint -c /yamllint/relaxed.yaml etc/netbox/opt/netbox/initializers/sites.yml
- yamllint -c /yamllint/relaxed.yaml etc/netbox/opt/netbox/initializers/tenant_groups.yml
- yamllint -c /yamllint/relaxed.yaml etc/netbox/opt/netbox/initializers/tenants.yml
- yamllint -c /yamllint/relaxed.yaml etc/netbox/opt/netbox/initializers/users.yml
- yamllint -c /yamllint/relaxed.yaml etc/netbox/opt/netbox/initializers/virtual_machines.yml
- yamllint -c /yamllint/relaxed.yaml etc/netbox/opt/netbox/initializers/virtualization_interfaces.yml
- yamllint -c /yamllint/relaxed.yaml etc/netbox/opt/netbox/initializers/vlan_groups.yml
- yamllint -c /yamllint/relaxed.yaml etc/netbox/opt/netbox/initializers/vlans.yml
- yamllint -c /yamllint/relaxed.yaml etc/netbox/opt/netbox/initializers/vrfs.yml
- yamllint -c /yamllint/relaxed.yaml docker-compose.yml
when:
event: pull_request

1
.gitignore

@ -1 +0,0 @@
/venv

28
Makefile

@ -9,34 +9,6 @@ lint: lint-yaml
LINT-YAML-CMD=docker run --rm -it -v $(PWD):/data ${REGISTRY}/${YAMLLINT_TAG}
lint-yaml:
docker pull ${REGISTRY}/${YAMLLINT_TAG}
$(LINT-YAML-CMD) etc/netbox/opt/netbox/initializers/aggregates.yml
$(LINT-YAML-CMD) etc/netbox/opt/netbox/initializers/cluster_types.yml
$(LINT-YAML-CMD) etc/netbox/opt/netbox/initializers/clusters.yml
$(LINT-YAML-CMD) etc/netbox/opt/netbox/initializers/custom_fields.yml
$(LINT-YAML-CMD) etc/netbox/opt/netbox/initializers/dcim_interfaces.yml
$(LINT-YAML-CMD) etc/netbox/opt/netbox/initializers/device_roles.yml
$(LINT-YAML-CMD) etc/netbox/opt/netbox/initializers/device_types.yml
$(LINT-YAML-CMD) etc/netbox/opt/netbox/initializers/devices.yml
$(LINT-YAML-CMD) etc/netbox/opt/netbox/initializers/groups.yml
$(LINT-YAML-CMD) etc/netbox/opt/netbox/initializers/ip_addresses.yml
$(LINT-YAML-CMD) etc/netbox/opt/netbox/initializers/manufacturers.yml
$(LINT-YAML-CMD) etc/netbox/opt/netbox/initializers/platforms.yml
$(LINT-YAML-CMD) etc/netbox/opt/netbox/initializers/prefix_vlan_roles.yml
$(LINT-YAML-CMD) etc/netbox/opt/netbox/initializers/prefixes.yml
$(LINT-YAML-CMD) etc/netbox/opt/netbox/initializers/rack_groups.yml
$(LINT-YAML-CMD) etc/netbox/opt/netbox/initializers/rack_roles.yml
$(LINT-YAML-CMD) etc/netbox/opt/netbox/initializers/racks.yml
$(LINT-YAML-CMD) etc/netbox/opt/netbox/initializers/regions.yml
$(LINT-YAML-CMD) etc/netbox/opt/netbox/initializers/rirs.yml
$(LINT-YAML-CMD) etc/netbox/opt/netbox/initializers/sites.yml
$(LINT-YAML-CMD) etc/netbox/opt/netbox/initializers/tenant_groups.yml
$(LINT-YAML-CMD) etc/netbox/opt/netbox/initializers/tenants.yml
$(LINT-YAML-CMD) etc/netbox/opt/netbox/initializers/users.yml
$(LINT-YAML-CMD) etc/netbox/opt/netbox/initializers/virtual_machines.yml
$(LINT-YAML-CMD) etc/netbox/opt/netbox/initializers/virtualization_interfaces.yml
$(LINT-YAML-CMD) etc/netbox/opt/netbox/initializers/vlan_groups.yml
$(LINT-YAML-CMD) etc/netbox/opt/netbox/initializers/vlans.yml
$(LINT-YAML-CMD) etc/netbox/opt/netbox/initializers/vrfs.yml
$(LINT-YAML-CMD) docker-compose.yml
restart:

3
README.md

@ -6,6 +6,5 @@
- [git](https://github.com/netbox-community/netbox-docker)
### services
- [netbox](https://hub.docker.com/r/netboxcommunity/netbox)
- [nginx](https://hub.docker.com/_/nginx)
- [netbox](https://hub.docker.com/r/linuxserver/netbox)
- [redis](https://hub.docker.com/_/redis)

79
docker-compose.yml

@ -1,84 +1,23 @@
---
version: "3"
volumes:
netbox-static-files:
driver: local
netbox-nginx-config:
driver: local
netbox-media-files:
driver: local
netbox-redis-data:
driver: local
services:
netbox: &netbox
image: netboxcommunity/netbox:v2.9.9
container_name: netbox_instance
hostname: netbox_instance
netbox:
image: ghcr.io/linuxserver/netbox
container_name: netbox
hostname: netbox
restart: unless-stopped
depends_on:
- redis
- redis-cache
- netbox-worker
env_file: env/netbox.env
user: '101'
volumes:
- ./etc/netbox/etc/netbox/config:/etc/netbox/config:z,ro
- ./etc/netbox/etc/netbox/reports:/etc/netbox/reports:z,ro
- ./etc/netbox/etc/netbox/scripts:/etc/netbox/scripts:z,ro
- ./etc/netbox/opt/netbox/initializers:/opt/netbox/initializers:z,ro
- ./etc/netbox/opt/netbox/startup_scripts:/opt/netbox/startup_scripts:z,ro
- netbox-nginx-config:/etc/netbox-nginx:z
- netbox-static-files:/opt/netbox/netbox/static:z
- netbox-media-files:/opt/netbox/netbox/media:z
netbox-worker:
<<: *netbox
container_name: netbox_worker
hostname: netbox_worker
depends_on:
- redis
entrypoint:
- python3
- /opt/netbox/netbox/manage.py
command:
- rqworker
nginx:
image: nginx:1.19-alpine
container_name: netbox_nginx
hostname: netbox_nginx
depends_on:
- netbox
ports:
- "3009:8080"
- "3009:8000"
volumes:
- netbox-nginx-config:/etc/netbox-nginx/:ro
- netbox-static-files:/opt/netbox/netbox/static:ro
command: nginx -c /etc/netbox-nginx/nginx.conf
- ./etc/netbox/config:/config
env_file: env/netbox.env
redis:
image: redis:6.0.9-alpine
image: redis:6.2-alpine
container_name: netbox_redis
hostname: netbox_redis
env_file: env/redis.env
volumes:
- netbox-redis-data:/data
command:
- sh
- -c # this is to evaluate the $REDIS_PASSWORD from the env
- redis-server --appendonly yes --requirepass $$REDIS_PASSWORD ## $$ because of docker-compose
redis-cache:
image: redis:6.0.9-alpine
container_name: netbox_redis_cache
hostname: netbox_redis_cache
env_file: env/redis-cache.env
command:
- sh
- -c # this is to evaluate the $REDIS_PASSWORD from the env
- redis-server --requirepass $$REDIS_PASSWORD ## $$ because of docker-compose
...

57
env/netbox.env-dist

@ -1,46 +1,17 @@
CORS_ORIGIN_ALLOW_ALL=True
MAX_PAGE_SIZE=1000
MEDIA_ROOT=/opt/netbox/netbox/media
METRICS_ENABLED=false
WEBHOOKS_ENABLED=true
SKIP_STARTUP_SCRIPTS=false
RELEASE_CHECK_URL=https://api.github.com/repos/netbox-community/netbox/releases
SECRET_KEY=
DB_HOST=192.168.1.152
DB_PORT=5432
DB_NAME=netbox
DB_USER=netbox
PUID=1000
PGID=1000
TZ=Etc/UTC
SUPERUSER_EMAIL=
SUPERUSER_PASSWORD=
ALLOWED_HOST=
DB_NAME=
DB_USER=
DB_PASSWORD=
EMAIL_SERVER=localhost
EMAIL_PORT=25
EMAIL_USERNAME=netbox
EMAIL_PASSWORD=
EMAIL_TIMEOUT=5
EMAIL_FROM=netbox@bar.com
# EMAIL_USE_SSL and EMAIL_USE_TLS are mutually exclusive, i.e. they can't both be `true`!
EMAIL_USE_SSL=false
EMAIL_USE_TLS=false
EMAIL_SSL_CERTFILE=
EMAIL_SSL_KEYFILE=
NAPALM_USERNAME=
NAPALM_PASSWORD=
NAPALM_TIMEOUT=10
REDIS_HOST=redis
DB_HOST=
DB_PORT=
REDIS_HOST=
REDIS_PORT=
REDIS_PASSWORD=
REDIS_DATABASE=0
REDIS_SSL=false
REDIS_CACHE_HOST=redis-cache
REDIS_CACHE_PASSWORD=
REDIS_CACHE_DATABASE=1
REDIS_CACHE_SSL=false
REDIS_DB_TASK=
REDIS_DB_CACHE=
SKIP_SUPERUSER=false
SUPERUSER_NAME=fedy95
SUPERUSER_EMAIL=fedy95@protonmail.com
SUPERUSER_PASSWORD=
SUPERUSER_API_TOKEN=

1
env/redis-cache.env-dist

@ -1 +0,0 @@
REDIS_PASSWORD=

1
env/redis.env-dist

@ -1 +0,0 @@
REDIS_PASSWORD=

2
etc/.gitignore

@ -0,0 +1,2 @@
*
!.gitignore

248
etc/netbox/etc/netbox/config/configuration.py

@ -1,248 +0,0 @@
####
## We recommend to not edit this file.
## Create separate files to overwrite the settings.
## See `extra.py` as an example.
####
import re
from os.path import dirname, abspath, join
from os import environ
# For reference see https://netbox.readthedocs.io/en/stable/configuration/
# Based on https://github.com/netbox-community/netbox/blob/master/netbox/netbox/configuration.example.py
# Read secret from file
def _read_secret(secret_name, default = None):
try:
f = open('/run/secrets/' + secret_name, 'r', encoding='utf-8')
except EnvironmentError:
return default
else:
with f:
return f.readline().strip()
_BASE_DIR = dirname(dirname(abspath(__file__)))
#########################
# #
# Required settings #
# #
#########################
# This is a list of valid fully-qualified domain names (FQDNs) for the NetBox server. NetBox 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 = ['netbox.example.com', 'netbox.internal.local']
ALLOWED_HOSTS = environ.get('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
DATABASE = {
'NAME': environ.get('DB_NAME', 'netbox'), # Database name
'USER': environ.get('DB_USER', ''), # PostgreSQL username
'PASSWORD': _read_secret('db_password', environ.get('DB_PASSWORD', '')),
# PostgreSQL password
'HOST': environ.get('DB_HOST', 'localhost'), # Database server
'PORT': environ.get('DB_PORT', ''), # Database port (leave blank for default)
'OPTIONS': {'sslmode': environ.get('DB_SSLMODE', 'prefer')},
# Database connection SSLMODE
'CONN_MAX_AGE': int(environ.get('DB_CONN_MAX_AGE', '300')),
# Max database connection age
}
# Redis database settings. Redis is used for caching and for queuing background tasks such as webhook events. A separate
# configuration exists for each. Full connection details are required in both sections, and it is strongly recommended
# to use two separate database IDs.
REDIS = {
'tasks': {
'HOST': environ.get('REDIS_HOST', 'localhost'),
'PORT': int(environ.get('REDIS_PORT', 6379)),
'PASSWORD': _read_secret('redis_password', environ.get('REDIS_PASSWORD', '')),
'DATABASE': int(environ.get('REDIS_DATABASE', 0)),
'SSL': environ.get('REDIS_SSL', 'False').lower() == 'true',
},
'caching': {
'HOST': environ.get('REDIS_CACHE_HOST', environ.get('REDIS_HOST', 'localhost')),
'PORT': int(environ.get('REDIS_CACHE_PORT', environ.get('REDIS_PORT', 6379))),
'PASSWORD': _read_secret('redis_cache_password', environ.get('REDIS_CACHE_PASSWORD', environ.get('REDIS_PASSWORD', ''))),
'DATABASE': int(environ.get('REDIS_CACHE_DATABASE', 1)),
'SSL': environ.get('REDIS_CACHE_SSL', environ.get('REDIS_SSL', 'False')).lower() == 'true',
},
}
# 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. NetBox will not run without this defined. For more information, see
# https://docs.djangoproject.com/en/stable/ref/settings/#std:setting-SECRET_KEY
SECRET_KEY = _read_secret('secret_key', environ.get('SECRET_KEY', ''))
#########################
# #
# Optional settings #
# #
#########################
# Specify one or more name and email address tuples representing NetBox 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 NetBox
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 = environ.get('BANNER_TOP', '')
BANNER_BOTTOM = environ.get('BANNER_BOTTOM', '')
# Text to include on the login page above the login form. HTML is allowed.
BANNER_LOGIN = environ.get('BANNER_LOGIN', '')
# Base URL path if accessing NetBox within a directory. For example, if installed at http://example.com/netbox/, set:
# BASE_PATH = 'netbox/'
BASE_PATH = environ.get('BASE_PATH', '')
# Cache timeout in seconds. Set to 0 to dissable caching. Defaults to 900 (15 minutes)
CACHE_TIMEOUT = int(environ.get('CACHE_TIMEOUT', 900))
# Maximum number of days to retain logged changes. Set to 0 to retain changes indefinitely. (Default: 90)
CHANGELOG_RETENTION = int(environ.get('CHANGELOG_RETENTION', 90))
# API Cross-Origin Resource Sharing (CORS) settings. If CORS_ORIGIN_ALLOW_ALL is set to True, all origins will be
# allowed. Otherwise, define a list of allowed origins using either CORS_ORIGIN_WHITELIST or
# CORS_ORIGIN_REGEX_WHITELIST. For more information, see https://github.com/ottoyiu/django-cors-headers
CORS_ORIGIN_ALLOW_ALL = environ.get('CORS_ORIGIN_ALLOW_ALL', 'False').lower() == 'true'
CORS_ORIGIN_WHITELIST = list(filter(None, environ.get('CORS_ORIGIN_WHITELIST', 'https://localhost').split(' ')))
CORS_ORIGIN_REGEX_WHITELIST = [re.compile(r) for r in list(filter(None, environ.get('CORS_ORIGIN_REGEX_WHITELIST', '').split(' ')))]
# 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 = environ.get('DEBUG', 'False').lower() == 'true'
# Email settings
EMAIL = {
'SERVER': environ.get('EMAIL_SERVER', 'localhost'),
'PORT': int(environ.get('EMAIL_PORT', 25)),
'USERNAME': environ.get('EMAIL_USERNAME', ''),
'PASSWORD': _read_secret('email_password', environ.get('EMAIL_PASSWORD', '')),
'USE_SSL': environ.get('EMAIL_USE_SSL', 'False').lower() == 'true',
'USE_TLS': environ.get('EMAIL_USE_TLS', 'False').lower() == 'true',
'SSL_CERTFILE': environ.get('EMAIL_SSL_CERTFILE', ''),
'SSL_KEYFILE': environ.get('EMAIL_SSL_KEYFILE', ''),
'TIMEOUT': int(environ.get('EMAIL_TIMEOUT', 10)), # seconds
'FROM_EMAIL': environ.get('EMAIL_FROM', ''),
}
# 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 = environ.get('ENFORCE_GLOBAL_UNIQUE', 'False').lower() == 'true'
# 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 `<app>.<model>`. Add '*' to this list to exempt all models.
EXEMPT_VIEW_PERMISSIONS = list(filter(None, environ.get('EXEMPT_VIEW_PERMISSIONS', '').split(' ')))
# Enable custom logging. Please see the Django documentation for detailed guidance on configuring custom logs:
# https://docs.djangoproject.com/en/stable/topics/logging/
LOGGING = {}
# Setting this to True will permit only authenticated users to access any part of NetBox. By default, anonymous users
# are permitted to access most data in NetBox (excluding secrets) but not make any changes.
LOGIN_REQUIRED = environ.get('LOGIN_REQUIRED', 'False').lower() == 'true'
# 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])
LOGIN_TIMEOUT = environ.get('LOGIN_TIMEOUT', None)
# Setting this to True will display a "maintenance mode" banner at the top of every page.
MAINTENANCE_MODE = environ.get('MAINTENANCE_MODE', 'False').lower() == 'true'
# 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(environ.get('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 derived from the installed location.
MEDIA_ROOT = environ.get('MEDIA_ROOT', join(_BASE_DIR, 'media'))
# Expose Prometheus monitoring metrics at the HTTP endpoint '/metrics'
METRICS_ENABLED = environ.get('METRICS_ENABLED', 'False').lower() == 'true'
# Credentials that NetBox will uses to authenticate to devices when connecting via NAPALM.
NAPALM_USERNAME = environ.get('NAPALM_USERNAME', '')
NAPALM_PASSWORD = _read_secret('napalm_password', environ.get('NAPALM_PASSWORD', ''))
# NAPALM timeout (in seconds). (Default: 30)
NAPALM_TIMEOUT = int(environ.get('NAPALM_TIMEOUT', 30))
# NAPALM optional arguments (see http://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(environ.get('PAGINATE_COUNT', 50))
# Enable installed plugins. Add the name of each plugin to the list.
PLUGINS = []
# 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 = {
}
# 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 = environ.get('PREFER_IPV4', 'False').lower() == 'true'
# 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(environ.get('RACK_ELEVATION_DEFAULT_UNIT_HEIGHT', 22))
RACK_ELEVATION_DEFAULT_UNIT_WIDTH = int(environ.get('RACK_ELEVATION_DEFAULT_UNIT_WIDTH', 220))
# Remote authentication support
REMOTE_AUTH_ENABLED = environ.get('REMOTE_AUTH_ENABLED', 'False').lower() == 'true'
REMOTE_AUTH_BACKEND = environ.get('REMOTE_AUTH_BACKEND', 'netbox.authentication.RemoteUserBackend')
REMOTE_AUTH_HEADER = environ.get('REMOTE_AUTH_HEADER', 'HTTP_REMOTE_USER')
REMOTE_AUTH_AUTO_CREATE_USER = environ.get('REMOTE_AUTH_AUTO_CREATE_USER', 'True').lower() == 'true'
REMOTE_AUTH_DEFAULT_GROUPS = list(filter(None, environ.get('REMOTE_AUTH_DEFAULT_GROUPS', '').split(' ')))
# This determines how often the GitHub API is called to check the latest release of NetBox. Must be at least 1 hour.
RELEASE_CHECK_TIMEOUT = int(environ.get('RELEASE_CHECK_TIMEOUT', 24 * 3600))
# This repository is used to check whether there is a new release of NetBox available. Set to None to disable the
# version check or use the URL below to check for release in the official NetBox repository.
# https://api.github.com/repos/netbox-community/netbox/releases
RELEASE_CHECK_URL = environ.get('RELEASE_CHECK_URL', None)
# The file path where custom reports will be stored. A trailing slash is not needed. Note that the default value of
# this setting is derived from the installed location.
REPORTS_ROOT = environ.get('REPORTS_ROOT', '/etc/netbox/reports')
# Maximum execution time for background tasks, in seconds.
RQ_DEFAULT_TIMEOUT = int(environ.get('RQ_DEFAULT_TIMEOUT', 300))
# The file path where custom scripts will be stored. A trailing slash is not needed. Note that the default value of
# this setting is derived from the installed location.
SCRIPTS_ROOT = environ.get('SCRIPTS_ROOT', '/etc/netbox/scripts')
# By default, NetBox 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 NetBox runs must have read and write permissions to this path.
SESSION_FILE_PATH = environ.get('REPORTS_ROOT', None)
# Time zone (default: UTC)
TIME_ZONE = environ.get('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 = environ.get('DATE_FORMAT', 'N j, Y')
SHORT_DATE_FORMAT = environ.get('SHORT_DATE_FORMAT', 'Y-m-d')
TIME_FORMAT = environ.get('TIME_FORMAT', 'g:i a')
SHORT_TIME_FORMAT = environ.get('SHORT_TIME_FORMAT', 'H:i:s')
DATETIME_FORMAT = environ.get('DATETIME_FORMAT', 'N j, Y g:i a')
SHORT_DATETIME_FORMAT = environ.get('SHORT_DATETIME_FORMAT', 'Y-m-d H:i')

55
etc/netbox/etc/netbox/config/extra.py

@ -1,55 +0,0 @@
####
## This file contains extra configuration options that can't be configured
## directly through environment variables.
####
## Specify one or more name and email address tuples representing NetBox 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 NetBox
# ALLOWED_URL_SCHEMES = (
# 'file', 'ftp', 'ftps', 'http', 'https', 'irc', 'mailto', 'sftp', 'ssh', 'tel', 'telnet', 'tftp', 'vnc', 'xmpp',
# )
## NAPALM optional arguments (see http://napalm.readthedocs.io/en/latest/support/#optional-arguments). Arguments must
## be provided as a dictionary.
# NAPALM_ARGS = {}
## Enable installed plugins. Add the name of each plugin to the list.
# from netbox.configuration.configuration import PLUGINS
# PLUGINS.append('my_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.
# from netbox.configuration.configuration import PLUGINS_CONFIG
# PLUGINS_CONFIG['my_plugin'] = {
# 'foo': 'bar',
# 'buzz': 'bazz'
# }
## Remote authentication support
# REMOTE_AUTH_DEFAULT_PERMISSIONS = {}
## 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': 'netbox',
# 'AWS_S3_REGION_NAME': 'eu-west-1',
# }
## This file can contain arbitrary Python code, e.g.:
# from datetime import datetime
# now = datetime.now().strftime("%d/%m/%Y %H:%M:%S")
# BANNER_TOP = f'<marquee width="200px">This instance started on {now}.</marquee>'

84
etc/netbox/etc/netbox/config/ldap/ldap_config.py

@ -1,84 +0,0 @@
import ldap
from django_auth_ldap.config import LDAPSearch
from importlib import import_module
from os import environ
# Read secret from file
def _read_secret(secret_name, default=None):
try:
f = open('/run/secrets/' + secret_name, 'r', encoding='utf-8')
except EnvironmentError:
return default
else:
with f:
return f.readline().strip()
# Import and return the group type based on string name
def _import_group_type(group_type_name):
mod = import_module('django_auth_ldap.config')
try:
return getattr(mod, group_type_name)()
except:
return None
# Server URI
AUTH_LDAP_SERVER_URI = environ.get('AUTH_LDAP_SERVER_URI', '')
# The following may be needed if you are binding to Active Directory.
AUTH_LDAP_CONNECTION_OPTIONS = {
ldap.OPT_REFERRALS: 0
}
# Set the DN and password for the NetBox service account.
AUTH_LDAP_BIND_DN = environ.get('AUTH_LDAP_BIND_DN', '')
AUTH_LDAP_BIND_PASSWORD = _read_secret('auth_ldap_bind_password', environ.get('AUTH_LDAP_BIND_PASSWORD', ''))
# Set a string template that describes any user’s distinguished name based on the username.
AUTH_LDAP_USER_DN_TEMPLATE = environ.get('AUTH_LDAP_USER_DN_TEMPLATE', None)
# Enable STARTTLS for ldap authentication.
AUTH_LDAP_START_TLS = environ.get('AUTH_LDAP_START_TLS', 'False').lower() == 'true'
# Include this setting if you want to ignore certificate errors. This might be needed to accept a self-signed cert.
# Note that this is a NetBox-specific setting which sets:
# ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER)
LDAP_IGNORE_CERT_ERRORS = environ.get('LDAP_IGNORE_CERT_ERRORS', 'False').lower() == 'true'
AUTH_LDAP_USER_SEARCH_BASEDN = environ.get('AUTH_LDAP_USER_SEARCH_BASEDN', '')
AUTH_LDAP_USER_SEARCH_ATTR = environ.get('AUTH_LDAP_USER_SEARCH_ATTR', 'sAMAccountName')
AUTH_LDAP_USER_SEARCH = LDAPSearch(AUTH_LDAP_USER_SEARCH_BASEDN,
ldap.SCOPE_SUBTREE,
"(" + AUTH_LDAP_USER_SEARCH_ATTR + "=%(user)s)")
# This search ought to return all groups to which the user belongs. django_auth_ldap uses this to determine group
# heirarchy.
AUTH_LDAP_GROUP_SEARCH_BASEDN = environ.get('AUTH_LDAP_GROUP_SEARCH_BASEDN', '')
AUTH_LDAP_GROUP_SEARCH_CLASS = environ.get('AUTH_LDAP_GROUP_SEARCH_CLASS', 'group')
AUTH_LDAP_GROUP_SEARCH = LDAPSearch(AUTH_LDAP_GROUP_SEARCH_BASEDN, ldap.SCOPE_SUBTREE,
"(objectClass=" + AUTH_LDAP_GROUP_SEARCH_CLASS + ")")
AUTH_LDAP_GROUP_TYPE = _import_group_type(environ.get('AUTH_LDAP_GROUP_TYPE', 'GroupOfNamesType'))
# Define a group required to login.
AUTH_LDAP_REQUIRE_GROUP = environ.get('AUTH_LDAP_REQUIRE_GROUP_DN', '')
# Define special user types using groups. Exercise great caution when assigning superuser status.
AUTH_LDAP_USER_FLAGS_BY_GROUP = {
"is_active": environ.get('AUTH_LDAP_REQUIRE_GROUP_DN', ''),
"is_staff": environ.get('AUTH_LDAP_IS_ADMIN_DN', ''),
"is_superuser": environ.get('AUTH_LDAP_IS_SUPERUSER_DN', '')
}
# For more granular permissions, we can map LDAP groups to Django groups.
AUTH_LDAP_FIND_GROUP_PERMS = environ.get('AUTH_LDAP_FIND_GROUP_PERMS', 'True').lower() == 'true'
AUTH_LDAP_MIRROR_GROUPS = environ.get('AUTH_LDAP_MIRROR_GROUPS', '').lower() == 'true'
# Cache groups for one hour to reduce LDAP traffic
AUTH_LDAP_CACHE_TIMEOUT = int(environ.get('AUTH_LDAP_CACHE_TIMEOUT', 3600))
# Populate the Django user from the LDAP directory.
AUTH_LDAP_USER_ATTR_MAP = {
"first_name": environ.get('AUTH_LDAP_ATTR_FIRSTNAME', 'givenName'),
"last_name": environ.get('AUTH_LDAP_ATTR_LASTNAME', 'sn'),
"email": environ.get('AUTH_LDAP_ATTR_MAIL', 'mail')
}

46
etc/netbox/etc/netbox/reports/devices.py.example

@ -1,46 +0,0 @@
from dcim.choices import DeviceStatusChoices
from dcim.models import ConsolePort, Device, PowerPort
from extras.reports import Report
class DeviceConnectionsReport(Report):
description = "Validate the minimum physical connections for each device"
def test_console_connection(self):
# Check that every console port for every active device has a connection defined.
active = DeviceStatusChoices.STATUS_ACTIVE
for console_port in ConsolePort.objects.prefetch_related('device').filter(device__status=active):
if console_port.connected_endpoint is None:
self.log_failure(
console_port.device,
"No console connection defined for {}".format(console_port.name)
)
elif not console_port.connection_status:
self.log_warning(
console_port.device,
"Console connection for {} marked as planned".format(console_port.name)
)
else:
self.log_success(console_port.device)
def test_power_connections(self):
# Check that every active device has at least two connected power supplies.
for device in Device.objects.filter(status=DeviceStatusChoices.STATUS_ACTIVE):
connected_ports = 0
for power_port in PowerPort.objects.filter(device=device):
if power_port.connected_endpoint is not None:
connected_ports += 1
if not power_port.connection_status:
self.log_warning(
device,
"Power connection for {} marked as planned".format(power_port.name)
)
if connected_ports < 2:
self.log_failure(
device,
"{} connected power supplies found (2 needed)".format(connected_ports)
)
else:
self.log_success(device)

0
etc/netbox/etc/netbox/scripts/__init__.py

6
etc/netbox/opt/netbox/initializers/aggregates.yml

@ -1,6 +0,0 @@
#- prefix: 10.0.0.0/16
# rir: RFC1918
#- prefix: fd00:ccdd::/32
# rir: RFC4193 ULA
#- prefix: 2001:db8::/32
# rir: RFC3849

2
etc/netbox/opt/netbox/initializers/cluster_types.yml

@ -1,2 +0,0 @@
#- name: Hyper-V
# slug: hyper-v

5
etc/netbox/opt/netbox/initializers/clusters.yml

@ -1,5 +0,0 @@
#- name: cluster1
# type: Hyper-V
#- name: cluster2
# type: Hyper-V
# site: SING 1

97
etc/netbox/opt/netbox/initializers/custom_fields.yml

@ -1,97 +0,0 @@
# Possible Choices:
# type:
# - text
# - integer
# - boolean
# - date
# - url
# - select
# filter_logic:
# - disabled
# - loose
# - exact
#
# Examples:
#text_field:
# type: text
# label: Custom Text
# description: Enter text in a text field.
# required: false
# weight: 0
# on_objects:
# - dcim.models.Device
# - dcim.models.Rack
# - dcim.models.Site
# - dcim.models.DeviceType
# - ipam.models.IPAddress
# - ipam.models.Prefix
# - tenancy.models.Tenant
# - virtualization.models.VirtualMachine
#integer_field:
# type: integer
# label: Custom Number
# description: Enter numbers into an integer field.
# required: true
# filter_logic: loose
# weight: 10
# on_objects:
# - tenancy.models.Tenant
#select_field:
# type: select
# label: Choose between items
# required: false
# filter_logic: exact
# weight: 30
# on_objects:
# - dcim.models.Device
# choices:
# - value: First Item
# weight: 10
# - value: Second Item
# weight: 20
# - value: Third Item
# weight: 30
# - value: Fifth Item
# weight: 50
# - value: Fourth Item
# weight: 40
#select_field_auto_weight:
# type: select
# label: Choose between items
# required: false
# filter_logic: loose
# weight: 30
# on_objects:
# - dcim.models.Device
# choices:
# - value: A
# - value: B
# - value: C
# - value: "D like deprecated"
# weight: 999
# - value: E
#boolean_field:
# type: boolean
# label: Yes Or No?
# required: true
# filter_logic: loose
# default: "false" # important: but "false" in quotes!
# weight: 90
# on_objects:
# - dcim.models.Device
#url_field:
# type: url
# label: Hyperlink
# description: Link to something nice.
# required: true
# filter_logic: disabled
# on_objects:
# - tenancy.models.Tenant
#date_field:
# type: date
# label: Important Date
# required: false
# filter_logic: disabled
# on_objects:
# - dcim.models.Device

18
etc/netbox/opt/netbox/initializers/dcim_interfaces.yml

@ -1,18 +0,0 @@
# Possible Choices:
# type:
# - virtual
# - lag
# - 1000base-t
# - ... and many more. See for yourself:
# https://github.com/netbox-community/netbox/blob/295d4f0394b431351c0cb2c3ecc791df68c6c2fb/netbox/dcim/choices.py#L510
#
# Examples:
#- device: server01
# enabled: true
# type: virtual
# name: to-server02
#- device: server02
# enabled: true
# type: virtual
# name: to-server01

15
etc/netbox/opt/netbox/initializers/device_roles.yml

@ -1,15 +0,0 @@
#- name: switch
# slug: switch
# color: Grey
#- name: router
# slug: router
# color: Cyan
#- name: load-balancer
# slug: load-balancer
# color: Red
#- name: server
# slug: server
# color: Blue
#- name: patchpanel
# slug: patchpanel
# color: Black

23
etc/netbox/opt/netbox/initializers/device_types.yml

@ -1,23 +0,0 @@
#- model: Model 1
# manufacturer: Manufacturer 1
# slug: model-1
# u_height: 2
# custom_fields:
# text_field: Description
#- model: Model 2
# manufacturer: Manufacturer 1
# slug: model-2
# custom_fields:
# text_field: Description
#- model: Model 3
# manufacturer: Manufacturer 1
# slug: model-3
# is_full_depth: false
# u_height: 0
# custom_fields:
# text_field: Description
#- model: Other
# manufacturer: No Name
# slug: other
# custom_fields:
# text_field: Description

44
etc/netbox/opt/netbox/initializers/devices.yml

@ -1,44 +0,0 @@
# Possible Choices:
# face:
# - front
# - rear
# status:
# - offline
# - active
# - planned
# - staged
# - failed
# - inventory
# - decommissioning
#
# Examples:
#
#- name: server01
# device_role: server
# device_type: Other
# site: AMS 1
# rack: rack-01
# face: front
# position: 1
# custom_fields:
# text_field: Description
#- name: server02
# device_role: server
# device_type: Other
# site: AMS 2
# rack: rack-02
# face: front
# position: 2
# primary_ip4: 10.1.1.2/24
# primary_ip6: 2001:db8:a000:1::2/64
# custom_fields:
# text_field: Description
#- name: server03
# device_role: server
# device_type: Other
# site: SING 1
# rack: rack-03
# face: front
# position: 3
# custom_fields:
# text_field: Description

35
etc/netbox/opt/netbox/initializers/groups.yml

@ -1,35 +0,0 @@
#To list all permissions, run:
#
#docker-compose run --rm --entrypoint /bin/bash netbox
#$ ./manage.py migrate
#$ ./manage.py shell
#> from django.contrib.auth.models import Permission
#> print('\n'.join([p.codename for p in Permission.objects.all()]))
#
#Permission lists support wildcards. See the examples below.
#
#Examples:
#applications:
# users:
# - technical_user
#readers:
# users:
# - reader
#writers:
# users:
# - writer
# permissions:
# - delete_device
# - delete_virtualmachine
# - add_*
# - change_*
#vm_managers:
# permissions:
# - '*_virtualmachine'
#device_managers:
# permissions:
# - '*device*'
#creators:
# permissions:
# - add_*

44
etc/netbox/opt/netbox/initializers/ip_addresses.yml

@ -1,44 +0,0 @@
## Possible Choices:
## status:
## - active
## - reserved
## - deprecated
## - dhcp
## role:
## - loopback
## - secondary
## - anycast
## - vip
## - vrrp
## - hsrp
## - glbp
## - carp
##
## Examples:
#
#- address: 10.1.1.1/24
# device: server01
# interface: to-server02
# status: active
# vrf: vrf1
#- address: 2001:db8:a000:1::1/64
# device: server01
# interface: to-server02
# status: active
# vrf: vrf1
#- address: 10.1.1.2/24
# device: server02
# interface: to-server01
# status: active
#- address: 2001:db8:a000:1::2/64
# device: server02
# interface: to-server01
# status: active
#- address: 10.1.1.10/24
# description: reserved IP
# status: reserved
# tenant: tenant1
#- address: 2001:db8:a000:1::10/64
# description: reserved IP
# status: reserved
# tenant: tenant1

2
etc/netbox/opt/netbox/initializers/manufacturers.yml

@ -1,2 +0,0 @@
#- name: Manufacturer 1
# slug: manufacturer-1

15
etc/netbox/opt/netbox/initializers/platforms.yml

@ -1,15 +0,0 @@
#- name: Platform 1
# slug: platform-1
# manufacturer: Manufacturer 1
# napalm_driver: driver1
# napalm_args: "{'arg1': 'value1', 'arg2': 'value2'}"
#- name: Platform 2
# slug: platform-2
# manufacturer: Manufacturer 2
# napalm_driver: driver2
# napalm_args: "{'arg1': 'value1', 'arg2': 'value2'}"
#- name: Platform 3
# slug: platform-3
# manufacturer: No Name
# napalm_driver: driver3
# napalm_args: "{'arg1': 'value1', 'arg2': 'value2'}"

2
etc/netbox/opt/netbox/initializers/prefix_vlan_roles.yml

@ -1,2 +0,0 @@
#- name: Main Management
# slug: main-management

29
etc/netbox/opt/netbox/initializers/prefixes.yml

@ -1,29 +0,0 @@
# Possible Choices:
# status:
# - container
# - active
# - reserved
# - deprecated
#
# Examples:
#
#- description: prefix1
# prefix: 10.1.1.0/24
# site: AMS 1
# status: active
# tenant: tenant1
# vlan: vlan1
#- description: prefix2
# prefix: 10.1.2.0/24
# site: AMS 2
# status: active
# tenant: tenant2
# vlan: vlan2
# is_pool: true
# vrf: vrf2
#- description: ipv6 prefix1
# prefix: 2001:db8:a000:1::/64
# site: AMS 2
# status: active
# tenant: tenant2
# vlan: vlan2

3
etc/netbox/opt/netbox/initializers/rack_groups.yml

@ -1,3 +0,0 @@
#- name: cage 101
# slug: cage-101
# site: SING 1

12
etc/netbox/opt/netbox/initializers/rack_roles.yml

@ -1,12 +0,0 @@
#- name: Role 1
# slug: role-1
# color: Pink
#- name: Role 2
# slug: role-2
# color: Cyan
#- name: Role 3
# slug: role-3
# color: Grey
#- name: Role 4
# slug: role-4
# color: Teal

41
etc/netbox/opt/netbox/initializers/racks.yml

@ -1,41 +0,0 @@
# Possible Choices:
# width:
# - 19
# - 23
# types:
# - 2-post-frame
# - 4-post-frame
# - 4-post-cabinet
# - wall-frame
# - wall-cabinet
# outer_unit:
# - mm
# - in
#
# Examples:
#
#- site: AMS 1
# name: rack-01
# role: Role 1
# type: 4-post-cabinet
# width: 19
# u_height: 47
# custom_fields:
# text_field: Description
#- site: AMS 2
# name: rack-02
# role: Role 2
# type: 4-post-cabinet
# width: 19
# u_height: 47
# custom_fields:
# text_field: Description
#- site: SING 1
# name: rack-03
# group: cage 101
# role: Role 3
# type: 4-post-cabinet
# width: 19
# u_height: 47
# custom_fields:
# text_field: Description

4
etc/netbox/opt/netbox/initializers/regions.yml

@ -1,4 +0,0 @@
---
- name: Saint-Petersburg
slug: spb
...

9
etc/netbox/opt/netbox/initializers/rirs.yml

@ -1,9 +0,0 @@
#- is_private: true
# name: RFC1918
# slug: rfc1918
#- is_private: true
# name: RFC4193 ULA
# slug: rfc4193-ula
#- is_private: true
# name: RFC3849
# slug: rfc3849

32
etc/netbox/opt/netbox/initializers/sites.yml

@ -1,32 +0,0 @@
#- name: AMS 1
# slug: ams1
# region: Downtown
# status: active
# facility: Amsterdam 1
# asn: 12345
# custom_fields:
# text_field: Description
#- name: AMS 2
# slug: ams2
# region: Downtown
# status: active
# facility: Amsterdam 2
# asn: 54321
# custom_fields:
# text_field: Description
#- name: AMS 3
# slug: ams3
# region: Suburbs
# status: active
# facility: Amsterdam 3
# asn: 67890
# custom_fields:
# text_field: Description
#- name: SING 1
# slug: sing1
# region: Singapore
# status: active
# facility: Singapore 1
# asn: 09876
# custom_fields:
# text_field: Description

4
etc/netbox/opt/netbox/initializers/tenant_groups.yml

@ -1,4 +0,0 @@
#- name: Tenant Group 1
# slug: tenant-group-1
#- name: Tenant Group 2
# slug: tenant-group-2

5
etc/netbox/opt/netbox/initializers/tenants.yml

@ -1,5 +0,0 @@
#- name: tenant1
# slug: tenant1
#- name: tenant2
# slug: tenant2
# group: Tenant Group 2

23
etc/netbox/opt/netbox/initializers/users.yml

@ -1,23 +0,0 @@
# To list all permissions, run:
#
# docker-compose run --rm --entrypoint /bin/bash netbox
# $ ./manage.py migrate
# $ ./manage.py shell
# > from django.contrib.auth.models import Permission
# > print('\n'.join([p.codename for p in Permission.objects.all()]))
#
# Permission lists support wildcards. See the examples below.
#
# Examples:
#
#technical_user:
# api_token: 0123456789technicaluser789abcdef01234567 # must be looooong!
#reader:
# password: reader
#writer:
# password: writer
# permissions:
# - delete_device
# - delete_virtualmachine
# - add_*
# - change_*

28
etc/netbox/opt/netbox/initializers/virtual_machines.yml

@ -1,28 +0,0 @@
# Possible Choices:
# status:
# - active
# - offline
# - staged
#
# Examples:
#
#- cluster: cluster1
# comments: VM1
# disk: 200
# memory: 4096
# name: virtual machine 1
# platform: Platform 2
# status: active
# tenant: tenant1
# vcpus: 8
#- cluster: cluster1
# comments: VM2
# disk: 100
# memory: 2048
# name: virtual machine 2
# platform: Platform 2
# primary_ip4: 10.1.1.10/24
# primary_ip6: 2001:db8:a000:1::10/64
# status: active
# tenant: tenant1
# vcpus: 8

12
etc/netbox/opt/netbox/initializers/virtualization_interfaces.yml

@ -1,12 +0,0 @@
#- description: Network Interface 1
# enabled: true
# mac_address: 00:77:77:77:77:77
# mtu: 1500
# name: Network Interface 1
# virtual_machine: virtual machine 1
#- description: Network Interface 2
# enabled: true
# mac_address: 00:55:55:55:55:55
# mtu: 1500
# name: Network Interface 2
# virtual_machine: virtual machine 1

6
etc/netbox/opt/netbox/initializers/vlan_groups.yml

@ -1,6 +0,0 @@
#- name: VLAN group 1
# site: AMS 1
# slug: vlan-group-1
#- name: VLAN group 2
# site: AMS 1
# slug: vlan-group-2

19
etc/netbox/opt/netbox/initializers/vlans.yml

@ -1,19 +0,0 @@
# Possible Choices:
# status:
# - active
# - reserved
# - deprecated
#
# Examples:
#
#- name: vlan1
# site: AMS 1
# status: active
# vid: 5
# role: Main Management
# description: VLAN 5 for MGMT
#- group: VLAN group 2
# name: vlan2
# site: AMS 1
# status: active
# vid: 1300

8
etc/netbox/opt/netbox/initializers/vrfs.yml

@ -1,8 +0,0 @@
#- enforce_unique: true
# name: vrf1
# tenant: tenant1
# description: main VRF
#- enforce_unique: true
# name: vrf2
# rd: "6500:6500"
# tenant: tenant2

23
etc/netbox/opt/netbox/startup_scripts/000_users.py

@ -1,23 +0,0 @@
import sys
from django.contrib.auth.models import Group, User
from startup_script_utils import load_yaml, set_permissions
from users.models import Token
users = load_yaml('/opt/netbox/initializers/users.yml')
if users is None:
sys.exit()
for username, user_details in users.items():
if not User.objects.filter(username=username):
user = User.objects.create_user(
username = username,
password = user_details.get('password', 0) or User.objects.make_random_password())
print("👤 Created user",username)
if user_details.get('api_token', 0):
Token.objects.create(user=user, key=user_details['api_token'])
yaml_permissions = user_details.get('permissions', [])
set_permissions(user.user_permissions, yaml_permissions)

23
etc/netbox/opt/netbox/startup_scripts/010_groups.py

@ -1,23 +0,0 @@
import sys
from django.contrib.auth.models import Group, User
from startup_script_utils import load_yaml, set_permissions
groups = load_yaml('/opt/netbox/initializers/groups.yml')
if groups is None:
sys.exit()
for groupname, group_details in groups.items():
group, created = Group.objects.get_or_create(name=groupname)
if created:
print("👥 Created group", groupname)
for username in group_details.get('users', []):
user = User.objects.get(username=username)
if user:
user.groups.add(group)
yaml_permissions = group_details.get('permissions', [])
set_permissions(group.permissions, yaml_permissions)

54
etc/netbox/opt/netbox/startup_scripts/020_custom_fields.py

@ -1,54 +0,0 @@
from extras.models import CustomField, CustomFieldChoice
from startup_script_utils import load_yaml
import sys
def get_class_for_class_path(class_path):
import importlib
from django.contrib.contenttypes.models import ContentType
module_name, class_name = class_path.rsplit(".", 1)
module = importlib.import_module(module_name)
clazz = getattr(module, class_name)
return ContentType.objects.get_for_model(clazz)
customfields = load_yaml('/opt/netbox/initializers/custom_fields.yml')
if customfields is None:
sys.exit()
for cf_name, cf_details in customfields.items():
custom_field, created = CustomField.objects.get_or_create(name = cf_name)
if created:
if cf_details.get('default', 0):
custom_field.default = cf_details['default']
if cf_details.get('description', 0):
custom_field.description = cf_details['description']
if cf_details.get('label', 0):
custom_field.label = cf_details['label']
for object_type in cf_details.get('on_objects', []):
custom_field.obj_type.add(get_class_for_class_path(object_type))
if cf_details.get('required', 0):
custom_field.required = cf_details['required']
if cf_details.get('type', 0):
custom_field.type = cf_details['type']
if cf_details.get('weight', 0):
custom_field.weight = cf_details['weight']
custom_field.save()
for idx, choice_details in enumerate(cf_details.get('choices', [])):
choice, _ = CustomFieldChoice.objects.get_or_create(
field=custom_field,
value=choice_details['value'],
defaults={'weight': idx * 10}
)
print("🔧 Created custom field", cf_name)

26
etc/netbox/opt/netbox/startup_scripts/030_regions.py

@ -1,26 +0,0 @@
from dcim.models import Region
from startup_script_utils import load_yaml
import sys
regions = load_yaml('/opt/netbox/initializers/regions.yml')
if regions is None:
sys.exit()
optional_assocs = {
'parent': (Region, 'name')
}
for params in regions:
for assoc, details in optional_assocs.items():
if assoc in params:
model, field = details
query = { field: params.pop(assoc) }
params[assoc] = model.objects.get(**query)
region, created = Region.objects.get_or_create(**params)
if created:
print("🌐 Created region", region.name)

41
etc/netbox/opt/netbox/startup_scripts/040_sites.py

@ -1,41 +0,0 @@
from dcim.models import Region, Site
from extras.models import CustomField, CustomFieldValue
from tenancy.models import Tenant
from startup_script_utils import load_yaml
import sys
sites = load_yaml('/opt/netbox/initializers/sites.yml')
if sites is None:
sys.exit()
optional_assocs = {
'region': (Region, 'name'),
'tenant': (Tenant, 'name')
}
for params in sites:
custom_fields = params.pop('custom_fields', None)
for assoc, details in optional_assocs.items():
if assoc in params:
model, field = details
query = { field: params.pop(assoc) }
params[assoc] = model.objects.get(**query)
site, created = Site.objects.get_or_create(**params)
if created:
if custom_fields is not None:
for cf_name, cf_value in custom_fields.items():
custom_field = CustomField.objects.get(name=cf_name)
custom_field_value = CustomFieldValue.objects.create(
field=custom_field,
obj=site,
value=cf_value
)
site.custom_field_values.add(custom_field_value)
print("📍 Created site", site.name)

14
etc/netbox/opt/netbox/startup_scripts/050_manufacturers.py

@ -1,14 +0,0 @@
from dcim.models import Manufacturer
from startup_script_utils import load_yaml
import sys
manufacturers = load_yaml('/opt/netbox/initializers/manufacturers.yml')
if manufacturers is None:
sys.exit()
for params in manufacturers:
manufacturer, created = Manufacturer.objects.get_or_create(**params)
if created:
print("🏭 Created Manufacturer", manufacturer.name)

51
etc/netbox/opt/netbox/startup_scripts/060_device_types.py

@ -1,51 +0,0 @@
from dcim.models import DeviceType, Manufacturer, Region
from tenancy.models import Tenant
from extras.models import CustomField, CustomFieldValue
from startup_script_utils import load_yaml
import sys
device_types = load_yaml('/opt/netbox/initializers/device_types.yml')
if device_types is None:
sys.exit()
required_assocs = {
'manufacturer': (Manufacturer, 'name')
}
optional_assocs = {
'region': (Region, 'name'),
'tenant': (Tenant, 'name')
}
for params in device_types:
custom_fields = params.pop('custom_fields', None)
for assoc, details in required_assocs.items():
model, field = details
query = { field: params.pop(assoc) }
params[assoc] = model.objects.get(**query)
for assoc, details in optional_assocs.items():
if assoc in params:
model, field = details
query = { field: params.pop(assoc) }
params[assoc] = model.objects.get(**query)
device_type, created = DeviceType.objects.get_or_create(**params)
if created:
if custom_fields is not None:
for cf_name, cf_value in custom_fields.items():
custom_field = CustomField.objects.get(name=cf_name)
custom_field_value = CustomFieldValue.objects.create(
field=custom_field,
obj=device_type,
value=cf_value
)
device_type.custom_field_values.add(custom_field_value)
print("🔡 Created device type", device_type.manufacturer, device_type.model)

23
etc/netbox/opt/netbox/startup_scripts/070_rack_roles.py

@ -1,23 +0,0 @@
from dcim.models import RackRole
from utilities.choices import ColorChoices
from startup_script_utils import load_yaml
import sys
rack_roles = load_yaml('/opt/netbox/initializers/rack_roles.yml')
if rack_roles is None:
sys.exit()
for params in rack_roles:
if 'color' in params:
color = params.pop('color')
for color_tpl in ColorChoices:
if color in color_tpl:
params['color'] = color_tpl[0]
rack_role, created = RackRole.objects.get_or_create(**params)
if created:
print("🎨 Created rack role", rack_role.name)

25
etc/netbox/opt/netbox/startup_scripts/075_rack_groups.py

@ -1,25 +0,0 @@
from dcim.models import Site,RackGroup
from startup_script_utils import load_yaml
import sys
rack_groups = load_yaml('/opt/netbox/initializers/rack_groups.yml')
if rack_groups is None:
sys.exit()
required_assocs = {
'site': (Site, 'name')
}
for params in rack_groups:
for assoc, details in required_assocs.items():
model, field = details
query = { field: params.pop(assoc) }
params[assoc] = model.objects.get(**query)
rack_group, created = RackGroup.objects.get_or_create(**params)
if created:
print("🎨 Created rack group", rack_group.name)

52
etc/netbox/opt/netbox/startup_scripts/080_racks.py

@ -1,52 +0,0 @@
from dcim.models import Site, RackRole, Rack, RackGroup
from tenancy.models import Tenant
from extras.models import CustomField, CustomFieldValue
from startup_script_utils import load_yaml
import sys
racks = load_yaml('/opt/netbox/initializers/racks.yml')
if racks is None:
sys.exit()
required_assocs = {
'site': (Site, 'name')
}
optional_assocs = {
'role': (RackRole, 'name'),
'tenant': (Tenant, 'name'),
'group': (RackGroup, 'name')
}
for params in racks:
custom_fields = params.pop('custom_fields', None)
for assoc, details in required_assocs.items():
model, field = details
query = { field: params.pop(assoc) }
params[assoc] = model.objects.get(**query)
for assoc, details in optional_assocs.items():
if assoc in params:
model, field = details
query = { field: params.pop(assoc) }
params[assoc] = model.objects.get(**query)
rack, created = Rack.objects.get_or_create(**params)
if created:
if custom_fields is not None:
for cf_name, cf_value in custom_fields.items():
custom_field = CustomField.objects.get(name=cf_name)
custom_field_value = CustomFieldValue.objects.create(
field=custom_field,
obj=rack,
value=cf_value
)
rack.custom_field_values.add(custom_field_value)
print("🔳 Created rack", rack.site, rack.name)

24
etc/netbox/opt/netbox/startup_scripts/090_device_roles.py

@ -1,24 +0,0 @@
from dcim.models import DeviceRole
from utilities.choices import ColorChoices
from startup_script_utils import load_yaml
import sys
device_roles = load_yaml('/opt/netbox/initializers/device_roles.yml')
if device_roles is None:
sys.exit()
for params in device_roles:
if 'color' in params:
color = params.pop('color')
for color_tpl in ColorChoices:
if color in color_tpl:
params['color'] = color_tpl[0]
device_role, created = DeviceRole.objects.get_or_create(**params)
if created:
print("🎨 Created device role", device_role.name)

26
etc/netbox/opt/netbox/startup_scripts/100_platforms.py

@ -1,26 +0,0 @@
from dcim.models import Manufacturer, Platform
from startup_script_utils import load_yaml
import sys
platforms = load_yaml('/opt/netbox/initializers/platforms.yml')
if platforms is None:
sys.exit()
optional_assocs = {
'manufacturer': (Manufacturer, 'name'),
}
for params in platforms:
for assoc, details in optional_assocs.items():
if assoc in params:
model, field = details
query = { field: params.pop(assoc) }
params[assoc] = model.objects.get(**query)
platform, created = Platform.objects.get_or_create(**params)
if created:
print("💾 Created platform", platform.name)

14
etc/netbox/opt/netbox/startup_scripts/110_tenant_groups.py

@ -1,14 +0,0 @@
from tenancy.models import TenantGroup
from startup_script_utils import load_yaml
import sys
tenant_groups = load_yaml('/opt/netbox/initializers/tenant_groups.yml')
if tenant_groups is None:
sys.exit()
for params in tenant_groups:
tenant_group, created = TenantGroup.objects.get_or_create(**params)
if created:
print("🔳 Created Tenant Group", tenant_group.name)

39
etc/netbox/opt/netbox/startup_scripts/120_tenants.py

@ -1,39 +0,0 @@
from tenancy.models import Tenant, TenantGroup
from extras.models import CustomField, CustomFieldValue
from startup_script_utils import load_yaml
import sys
tenants = load_yaml('/opt/netbox/initializers/tenants.yml')
if tenants is None:
sys.exit()
optional_assocs = {
'group': (TenantGroup, 'name')
}
for params in tenants:
custom_fields = params.pop('custom_fields', None)
for assoc, details in optional_assocs.items():
if assoc in params:
model, field = details
query = { field: params.pop(assoc) }
params[assoc] = model.objects.get(**query)
tenant, created = Tenant.objects.get_or_create(**params)
if created:
if custom_fields is not None:
for cf_name, cf_value in custom_fields.items():
custom_field = CustomField.objects.get(name=cf_name)
custom_field_value = CustomFieldValue.objects.create(
field=custom_field,
obj=tenant,
value=cf_value
)
tenant.custom_field_values.add(custom_field_value)
print("👩‍💻 Created Tenant", tenant.name)

59
etc/netbox/opt/netbox/startup_scripts/130_devices.py

@ -1,59 +0,0 @@
from dcim.models import Site, Rack, DeviceRole, DeviceType, Device, Platform
from virtualization.models import Cluster
from tenancy.models import Tenant
from extras.models import CustomField, CustomFieldValue
from startup_script_utils import load_yaml
import sys
devices = load_yaml('/opt/netbox/initializers/devices.yml')
if devices is None:
sys.exit()
required_assocs = {
'device_role': (DeviceRole, 'name'),
'device_type': (DeviceType, 'model'),
'site': (Site, 'name')
}
optional_assocs = {
'tenant': (Tenant, 'name'),
'platform': (Platform, 'name'),
'rack': (Rack, 'name'),
'cluster': (Cluster, 'name')
}
for params in devices:
custom_fields = params.pop('custom_fields', None)
# primary ips are handled later in `270_primary_ips.py`
params.pop('primary_ip4', None)
params.pop('primary_ip6', None)
for assoc, details in required_assocs.items():
model, field = details
query = { field: params.pop(assoc) }
params[assoc] = model.objects.get(**query)
for assoc, details in optional_assocs.items():
if assoc in params:
model, field = details
query = { field: params.pop(assoc) }
params[assoc] = model.objects.get(**query)
device, created = Device.objects.get_or_create(**params)
if created:
if custom_fields is not None:
for cf_name, cf_value in custom_fields.items():
custom_field = CustomField.objects.get(name=cf_name)
custom_field_value = CustomFieldValue.objects.create(
field=custom_field,
obj=device,
value=cf_value
)
device.custom_field_values.add(custom_field_value)
print("🖥️ Created device", device.name)

14
etc/netbox/opt/netbox/startup_scripts/140_cluster_types.py

@ -1,14 +0,0 @@
from virtualization.models import ClusterType
from startup_script_utils import load_yaml
import sys
cluster_types = load_yaml('/opt/netbox/initializers/cluster_types.yml')
if cluster_types is None:
sys.exit()
for params in cluster_types:
cluster_type, created = ClusterType.objects.get_or_create(**params)
if created:
print("🧰 Created Cluster Type", cluster_type.name)

14
etc/netbox/opt/netbox/startup_scripts/150_rirs.py

@ -1,14 +0,0 @@
from ipam.models import RIR
from startup_script_utils import load_yaml
import sys
rirs = load_yaml('/opt/netbox/initializers/rirs.yml')
if rirs is None:
sys.exit()
for params in rirs:
rir, created = RIR.objects.get_or_create(**params)
if created:
print("🗺️ Created RIR", rir.name)

42
etc/netbox/opt/netbox/startup_scripts/160_aggregates.py

@ -1,42 +0,0 @@
from ipam.models import Aggregate, RIR
from extras.models import CustomField, CustomFieldValue
from netaddr import IPNetwork
from startup_script_utils import load_yaml
import sys
aggregates = load_yaml('/opt/netbox/initializers/aggregates.yml')
if aggregates is None:
sys.exit()
required_assocs = {
'rir': (RIR, 'name')
}
for params in aggregates:
custom_fields = params.pop('custom_fields', None)
params['prefix'] = IPNetwork(params['prefix'])
for assoc, details in required_assocs.items():
model, field = details
query = { field: params.pop(assoc) }
params[assoc] = model.objects.get(**query)
aggregate, created = Aggregate.objects.get_or_create(**params)
if created:
if custom_fields is not None:
for cf_name, cf_value in custom_fields.items():
custom_field = CustomField.objects.get(name=cf_name)
custom_field_value = CustomFieldValue.objects.create(
field=custom_field,
obj=aggregate,
value=cf_value
)
aggregate.custom_field_values.add(custom_field_value)
print("🗞️ Created Aggregate", aggregate.prefix)

51
etc/netbox/opt/netbox/startup_scripts/170_clusters.py

@ -1,51 +0,0 @@
from dcim.models import Site
from virtualization.models import Cluster, ClusterType, ClusterGroup
from extras.models import CustomField, CustomFieldValue
from startup_script_utils import load_yaml
import sys
clusters = load_yaml('/opt/netbox/initializers/clusters.yml')
if clusters is None:
sys.exit()
required_assocs = {
'type': (ClusterType, 'name')
}
optional_assocs = {
'site': (Site, 'name'),
'group': (ClusterGroup, 'name')
}
for params in clusters:
custom_fields = params.pop('custom_fields', None)
for assoc, details in required_assocs.items():
model, field = details
query = { field: params.pop(assoc) }
params[assoc] = model.objects.get(**query)
for assoc, details in optional_assocs.items():
if assoc in params:
model, field = details
query = { field: params.pop(assoc) }
params[assoc] = model.objects.get(**query)
cluster, created = Cluster.objects.get_or_create(**params)
if created:
if custom_fields is not None:
for cf_name, cf_value in custom_fields.items():
custom_field = CustomField.objects.get(name=cf_name)
custom_field_value = CustomFieldValue.objects.create(
field=custom_field,
obj=cluster,
value=cf_value
)
cluster.custom_field_values.add(custom_field_value)
print("🗄️ Created cluster", cluster.name)

42
etc/netbox/opt/netbox/startup_scripts/180_vrfs.py

@ -1,42 +0,0 @@
from ipam.models import VRF
from tenancy.models import Tenant
from extras.models import CustomField, CustomFieldValue
from startup_script_utils import load_yaml
import sys
vrfs = load_yaml('/opt/netbox/initializers/vrfs.yml')
if vrfs is None:
sys.exit()
optional_assocs = {
'tenant': (Tenant, 'name')
}
for params in vrfs:
custom_fields = params.pop('custom_fields', None)
for assoc, details in optional_assocs.items():
if assoc in params:
model, field = details
query = { field: params.pop(assoc) }
params[assoc] = model.objects.get(**query)
vrf, created = VRF.objects.get_or_create(**params)
if created:
if custom_fields is not None:
for cf_name, cf_value in custom_fields.items():
custom_field = CustomField.objects.get(name=cf_name)
custom_field_value = CustomFieldValue.objects.create(
field=custom_field,
obj=vrf,
value=cf_value
)
vrf.custom_field_values.add(custom_field_value)
print("📦 Created VRF", vrf.name)

14
etc/netbox/opt/netbox/startup_scripts/190_prefix_vlan_roles.py

@ -1,14 +0,0 @@
from ipam.models import Role
from startup_script_utils import load_yaml
import sys
roles = load_yaml('/opt/netbox/initializers/prefix_vlan_roles.yml')
if roles is None:
sys.exit()
for params in roles:
role, created = Role.objects.get_or_create(**params)
if created:
print("⛹️‍ Created Prefix/VLAN Role", role.name)

40
etc/netbox/opt/netbox/startup_scripts/200_vlan_groups.py

@ -1,40 +0,0 @@
from dcim.models import Site
from ipam.models import VLANGroup
from extras.models import CustomField, CustomFieldValue
from startup_script_utils import load_yaml
import sys
vlan_groups = load_yaml('/opt/netbox/initializers/vlan_groups.yml')
if vlan_groups is None:
sys.exit()
optional_assocs = {
'site': (Site, 'name')
}
for params in vlan_groups:
custom_fields = params.pop('custom_fields', None)
for assoc, details in optional_assocs.items():
if assoc in params:
model, field = details
query = { field: params.pop(assoc) }
params[assoc] = model.objects.get(**query)
vlan_group, created = VLANGroup.objects.get_or_create(**params)
if created:
if custom_fields is not None:
for cf_name, cf_value in custom_fields.items():
custom_field = CustomField.objects.get(name=cf_name)
custom_field_value = CustomFieldValue.objects.create(
field=custom_field,
obj=vlan_group,
value=cf_value
)
vlan_group.custom_field_values.add(custom_field_value)
print("🏘️ Created VLAN Group", vlan_group.name)

45
etc/netbox/opt/netbox/startup_scripts/210_vlans.py

@ -1,45 +0,0 @@
from dcim.models import Site
from ipam.models import VLAN, VLANGroup, Role
from tenancy.models import Tenant, TenantGroup
from extras.models import CustomField, CustomFieldValue
from startup_script_utils import load_yaml
import sys
vlans = load_yaml('/opt/netbox/initializers/vlans.yml')
if vlans is None:
sys.exit()
optional_assocs = {
'site': (Site, 'name'),
'tenant': (Tenant, 'name'),
'tenant_group': (TenantGroup, 'name'),
'group': (VLANGroup, 'name'),
'role': (Role, 'name')
}
for params in vlans:
custom_fields = params.pop('custom_fields', None)
for assoc, details in optional_assocs.items():
if assoc in params:
model, field = details
query = { field: params.pop(assoc) }
params[assoc] = model.objects.get(**query)
vlan, created = VLAN.objects.get_or_create(**params)
if created:
if custom_fields is not None:
for cf_name, cf_value in custom_fields.items():
custom_field = CustomField.objects.get(name=cf_name)
custom_field_value = CustomFieldValue.objects.create(
field=custom_field,
obj=vlan,
value=cf_value
)
vlan.custom_field_values.add(custom_field_value)
print("🏠 Created VLAN", vlan.name)

46
etc/netbox/opt/netbox/startup_scripts/220_prefixes.py

@ -1,46 +0,0 @@
from dcim.models import Site
from ipam.models import Prefix, VLAN, Role, VRF
from tenancy.models import Tenant, TenantGroup
from extras.models import CustomField, CustomFieldValue
from netaddr import IPNetwork
from startup_script_utils import load_yaml
import sys
prefixes = load_yaml('/opt/netbox/initializers/prefixes.yml')
if prefixes is None:
sys.exit()
optional_assocs = {
'site': (Site, 'name'),
'tenant': (Tenant, 'name'),
'tenant_group': (TenantGroup, 'name'),
'vlan': (VLAN, 'name'),
'role': (Role, 'name'),
'vrf': (VRF, 'name')
}
for params in prefixes:
custom_fields = params.pop('custom_fields', None)
params['prefix'] = IPNetwork(params['prefix'])
for assoc, details in optional_assocs.items():
if assoc in params:
model, field = details
query = { field: params.pop(assoc) }
params[assoc] = model.objects.get(**query)
prefix, created = Prefix.objects.get_or_create(**params)
if created:
if custom_fields is not None:
for cf_name, cf_value in custom_fields.items():
custom_field = CustomField.objects.get(name=cf_name)
custom_field_value = CustomFieldValue.objects.create(
field=custom_field,
obj=prefix,
value=cf_value
)
prefix.custom_field_values.add(custom_field_value)
print("📌 Created Prefix", prefix.prefix)

56
etc/netbox/opt/netbox/startup_scripts/230_virtual_machines.py

@ -1,56 +0,0 @@
from dcim.models import Site, Platform, DeviceRole
from virtualization.models import Cluster, VirtualMachine
from tenancy.models import Tenant
from extras.models import CustomField, CustomFieldValue
from startup_script_utils import load_yaml
import sys
virtual_machines = load_yaml('/opt/netbox/initializers/virtual_machines.yml')
if virtual_machines is None:
sys.exit()
required_assocs = {
'cluster': (Cluster, 'name')
}
optional_assocs = {
'tenant': (Tenant, 'name'),
'platform': (Platform, 'name'),
'role': (DeviceRole, 'name')
}
for params in virtual_machines:
custom_fields = params.pop('custom_fields', None)
# primary ips are handled later in `270_primary_ips.py`
params.pop('primary_ip4', None)
params.pop('primary_ip6', None)
for assoc, details in required_assocs.items():
model, field = details
query = { field: params.pop(assoc) }
params[assoc] = model.objects.get(**query)
for assoc, details in optional_assocs.items():
if assoc in params:
model, field = details
query = { field: params.pop(assoc) }
params[assoc] = model.objects.get(**query)
virtual_machine, created = VirtualMachine.objects.get_or_create(**params)
if created:
if custom_fields is not None:
for cf_name, cf_value in custom_fields.items():
custom_field = CustomField.objects.get(name=cf_name)
custom_field_value = CustomFieldValue.objects.create(
field=custom_field,
obj=virtual_machine,
value=cf_value
)
virtual_machine.custom_field_values.add(custom_field_value)
print("🖥️ Created virtual machine", virtual_machine.name)

38
etc/netbox/opt/netbox/startup_scripts/240_virtualization_interfaces.py

@ -1,38 +0,0 @@
from virtualization.models import VirtualMachine, VMInterface
from extras.models import CustomField, CustomFieldValue
from startup_script_utils import load_yaml
import sys
interfaces = load_yaml('/opt/netbox/initializers/virtualization_interfaces.yml')
if interfaces is None:
sys.exit()
required_assocs = {
'virtual_machine': (VirtualMachine, 'name')
}
for params in interfaces:
custom_fields = params.pop('custom_fields', None)
for assoc, details in required_assocs.items():
model, field = details
query = { field: params.pop(assoc) }
params[assoc] = model.objects.get(**query)
interface, created = VMInterface.objects.get_or_create(**params)
if created:
if custom_fields is not None:
for cf_name, cf_value in custom_fields.items():
custom_field = CustomField.objects.get(name=cf_name)
custom_field_value = CustomFieldValue.objects.create(
field=custom_field,
obj=interface,
value=cf_value
)
interface.custom_field_values.add(custom_field_value)
print("🧷 Created interface", interface.name, interface.virtual_machine.name)

38
etc/netbox/opt/netbox/startup_scripts/250_dcim_interfaces.py

@ -1,38 +0,0 @@
from dcim.models import Interface, Device
from extras.models import CustomField, CustomFieldValue
from startup_script_utils import load_yaml
import sys
interfaces= load_yaml('/opt/netbox/initializers/dcim_interfaces.yml')
if interfaces is None:
sys.exit()
required_assocs = {
'device': (Device, 'name')
}
for params in interfaces:
custom_fields = params.pop('custom_fields', None)
for assoc, details in required_assocs.items():
model, field = details
query = { field: params.pop(assoc) }
params[assoc] = model.objects.get(**query)
interface, created = Interface.objects.get_or_create(**params)
if created:
if custom_fields is not None:
for cf_name, cf_value in custom_fields.items():
custom_field = CustomField.objects.get(name=cf_name)
custom_field_value = CustomFieldValue.objects.create(
field=custom_field,
obj=interface,
value=cf_value
)
interface.custom_field_values.add(custom_field_value)
print("🧷 Created interface", interface.name, interface.device.name)

69
etc/netbox/opt/netbox/startup_scripts/260_ip_addresses.py

@ -1,69 +0,0 @@
import sys
from dcim.models import Device, Interface
from django.contrib.contenttypes.models import ContentType
from django.db.models import Q
from extras.models import CustomField, CustomFieldValue
from ipam.models import VRF, IPAddress
from netaddr import IPNetwork
from startup_script_utils import load_yaml
from tenancy.models import Tenant
from virtualization.models import VirtualMachine, VMInterface
ip_addresses = load_yaml('/opt/netbox/initializers/ip_addresses.yml')
if ip_addresses is None:
sys.exit()
optional_assocs = {
'tenant': (Tenant, 'name'),
'vrf': (VRF, 'name'),
'interface': (None, None)
}
vm_interface_ct = ContentType.objects.filter(Q(app_label='virtualization', model='vminterface')).first()
interface_ct = ContentType.objects.filter(Q(app_label='dcim', model='interface')).first()
for params in ip_addresses:
vm = params.pop('virtual_machine', None)
device = params.pop('device', None)
custom_fields = params.pop('custom_fields', None)
params['address'] = IPNetwork(params['address'])
if vm and device:
print("IP Address can only specify one of the following: virtual_machine or device.")
sys.exit()
for assoc, details in optional_assocs.items():
if assoc in params:
model, field = details
if assoc == 'interface':
if vm:
vm_id = VirtualMachine.objects.get(name=vm).id
query = { 'name': params.pop(assoc), "virtual_machine_id": vm_id }
params['assigned_object_type'] = vm_interface_ct
params['assigned_object_id'] = VMInterface.objects.get(**query).id
elif device:
dev_id = Device.objects.get(name=device).id
query = { 'name': params.pop(assoc), "device_id": dev_id }
params['assigned_object_type'] = interface_ct
params['assigned_object_id'] = Interface.objects.get(**query).id
else:
query = { field: params.pop(assoc) }
params[assoc] = model.objects.get(**query)
ip_address, created = IPAddress.objects.get_or_create(**params)
if created:
if custom_fields is not None:
for cf_name, cf_value in custom_fields.items():
custom_field = CustomField.objects.get(name=cf_name)
custom_field_value = CustomFieldValue.objects.create(
field=custom_field,
obj=ip_address,
value=cf_value
)
ip_address.custom_field_values.add(custom_field_value)
print("🧬 Created IP Address", ip_address.address)

43
etc/netbox/opt/netbox/startup_scripts/270_primary_ips.py

@ -1,43 +0,0 @@
from dcim.models import Device
from ipam.models import IPAddress
from virtualization.models import VirtualMachine
from startup_script_utils import load_yaml
import sys
def link_primary_ip(assets, asset_model):
for params in assets:
primary_ip_fields = set(params) & {'primary_ip4', 'primary_ip6'}
if not primary_ip_fields:
continue
for assoc, details in optional_assocs.items():
if assoc in params:
model, field = details
query = { field: params.pop(assoc) }
try:
params[assoc] = model.objects.get(**query)
except model.DoesNotExist:
primary_ip_fields -= {assoc}
print(f"⚠️ IP Address '{query[field]}' not found")
asset = asset_model.objects.get(name=params['name'])
for field in primary_ip_fields:
if getattr(asset, field) != params[field]:
setattr(asset, field, params[field])
print(f"🔗 Define primary IP '{params[field].address}' on '{asset.name}'")
asset.save()
devices = load_yaml('/opt/netbox/initializers/devices.yml')
virtual_machines = load_yaml('/opt/netbox/initializers/virtual_machines.yml')
if devices is None and virtual_machines is None:
sys.exit()
optional_assocs = {
'primary_ip4': (IPAddress, 'address'),
'primary_ip6': (IPAddress, 'address')
}
link_primary_ip(devices, Device)
link_primary_ip(virtual_machines, VirtualMachine)

29
etc/netbox/opt/netbox/startup_scripts/__main__.py

@ -1,29 +0,0 @@
#!/usr/bin/env python3
import runpy
from os import scandir
from os.path import dirname, abspath
this_dir = dirname(abspath(__file__))
def filename(f):
return f.name
with scandir(this_dir) as it:
for f in sorted(it, key = filename):
if not f.is_file():
continue
if f.name.startswith('__'):
continue
if not f.name.endswith('.py'):
continue
print(f"▶️ Running the startup script {f.path}")
try:
runpy.run_path(f.path)
except SystemExit as e:
if e.code is not None and e.code != 0:
print(f"‼️ The startup script {f.path} returned with code {e.code}, exiting.")
raise

2
etc/netbox/opt/netbox/startup_scripts/startup_script_utils/__init__.py

@ -1,2 +0,0 @@
from .load_yaml import load_yaml
from .permissions import set_permissions

10
etc/netbox/opt/netbox/startup_scripts/startup_script_utils/load_yaml.py

@ -1,10 +0,0 @@
from ruamel.yaml import YAML
from pathlib import Path
def load_yaml(yaml_file: str):
yf = Path(yaml_file)
if not yf.is_file():
return None
with yf.open("r") as stream:
yaml = YAML(typ="safe")
return yaml.load(stream)

18
etc/netbox/opt/netbox/startup_scripts/startup_script_utils/permissions.py

@ -1,18 +0,0 @@
from django.contrib.auth.models import Permission
def set_permissions(subject, permission_filters):
if subject is None or permission_filters is None:
return
subject.clear()
for permission_filter in permission_filters:
if "*" in permission_filter:
permission_filter_regex = "^" + permission_filter.replace("*", ".*") + "$"
permissions = Permission.objects.filter(codename__iregex=permission_filter_regex)
print(" ⚿ Granting", permissions.count(), "permissions matching '" + permission_filter + "'")
else:
permissions = Permission.objects.filter(codename=permission_filter)
print(" ⚿ Granting permission", permission_filter)
for permission in permissions:
subject.add(permission)