diff --git a/Dockerfile b/Dockerfile index 82576c1..7764248 100644 --- a/Dockerfile +++ b/Dockerfile @@ -26,7 +26,9 @@ RUN pip install --prefix="/install" --no-warn-script-location \ # ruamel is used in startup_scripts 'ruamel.yaml>=0.15,<0.16' \ # django_auth_ldap is required for ldap - django_auth_ldap + django_auth_ldap \ +# django-storages was introduced in 2.7 and is optional + django-storages ARG NETBOX_PATH COPY ${NETBOX_PATH}/requirements.txt / diff --git a/configuration/configuration.py b/configuration/configuration.py index 4199b9d..af121d9 100644 --- a/configuration/configuration.py +++ b/configuration/configuration.py @@ -37,9 +37,9 @@ DATABASE = { # PostgreSQL password 'HOST': os.environ.get('DB_HOST', 'localhost'), # Database server 'PORT': os.environ.get('DB_PORT', ''), # Database port (leave blank for default) - 'OPTIONS': {'sslmode': os.environ.get('DB_SSLMODE', 'prefer')}, + 'OPTIONS': {'sslmode': os.environ.get('DB_SSLMODE', 'prefer')}, # Database connection SSLMODE - 'CONN_MAX_AGE': int(os.environ.get('DB_CONN_MAX_AGE', '300')), + 'CONN_MAX_AGE': int(os.environ.get('DB_CONN_MAX_AGE', '300')), # Database connection persistence } @@ -51,13 +51,22 @@ SECRET_KEY = os.environ.get('SECRET_KEY', read_secret('secret_key')) # Redis database settings. The Redis database is used for caching and background processing such as webhooks REDIS = { - 'HOST': os.environ.get('REDIS_HOST', 'localhost'), - 'PORT': int(os.environ.get('REDIS_PORT', 6379)), - 'PASSWORD': os.environ.get('REDIS_PASSWORD', read_secret('redis_password')), - 'DATABASE': os.environ.get('REDIS_DATABASE', '0'), - 'CACHE_DATABASE': os.environ.get('REDIS_CACHE_DATABASE', '1'), - 'DEFAULT_TIMEOUT': os.environ.get('REDIS_TIMEOUT', '300'), - 'SSL': os.environ.get('REDIS_SSL', 'False').lower() == 'true', + 'webhooks': { + 'HOST': os.environ.get('REDIS_HOST', 'localhost'), + 'PORT': int(os.environ.get('REDIS_PORT', 6379)), + 'PASSWORD': os.environ.get('REDIS_PASSWORD', read_secret('redis_password')), + 'DATABASE': int(os.environ.get('REDIS_DATABASE', 0)), + 'DEFAULT_TIMEOUT': int(os.environ.get('REDIS_TIMEOUT', 300)), + 'SSL': os.environ.get('REDIS_SSL', 'False').lower() == 'true', + }, + 'caching': { + 'HOST': os.environ.get('REDIS_CACHE_HOST', os.environ.get('REDIS_HOST', 'localhost')), + 'PORT': int(os.environ.get('REDIS_CACHE_PORT', os.environ.get('REDIS_PORT', 6379))), + 'PASSWORD': os.environ.get('REDIS_CACHE_PASSWORD', os.environ.get('REDIS_PASSWORD', read_secret('redis_cache_password'))), + 'DATABASE': int(os.environ.get('REDIS_CACHE_DATABASE', 1)), + 'DEFAULT_TIMEOUT': int(os.environ.get('REDIS_CACHE_TIMEOUT', os.environ.get('REDIS_TIMEOUT', 300))), + 'SSL': os.environ.get('REDIS_CACHE_SSL', os.environ.get('REDIS_SSL', 'False')).lower() == 'true', + }, } ######################### @@ -172,10 +181,6 @@ SCRIPTS_ROOT = os.environ.get('SCRIPTS_ROOT', '/etc/netbox/scripts') # Time zone (default: UTC) TIME_ZONE = os.environ.get('TIME_ZONE', 'UTC') -# The Webhook event backend is disabled by default. Set this to True to enable it. Note that this requires a Redis -# database be configured and accessible by NetBox (see `REDIS` below). -WEBHOOKS_ENABLED = os.environ.get('WEBHOOKS_ENABLED', 'False').lower() == 'true' - # Date/time formatting. See the following link for supported formats: # https://docs.djangoproject.com/en/dev/ref/templates/builtins/#date DATE_FORMAT = os.environ.get('DATE_FORMAT', 'N j, Y') diff --git a/docker-compose.yml b/docker-compose.yml index 10b4ad9..3806480 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -5,6 +5,7 @@ services: depends_on: - postgres - redis + - redis-cache - netbox-worker env_file: env/netbox.env user: '101' @@ -50,6 +51,13 @@ services: env_file: env/redis.env volumes: - netbox-redis-data:/data + redis-cache: + image: redis:5-alpine + command: + - sh + - -c # this is to evaluate the $REDIS_PASSWORD from the env + - redis-server --requirepass $$REDIS_PASSWORD ## $$ because of docker-compose + env_file: env/redis.env volumes: netbox-static-files: driver: local diff --git a/env/netbox.env b/env/netbox.env index 4a75905..aaa7482 100644 --- a/env/netbox.env +++ b/env/netbox.env @@ -17,8 +17,11 @@ MAX_PAGE_SIZE=1000 REDIS_HOST=redis REDIS_PASSWORD=H733Kdjndks81 REDIS_DATABASE=0 -REDIS_CACHE_DATABASE=1 REDIS_SSL=false +REDIS_CACHE_HOST=redis-cache +REDIS_CACHE_PASSWORD=t4Ph722qJ5QHeQ1qfu36 +REDIS_CACHE_DATABASE=0 +REDIS_CACHE_SSL=false SECRET_KEY=r8OwDznj!!dci#P9ghmRfdu1Ysxm0AiPeDCQhKE+N_rClfWNj SKIP_STARTUP_SCRIPTS=false SKIP_SUPERUSER=false diff --git a/env/redis-cache.env b/env/redis-cache.env new file mode 100644 index 0000000..6285c33 --- /dev/null +++ b/env/redis-cache.env @@ -0,0 +1 @@ +REDIS_PASSWORD=t4Ph722qJ5QHeQ1qfu36 diff --git a/initializers/custom_fields.yml b/initializers/custom_fields.yml index 0b6472a..4085ab0 100644 --- a/initializers/custom_fields.yml +++ b/initializers/custom_fields.yml @@ -1,3 +1,18 @@ +## Possible Choices: +## type: +## - text +## - integer +## - boolean +## - date +## - url +## - select +## filter_logic: +## - disabled +## - loose +## - exact +## +## Examples: + # text_field: # type: text # label: Custom Text @@ -22,8 +37,8 @@ # weight: 10 # on_objects: # - tenancy.models.Tenant -# selection_field: -# type: selection +# select_field: +# type: select # label: Choose between items # required: false # filter_logic: exact @@ -41,8 +56,8 @@ # weight: 50 # - value: Fourth Item # weight: 40 -# selection_field_auto_weight: -# type: selection +# select_field_auto_weight: +# type: select # label: Choose between items # required: false # filter_logic: loose diff --git a/initializers/dcim_interfaces.yml b/initializers/dcim_interfaces.yml index 18920fe..4030530 100644 --- a/initializers/dcim_interfaces.yml +++ b/initializers/dcim_interfaces.yml @@ -1,8 +1,18 @@ +## 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 +# type: virtual # name: to-server02 # - device: server02 # enabled: true -# type: Virtual +# type: virtual # name: to-server01 diff --git a/initializers/devices.yml b/initializers/devices.yml index 0beb6f2..708b68c 100644 --- a/initializers/devices.yml +++ b/initializers/devices.yml @@ -1,9 +1,24 @@ +## 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 +# face: front # position: 1 # custom_fields: # text_field: Description @@ -12,7 +27,7 @@ # device_type: Other # site: AMS 2 # rack: rack-02 -# face: Front +# face: front # position: 2 # custom_fields: # text_field: Description @@ -21,7 +36,7 @@ # device_type: Other # site: SING 1 # rack: rack-03 -# face: Front +# face: front # position: 3 # custom_fields: # text_field: Description diff --git a/initializers/ip_addresses.yml b/initializers/ip_addresses.yml index 5738749..6ac38e9 100644 --- a/initializers/ip_addresses.yml +++ b/initializers/ip_addresses.yml @@ -1,26 +1,44 @@ +## 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 +# status: active # vrf: vrf1 # - address: 2001:db8:a000:1::1/64 # device: server01 # interface: to-server02 -# status: Active +# status: active # vrf: vrf1 # - address: 10.1.1.2/24 # device: server02 # interface: to-server01 -# status: Active +# status: active # - address: 2001:db8:a000:1::2/64 # device: server02 # interface: to-server01 -# status: Active +# status: active # - address: 10.1.1.10/24 # description: reserved IP -# status: Reserved +# status: reserved # tenant: tenant1 # - address: 2001:db8:a000:1::10/64 # description: reserved IP -# status: Reserved +# status: reserved # tenant: tenant1 diff --git a/initializers/prefixes.yml b/initializers/prefixes.yml index a7e6815..fbf3eee 100644 --- a/initializers/prefixes.yml +++ b/initializers/prefixes.yml @@ -1,13 +1,22 @@ +## Possible Choices: +## status: +## - container +## - active +## - reserved +## - deprecated +## +## Examples: + # - description: prefix1 # prefix: 10.1.1.0/24 # site: AMS 1 -# status: Active +# status: active # tenant: tenant1 # vlan: vlan1 # - description: prefix2 # prefix: 10.1.2.0/24 # site: AMS 2 -# status: Active +# status: active # tenant: tenant2 # vlan: vlan2 # is_pool: true @@ -15,6 +24,6 @@ # - description: ipv6 prefix1 # prefix: 2001:db8:a000:1::/64 # site: AMS 2 -# status: Active +# status: active # tenant: tenant2 # vlan: vlan2 diff --git a/initializers/racks.yml b/initializers/racks.yml index 3a31526..51502de 100644 --- a/initializers/racks.yml +++ b/initializers/racks.yml @@ -1,16 +1,32 @@ +## 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 inches +# 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 inches +# type: 4-post-cabinet +# width: 19 # u_height: 47 # custom_fields: # text_field: Description @@ -18,8 +34,8 @@ # name: rack-03 # group: cage 101 # role: Role 3 -# type: 4-post cabinet -# width: 19 inches +# type: 4-post-cabinet +# width: 19 # u_height: 47 # custom_fields: # text_field: Description diff --git a/initializers/virtual_machines.yml b/initializers/virtual_machines.yml index 5da75a2..2122920 100644 --- a/initializers/virtual_machines.yml +++ b/initializers/virtual_machines.yml @@ -1,10 +1,18 @@ +## Possible Choices: +## status: +## - active +## - offline +## - staged +## +## Examples: + # - cluster: cluster1 # comments: VM1 # disk: 200 # memory: 4096 # name: virtual machine 1 # platform: Platform 2 -# status: Active +# status: active # tenant: tenant1 # vcpus: 8 # - cluster: cluster1 @@ -13,6 +21,6 @@ # memory: 2048 # name: virtual machine 2 # platform: Platform 2 -# status: Active +# status: active # tenant: tenant1 # vcpus: 8 diff --git a/initializers/vlans.yml b/initializers/vlans.yml index 26532c7..a8cd521 100644 --- a/initializers/vlans.yml +++ b/initializers/vlans.yml @@ -1,11 +1,19 @@ +## Possible Choices: +## status: +## - active +## - reserved +## - deprecated +## +## Examples: + # - name: vlan1 # site: AMS 1 -# status: Active +# status: active # vid: 5 # role: Main Management # description: VLAN 5 for MGMT # - group: VLAN group 2 # name: vlan2 # site: AMS 1 -# status: Active +# status: active # vid: 1300 diff --git a/startup_scripts/020_custom_fields.py b/startup_scripts/020_custom_fields.py index 76a32bb..2f6ba72 100644 --- a/startup_scripts/020_custom_fields.py +++ b/startup_scripts/020_custom_fields.py @@ -1,19 +1,9 @@ -from extras.constants import CF_TYPE_TEXT, CF_TYPE_INTEGER, CF_TYPE_BOOLEAN, CF_TYPE_DATE, CF_TYPE_URL, CF_TYPE_SELECT, CF_FILTER_CHOICES from extras.models import CustomField, CustomFieldChoice from ruamel.yaml import YAML from pathlib import Path import sys -text_to_fields = { - 'boolean': CF_TYPE_BOOLEAN, - 'date': CF_TYPE_DATE, - 'integer': CF_TYPE_INTEGER, - 'selection': CF_TYPE_SELECT, - 'text': CF_TYPE_TEXT, - 'url': CF_TYPE_URL, -} - def get_class_for_class_path(class_path): import importlib from django.contrib.contenttypes.models import ContentType @@ -42,12 +32,6 @@ with file.open('r') as stream: if cf_details.get('description', 0): custom_field.description = cf_details['description'] - # If no filter_logic is specified then it will default to 'Loose' - if cf_details.get('filter_logic', 0): - for choice_id, choice_text in CF_FILTER_CHOICES: - if choice_text.lower() == cf_details['filter_logic']: - custom_field.filter_logic = choice_id - if cf_details.get('label', 0): custom_field.label = cf_details['label'] @@ -58,7 +42,7 @@ with file.open('r') as stream: custom_field.required = cf_details['required'] if cf_details.get('type', 0): - custom_field.type = text_to_fields[cf_details['type']] + custom_field.type = cf_details['type'] if cf_details.get('weight', 0): custom_field.weight = cf_details['weight'] diff --git a/startup_scripts/080_racks.py b/startup_scripts/080_racks.py index 05bca10..ed7713d 100644 --- a/startup_scripts/080_racks.py +++ b/startup_scripts/080_racks.py @@ -1,7 +1,6 @@ from dcim.models import Site, RackRole, Rack, RackGroup from tenancy.models import Tenant from extras.models import CustomField, CustomFieldValue -from dcim.constants import RACK_TYPE_CHOICES, RACK_WIDTH_CHOICES from ruamel.yaml import YAML from pathlib import Path import sys @@ -41,14 +40,6 @@ with file.open('r') as stream: params[assoc] = model.objects.get(**query) - for rack_type in RACK_TYPE_CHOICES: - if params['type'] in rack_type: - params['type'] = rack_type[0] - - for rack_width in RACK_WIDTH_CHOICES: - if params['width'] in rack_width: - params['width'] = rack_width[0] - rack, created = Rack.objects.get_or_create(**params) if created: diff --git a/startup_scripts/130_devices.py b/startup_scripts/130_devices.py index 2d8d3ca..4217549 100644 --- a/startup_scripts/130_devices.py +++ b/startup_scripts/130_devices.py @@ -1,5 +1,4 @@ from dcim.models import Site, Rack, DeviceRole, DeviceType, Device, Platform -from dcim.constants import RACK_FACE_CHOICES from ipam.models import IPAddress from virtualization.models import Cluster from tenancy.models import Tenant @@ -49,12 +48,6 @@ with file.open('r') as stream: params[assoc] = model.objects.get(**query) - if 'face' in params: - for rack_face in RACK_FACE_CHOICES: - if params['face'] in rack_face: - params['face'] = rack_face[0] - break - device, created = Device.objects.get_or_create(**params) if created: diff --git a/startup_scripts/210_vlans.py b/startup_scripts/210_vlans.py index e3a0ef1..ab6bd2b 100644 --- a/startup_scripts/210_vlans.py +++ b/startup_scripts/210_vlans.py @@ -1,6 +1,5 @@ from dcim.models import Site from ipam.models import VLAN, VLANGroup, Role -from ipam.constants import VLAN_STATUS_CHOICES from tenancy.models import Tenant, TenantGroup from extras.models import CustomField, CustomFieldValue from ruamel.yaml import YAML @@ -35,12 +34,6 @@ with file.open('r') as stream: params[assoc] = model.objects.get(**query) - if 'status' in params: - for vlan_status in VLAN_STATUS_CHOICES: - if params['status'] in vlan_status: - params['status'] = vlan_status[0] - break - vlan, created = VLAN.objects.get_or_create(**params) if created: diff --git a/startup_scripts/220_prefixes.py b/startup_scripts/220_prefixes.py index a832c88..d13578a 100644 --- a/startup_scripts/220_prefixes.py +++ b/startup_scripts/220_prefixes.py @@ -1,6 +1,5 @@ from dcim.models import Site from ipam.models import Prefix, VLAN, Role, VRF -from ipam.constants import PREFIX_STATUS_CHOICES from tenancy.models import Tenant, TenantGroup from extras.models import CustomField, CustomFieldValue from ruamel.yaml import YAML @@ -38,12 +37,6 @@ with file.open('r') as stream: params[assoc] = model.objects.get(**query) - if 'status' in params: - for prefix_status in PREFIX_STATUS_CHOICES: - if params['status'] in prefix_status: - params['status'] = prefix_status[0] - break - prefix, created = Prefix.objects.get_or_create(**params) if created: diff --git a/startup_scripts/230_virtual_machines.py b/startup_scripts/230_virtual_machines.py index 065b600..449df8a 100644 --- a/startup_scripts/230_virtual_machines.py +++ b/startup_scripts/230_virtual_machines.py @@ -1,6 +1,5 @@ from dcim.models import Site, Platform, DeviceRole from virtualization.models import Cluster, VirtualMachine -from virtualization.constants import VM_STATUS_CHOICES from tenancy.models import Tenant from extras.models import CustomField, CustomFieldValue from ruamel.yaml import YAML @@ -43,12 +42,6 @@ with file.open('r') as stream: params[assoc] = model.objects.get(**query) - if 'status' in params: - for vm_status in VM_STATUS_CHOICES: - if params['status'] in vm_status: - params['status'] = vm_status[0] - break - virtual_machine, created = VirtualMachine.objects.get_or_create(**params) if created: diff --git a/startup_scripts/250_dcim_interfaces.py b/startup_scripts/250_dcim_interfaces.py index ce7e7bd..ec30b5c 100644 --- a/startup_scripts/250_dcim_interfaces.py +++ b/startup_scripts/250_dcim_interfaces.py @@ -1,5 +1,4 @@ from dcim.models import Interface, Device -from dcim.constants import IFACE_TYPE_CHOICES from extras.models import CustomField, CustomFieldValue from ruamel.yaml import YAML @@ -28,16 +27,6 @@ with file.open('r') as stream: params[assoc] = model.objects.get(**query) - if 'type' in params: - for outer_list in IFACE_TYPE_CHOICES: - for type_choices in outer_list[1]: - if params['type'] in type_choices: - params['type'] = type_choices[0] - break - else: - continue - break - interface, created = Interface.objects.get_or_create(**params) if created: diff --git a/startup_scripts/260_ip_addresses.py b/startup_scripts/260_ip_addresses.py index f7f2bc7..d109a36 100644 --- a/startup_scripts/260_ip_addresses.py +++ b/startup_scripts/260_ip_addresses.py @@ -1,5 +1,4 @@ from ipam.models import IPAddress, VRF -from ipam.constants import IPADDRESS_STATUS_CHOICES from dcim.models import Device, Interface from virtualization.models import VirtualMachine from tenancy.models import Tenant @@ -49,12 +48,6 @@ with file.open('r') as stream: query = { field: params.pop(assoc) } params[assoc] = model.objects.get(**query) - if 'status' in params: - for ip_status in IPADDRESS_STATUS_CHOICES: - if params['status'] in ip_status: - params['status'] = ip_status[0] - break - ip_address, created = IPAddress.objects.get_or_create(**params) if created: