From a863690e1188e2cf5e1c9f2704044fba4fdf964a Mon Sep 17 00:00:00 2001 From: Michal Fiedorowicz Date: Fri, 9 Aug 2024 12:36:06 +0200 Subject: [PATCH 01/23] add pyproject.toml Signed-off-by: Michal Fiedorowicz --- pyproject.toml | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 pyproject.toml diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..a3ec3bb --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,60 @@ +[project] +name = "netboxlabs-netbox-branching" +version = "0.2.0" # Overwritten during the build process +description = "A git-like branching implementation for NetBox" +readme = "README.md" +requires-python = ">=3.10" +license = { text = "PolyForm Shield License 1.0.0" } +authors = [ + {name = "NetBox Labs", email = "support@netboxlabs.com" } +] +maintainers = [ + {name = "NetBox Labs", email = "support@netboxlabs.com" } +] + +classifiers = [ + "Development Status :: 4 - Beta", + "Intended Audience :: Developers", + "Topic :: Software Development :: Build Tools", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3 :: Only", + 'Programming Language :: Python :: 3.10', + 'Programming Language :: Python :: 3.11', + 'Programming Language :: Python :: 3.12', +] + +dependencies = [ + "Django", +] + +[project.optional-dependencies] +dev = ["black", "check-manifest", "ruff"] +test = ["coverage", "pytest", "pytest-cov"] + +[project.urls] +"Homepage" = "https://netboxlabs.com/" + +[project.scripts] + +[tool.setuptools] +packages = [ + "netbox_branching", +] +package-data = {"netbox_branching" = ["**/*", "templates/**"]} +exclude-package-data = {netbox_branching = ["tests/*"]} +license-files = ["LICENSE.md"] + +[build-system] +requires = ["setuptools>=43.0.0", "wheel"] +build-backend = "setuptools.build_meta" + +[tool.ruff] +line-length = 140 + +[tool.ruff.format] +quote-style = "double" +indent-style = "space" + +[tool.ruff.lint] +select = ["C", "D", "E", "F", "I", "R", "UP", "W"] +ignore = ["F401", "D203", "D212", "D400", "D401", "D404", "RET504"] From 982141545eb8b04963d63d862ed7713d1bd4ac04 Mon Sep 17 00:00:00 2001 From: Michal Fiedorowicz Date: Fri, 9 Aug 2024 12:38:42 +0200 Subject: [PATCH 02/23] add docker-compose setup based on NetBox v4.1-beta1-2.9.1 image with netbox_branching plugin installed Signed-off-by: Michal Fiedorowicz --- docker/configuration/configuration.py | 324 +++++++++++++++++++++++ docker/configuration/extra.py | 49 ++++ docker/configuration/ldap/extra.py | 28 ++ docker/configuration/ldap/ldap_config.py | 113 ++++++++ docker/configuration/local_settings.py | 12 + docker/configuration/logging.py | 55 ++++ docker/configuration/plugins.py | 7 + docker/docker-compose.yaml | 92 +++++++ docker/env/netbox.env | 38 +++ docker/env/postgres.env | 3 + docker/env/redis-cache.env | 1 + docker/env/redis.env | 1 + 12 files changed, 723 insertions(+) create mode 100644 docker/configuration/configuration.py create mode 100644 docker/configuration/extra.py create mode 100644 docker/configuration/ldap/extra.py create mode 100644 docker/configuration/ldap/ldap_config.py create mode 100644 docker/configuration/local_settings.py create mode 100644 docker/configuration/logging.py create mode 100644 docker/configuration/plugins.py create mode 100644 docker/docker-compose.yaml create mode 100644 docker/env/netbox.env create mode 100644 docker/env/postgres.env create mode 100644 docker/env/redis-cache.env create mode 100644 docker/env/redis.env diff --git a/docker/configuration/configuration.py b/docker/configuration/configuration.py new file mode 100644 index 0000000..cc51c59 --- /dev/null +++ b/docker/configuration/configuration.py @@ -0,0 +1,324 @@ +#### +## We recommend to not edit this file. +## Create separate files to overwrite the settings. +## See `extra.py` as an example. +#### + +import re +from os import environ +from os.path import abspath, dirname, join +from typing import Any, Callable + +# For reference see https://docs.netbox.dev/en/stable/configuration/ +# Based on https://github.com/netbox-community/netbox/blob/develop/netbox/netbox/configuration_example.py + +### +# NetBox-Docker Helper functions +### + +# Read secret from file +def _read_secret(secret_name: str, default: str | None = None) -> str | None: + try: + f = open('/run/secrets/' + secret_name, encoding='utf-8') + except OSError: + return default + else: + with f: + return f.readline().strip() + + +# If the `map_fn` isn't defined, then the value that is read from the environment (or the default value if not found) is returned. +# If the `map_fn` is defined, then `map_fn` is invoked and the value (that was read from the environment or the default value if not found) +# is passed to it as a parameter. The value returned from `map_fn` is then the return value of this function. +# The `map_fn` is not invoked, if the value (that was read from the environment or the default value if not found) is None. +def _environ_get_and_map(variable_name: str, default: str | None = None, + map_fn: Callable[[str], Any | None] = None) -> Any | None: + env_value = environ.get(variable_name, default) + + if env_value is None: + return env_value + + if not map_fn: + return env_value + + return map_fn(env_value) + + +_AS_BOOL = lambda value: value.lower() == 'true' +_AS_INT = lambda value: int(value) +_AS_LIST = lambda value: list(filter(None, value.split(' '))) + +_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(' ') +# ensure that '*' or 'localhost' is always in ALLOWED_HOSTS (needed for health checks) +if '*' not in ALLOWED_HOSTS and 'localhost' not in ALLOWED_HOSTS: + ALLOWED_HOSTS.append('localhost') + +# 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': _environ_get_and_map('DB_CONN_MAX_AGE', '300', _AS_INT), + # Max database connection age + 'DISABLE_SERVER_SIDE_CURSORS': _environ_get_and_map('DB_DISABLE_SERVER_SIDE_CURSORS', 'False', _AS_BOOL), + # Disable the use of server-side cursors transaction pooling +} + +# 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': _environ_get_and_map('REDIS_PORT', 6379, _AS_INT), + 'USERNAME': environ.get('REDIS_USERNAME', ''), + 'PASSWORD': _read_secret('redis_password', environ.get('REDIS_PASSWORD', '')), + 'DATABASE': _environ_get_and_map('REDIS_DATABASE', 0, _AS_INT), + 'SSL': _environ_get_and_map('REDIS_SSL', 'False', _AS_BOOL), + 'INSECURE_SKIP_TLS_VERIFY': _environ_get_and_map('REDIS_INSECURE_SKIP_TLS_VERIFY', 'False', _AS_BOOL), + }, + 'caching': { + 'HOST': environ.get('REDIS_CACHE_HOST', environ.get('REDIS_HOST', 'localhost')), + 'PORT': _environ_get_and_map('REDIS_CACHE_PORT', environ.get('REDIS_PORT', '6379'), _AS_INT), + 'USERNAME': environ.get('REDIS_CACHE_USERNAME', environ.get('REDIS_USERNAME', '')), + 'PASSWORD': _read_secret('redis_cache_password', + environ.get('REDIS_CACHE_PASSWORD', environ.get('REDIS_PASSWORD', ''))), + 'DATABASE': _environ_get_and_map('REDIS_CACHE_DATABASE', '1', _AS_INT), + 'SSL': _environ_get_and_map('REDIS_CACHE_SSL', environ.get('REDIS_SSL', 'False'), _AS_BOOL), + 'INSECURE_SKIP_TLS_VERIFY': _environ_get_and_map('REDIS_CACHE_INSECURE_SKIP_TLS_VERIFY', + environ.get('REDIS_INSECURE_SKIP_TLS_VERIFY', 'False'), + _AS_BOOL), + }, +} + +# 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'], +# ] + +if 'ALLOWED_URL_SCHEMES' in environ: + ALLOWED_URL_SCHEMES = _environ_get_and_map('ALLOWED_URL_SCHEMES', None, _AS_LIST) + +# 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. +if 'BANNER_TOP' in environ: + BANNER_TOP = environ.get('BANNER_TOP', None) +if 'BANNER_BOTTOM' in environ: + BANNER_BOTTOM = environ.get('BANNER_BOTTOM', None) + +# Text to include on the login page above the login form. HTML is allowed. +if 'BANNER_LOGIN' in environ: + BANNER_LOGIN = environ.get('BANNER_LOGIN', None) + +# Maximum number of days to retain logged changes. Set to 0 to retain changes indefinitely. (Default: 90) +if 'CHANGELOG_RETENTION' in environ: + CHANGELOG_RETENTION = _environ_get_and_map('CHANGELOG_RETENTION', None, _AS_INT) + +# Maximum number of days to retain job results (scripts and reports). Set to 0 to retain job results in the database indefinitely. (Default: 90) +if 'JOB_RETENTION' in environ: + JOB_RETENTION = _environ_get_and_map('JOB_RETENTION', None, _AS_INT) +# JOBRESULT_RETENTION was renamed to JOB_RETENTION in the v3.5.0 release of NetBox. For backwards compatibility, map JOBRESULT_RETENTION to JOB_RETENTION +elif 'JOBRESULT_RETENTION' in environ: + JOB_RETENTION = _environ_get_and_map('JOBRESULT_RETENTION', None, _AS_INT) + +# 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_and_map('CORS_ORIGIN_ALLOW_ALL', 'False', _AS_BOOL) +CORS_ORIGIN_WHITELIST = _environ_get_and_map('CORS_ORIGIN_WHITELIST', 'https://localhost', _AS_LIST) +CORS_ORIGIN_REGEX_WHITELIST = [re.compile(r) for r in _environ_get_and_map('CORS_ORIGIN_REGEX_WHITELIST', '', _AS_LIST)] + +# 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_and_map('DEBUG', 'False', _AS_BOOL) + +# This parameter serves as a safeguard to prevent some potentially dangerous behavior, +# such as generating new database schema migrations. +# Set this to True only if you are actively developing the NetBox code base. +DEVELOPER = _environ_get_and_map('DEVELOPER', 'False', _AS_BOOL) + +# Email settings +EMAIL = { + 'SERVER': environ.get('EMAIL_SERVER', 'localhost'), + 'PORT': _environ_get_and_map('EMAIL_PORT', 25, _AS_INT), + 'USERNAME': environ.get('EMAIL_USERNAME', ''), + 'PASSWORD': _read_secret('email_password', environ.get('EMAIL_PASSWORD', '')), + 'USE_SSL': _environ_get_and_map('EMAIL_USE_SSL', 'False', _AS_BOOL), + 'USE_TLS': _environ_get_and_map('EMAIL_USE_TLS', 'False', _AS_BOOL), + 'SSL_CERTFILE': environ.get('EMAIL_SSL_CERTFILE', ''), + 'SSL_KEYFILE': environ.get('EMAIL_SSL_KEYFILE', ''), + 'TIMEOUT': _environ_get_and_map('EMAIL_TIMEOUT', 10, _AS_INT), # 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. +if 'ENFORCE_GLOBAL_UNIQUE' in environ: + ENFORCE_GLOBAL_UNIQUE = _environ_get_and_map('ENFORCE_GLOBAL_UNIQUE', None, _AS_BOOL) + +# Exempt certain models from the enforcement of view permissions. Models listed here will be viewable by all users and +# by anonymous users. List models in the form `.`. Add '*' to this list to exempt all models. +EXEMPT_VIEW_PERMISSIONS = _environ_get_and_map('EXEMPT_VIEW_PERMISSIONS', '', _AS_LIST) + +# HTTP proxies NetBox should use when sending outbound HTTP requests (e.g. for webhooks). +# HTTP_PROXIES = { +# 'http': 'http://10.10.1.10:3128', +# 'https': 'http://10.10.1.10:1080', +# } + +# IP addresses recognized as internal to the system. The debugging toolbar will be available only to clients accessing +# NetBox from an internal IP. +INTERNAL_IPS = _environ_get_and_map('INTERNAL_IPS', '127.0.0.1 ::1', _AS_LIST) + +# Enable GraphQL API. +if 'GRAPHQL_ENABLED' in environ: + GRAPHQL_ENABLED = _environ_get_and_map('GRAPHQL_ENABLED', None, _AS_BOOL) + +# # Enable custom logging. Please see the Django documentation for detailed guidance on configuring custom logs: +# # https://docs.djangoproject.com/en/stable/topics/logging/ +# LOGGING = {} + +# Automatically reset the lifetime of a valid session upon each authenticated request. Enables users to remain +# authenticated to NetBox indefinitely. +LOGIN_PERSISTENCE = _environ_get_and_map('LOGIN_PERSISTENCE', 'False', _AS_BOOL) + +# 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_and_map('LOGIN_REQUIRED', 'False', _AS_BOOL) + +# 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_and_map('LOGIN_TIMEOUT', 1209600, _AS_INT) + +# Setting this to True will display a "maintenance mode" banner at the top of every page. +if 'MAINTENANCE_MODE' in environ: + MAINTENANCE_MODE = _environ_get_and_map('MAINTENANCE_MODE', None, _AS_BOOL) + +# Maps provider +if 'MAPS_URL' in environ: + MAPS_URL = environ.get('MAPS_URL', None) + +# 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". +if 'MAX_PAGE_SIZE' in environ: + MAX_PAGE_SIZE = _environ_get_and_map('MAX_PAGE_SIZE', None, _AS_INT) + +# 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_and_map('METRICS_ENABLED', 'False', _AS_BOOL) + +# Determine how many objects to display per page within a list. (Default: 50) +if 'PAGINATE_COUNT' in environ: + PAGINATE_COUNT = _environ_get_and_map('PAGINATE_COUNT', None, _AS_INT) + +# # 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. +if 'PREFER_IPV4' in environ: + PREFER_IPV4 = _environ_get_and_map('PREFER_IPV4', None, _AS_BOOL) + +# The default value for the amperage field when creating new power feeds. +if 'POWERFEED_DEFAULT_AMPERAGE' in environ: + POWERFEED_DEFAULT_AMPERAGE = _environ_get_and_map('POWERFEED_DEFAULT_AMPERAGE', None, _AS_INT) + +# The default value (percentage) for the max_utilization field when creating new power feeds. +if 'POWERFEED_DEFAULT_MAX_UTILIZATION' in environ: + POWERFEED_DEFAULT_MAX_UTILIZATION = _environ_get_and_map('POWERFEED_DEFAULT_MAX_UTILIZATION', None, _AS_INT) + +# The default value for the voltage field when creating new power feeds. +if 'POWERFEED_DEFAULT_VOLTAGE' in environ: + POWERFEED_DEFAULT_VOLTAGE = _environ_get_and_map('POWERFEED_DEFAULT_VOLTAGE', None, _AS_INT) + +# Rack elevation size defaults, in pixels. For best results, the ratio of width to height should be roughly 10:1. +if 'RACK_ELEVATION_DEFAULT_UNIT_HEIGHT' in environ: + RACK_ELEVATION_DEFAULT_UNIT_HEIGHT = _environ_get_and_map('RACK_ELEVATION_DEFAULT_UNIT_HEIGHT', None, _AS_INT) +if 'RACK_ELEVATION_DEFAULT_UNIT_WIDTH' in environ: + RACK_ELEVATION_DEFAULT_UNIT_WIDTH = _environ_get_and_map('RACK_ELEVATION_DEFAULT_UNIT_WIDTH', None, _AS_INT) + +# Remote authentication support +REMOTE_AUTH_ENABLED = _environ_get_and_map('REMOTE_AUTH_ENABLED', 'False', _AS_BOOL) +REMOTE_AUTH_BACKEND = _environ_get_and_map('REMOTE_AUTH_BACKEND', 'netbox.authentication.RemoteUserBackend', _AS_LIST) +REMOTE_AUTH_HEADER = environ.get('REMOTE_AUTH_HEADER', 'HTTP_REMOTE_USER') +REMOTE_AUTH_AUTO_CREATE_USER = _environ_get_and_map('REMOTE_AUTH_AUTO_CREATE_USER', 'False', _AS_BOOL) +REMOTE_AUTH_DEFAULT_GROUPS = _environ_get_and_map('REMOTE_AUTH_DEFAULT_GROUPS', '', _AS_LIST) +# REMOTE_AUTH_DEFAULT_PERMISSIONS = {} + +# 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. +RELEASE_CHECK_URL = environ.get('RELEASE_CHECK_URL', None) +# RELEASE_CHECK_URL = 'https://api.github.com/repos/netbox-community/netbox/releases' + +# Maximum execution time for background tasks, in seconds. +RQ_DEFAULT_TIMEOUT = _environ_get_and_map('RQ_DEFAULT_TIMEOUT', 300, _AS_INT) + +# The name to use for the csrf token cookie. +CSRF_COOKIE_NAME = environ.get('CSRF_COOKIE_NAME', 'csrftoken') + +# Cross-Site-Request-Forgery-Attack settings. If Netbox is sitting behind a reverse proxy, you might need to set the CSRF_TRUSTED_ORIGINS flag. +# Django 4.0 requires to specify the URL Scheme in this setting. An example environment variable could be specified like: +# CSRF_TRUSTED_ORIGINS=https://demo.netbox.dev http://demo.netbox.dev +CSRF_TRUSTED_ORIGINS = _environ_get_and_map('CSRF_TRUSTED_ORIGINS', '', _AS_LIST) + +# The name to use for the session cookie. +SESSION_COOKIE_NAME = environ.get('SESSION_COOKIE_NAME', 'sessionid') + +# 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('SESSION_FILE_PATH', environ.get('SESSIONS_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') +BASE_PATH = environ.get('BASE_PATH', '') diff --git a/docker/configuration/extra.py b/docker/configuration/extra.py new file mode 100644 index 0000000..8bd1337 --- /dev/null +++ b/docker/configuration/extra.py @@ -0,0 +1,49 @@ +#### +## 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', +# ) + +## 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'This instance started on {now}.' diff --git a/docker/configuration/ldap/extra.py b/docker/configuration/ldap/extra.py new file mode 100644 index 0000000..4505197 --- /dev/null +++ b/docker/configuration/ldap/extra.py @@ -0,0 +1,28 @@ +#### +## This file contains extra configuration options that can't be configured +## directly through environment variables. +## All vairables set here overwrite any existing found in ldap_config.py +#### + +# # This Python script inherits all the imports from ldap_config.py +# from django_auth_ldap.config import LDAPGroupQuery # Imported since not in ldap_config.py + +# # Sets a base requirement of membetship to netbox-user-ro, netbox-user-rw, or netbox-user-admin. +# AUTH_LDAP_REQUIRE_GROUP = ( +# LDAPGroupQuery("cn=netbox-user-ro,ou=groups,dc=example,dc=com") +# | LDAPGroupQuery("cn=netbox-user-rw,ou=groups,dc=example,dc=com") +# | LDAPGroupQuery("cn=netbox-user-admin,ou=groups,dc=example,dc=com") +# ) + +# # Sets LDAP Flag groups variables with example. +# AUTH_LDAP_USER_FLAGS_BY_GROUP = { +# "is_staff": ( +# LDAPGroupQuery("cn=netbox-user-ro,ou=groups,dc=example,dc=com") +# | LDAPGroupQuery("cn=netbox-user-rw,ou=groups,dc=example,dc=com") +# | LDAPGroupQuery("cn=netbox-user-admin,ou=groups,dc=example,dc=com") +# ), +# "is_superuser": "cn=netbox-user-admin,ou=groups,dc=example,dc=com", +# } + +# # Sets LDAP Mirror groups variables with example groups +# AUTH_LDAP_MIRROR_GROUPS = ["netbox-user-ro", "netbox-user-rw", "netbox-user-admin"] diff --git a/docker/configuration/ldap/ldap_config.py b/docker/configuration/ldap/ldap_config.py new file mode 100644 index 0000000..32743c7 --- /dev/null +++ b/docker/configuration/ldap/ldap_config.py @@ -0,0 +1,113 @@ +from importlib import import_module +from os import environ + +import ldap +from django_auth_ldap.config import LDAPSearch + + +# Read secret from file +def _read_secret(secret_name, default=None): + try: + f = open('/run/secrets/' + secret_name, encoding='utf-8') + except OSError: + 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 +} + +AUTH_LDAP_BIND_AS_AUTHENTICATING_USER = environ.get('AUTH_LDAP_BIND_AS_AUTHENTICATING_USER', 'False').lower() == 'true' + +# Set the DN and password for the NetBox service account if needed. +if not AUTH_LDAP_BIND_AS_AUTHENTICATING_USER: + 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' + +# Include this setting if you want to validate the LDAP server certificates against a CA certificate directory on your server +# Note that this is a NetBox-specific setting which sets: +# ldap.set_option(ldap.OPT_X_TLS_CACERTDIR, LDAP_CA_CERT_DIR) +LDAP_CA_CERT_DIR = environ.get('LDAP_CA_CERT_DIR', None) + +# Include this setting if you want to validate the LDAP server certificates against your own CA. +# Note that this is a NetBox-specific setting which sets: +# ldap.set_option(ldap.OPT_X_TLS_CACERTFILE, LDAP_CA_CERT_FILE) +LDAP_CA_CERT_FILE = environ.get('LDAP_CA_CERT_FILE', None) + +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_FILTER: str = environ.get( + 'AUTH_LDAP_USER_SEARCH_FILTER', f'({AUTH_LDAP_USER_SEARCH_ATTR}=%(user)s)' +) + +AUTH_LDAP_USER_SEARCH = LDAPSearch( + AUTH_LDAP_USER_SEARCH_BASEDN, ldap.SCOPE_SUBTREE, AUTH_LDAP_USER_SEARCH_FILTER +) + +# 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_FILTER: str = environ.get( + 'AUTH_LDAP_GROUP_SEARCH_FILTER', f'(objectclass={AUTH_LDAP_GROUP_SEARCH_CLASS})' +) +AUTH_LDAP_GROUP_SEARCH = LDAPSearch( + AUTH_LDAP_GROUP_SEARCH_BASEDN, ldap.SCOPE_SUBTREE, AUTH_LDAP_GROUP_SEARCH_FILTER +) +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 = {} + +if AUTH_LDAP_REQUIRE_GROUP is not None: + 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') +} diff --git a/docker/configuration/local_settings.py b/docker/configuration/local_settings.py new file mode 100644 index 0000000..cacc0b7 --- /dev/null +++ b/docker/configuration/local_settings.py @@ -0,0 +1,12 @@ +from netbox_branching.utilities import DynamicSchemaDict +from netbox.configuration.configuration import DATABASE + +# Wrap DATABASES with DynamicSchemaDict for dynamic schema support +DATABASES = DynamicSchemaDict({ + 'default': DATABASE, +}) + +# Employ our custom database router +DATABASE_ROUTERS = [ + 'netbox_branching.database.BranchAwareRouter', +] diff --git a/docker/configuration/logging.py b/docker/configuration/logging.py new file mode 100644 index 0000000..d786768 --- /dev/null +++ b/docker/configuration/logging.py @@ -0,0 +1,55 @@ +# # Remove first comment(#) on each line to implement this working logging example. +# # Add LOGLEVEL environment variable to netbox if you use this example & want a different log level. +# from os import environ + +# # Set LOGLEVEL in netbox.env or docker-compose.overide.yml to override a logging level of INFO. +# LOGLEVEL = environ.get('LOGLEVEL', 'INFO') + +# LOGGING = { + +# 'version': 1, +# 'disable_existing_loggers': False, +# 'formatters': { +# 'verbose': { +# 'format': '{levelname} {asctime} {module} {process:d} {thread:d} {message}', +# 'style': '{', +# }, +# 'simple': { +# 'format': '{levelname} {message}', +# 'style': '{', +# }, +# }, +# 'filters': { +# 'require_debug_false': { +# '()': 'django.utils.log.RequireDebugFalse', +# }, +# }, +# 'handlers': { +# 'console': { +# 'level': LOGLEVEL, +# 'filters': ['require_debug_false'], +# 'class': 'logging.StreamHandler', +# 'formatter': 'simple' +# }, +# 'mail_admins': { +# 'level': 'ERROR', +# 'class': 'django.utils.log.AdminEmailHandler', +# 'filters': ['require_debug_false'] +# } +# }, +# 'loggers': { +# 'django': { +# 'handlers': ['console'], +# 'propagate': True, +# }, +# 'django.request': { +# 'handlers': ['mail_admins'], +# 'level': 'ERROR', +# 'propagate': False, +# }, +# 'django_auth_ldap': { +# 'handlers': ['console',], +# 'level': LOGLEVEL, +# } +# } +# } diff --git a/docker/configuration/plugins.py b/docker/configuration/plugins.py new file mode 100644 index 0000000..adba7c4 --- /dev/null +++ b/docker/configuration/plugins.py @@ -0,0 +1,7 @@ +# Add your plugins and plugin settings here. +# Of course uncomment this file out. + +# To learn how to build images with your required plugins +# See https://github.com/netbox-community/netbox-docker/wiki/Using-Netbox-Plugins + +PLUGINS = ["netbox_branching"] diff --git a/docker/docker-compose.yaml b/docker/docker-compose.yaml new file mode 100644 index 0000000..d31a224 --- /dev/null +++ b/docker/docker-compose.yaml @@ -0,0 +1,92 @@ +name: netbox-branching +services: + netbox: &netbox + image: netboxcommunity/netbox:v4.1-beta1-2.9.1 + depends_on: + - postgres + - redis + - redis-cache + env_file: env/netbox.env + user: 'unit:root' + healthcheck: + start_period: 60s + timeout: 3s + interval: 15s + test: "curl -f http://localhost:8080/login/ || exit 1" + ports: + - "8000:8080" + volumes: + - ./configuration:/etc/netbox/config:z,ro + - ../netbox_branching:/opt/netbox/netbox/netbox_branching:ro + - netbox-media-files:/opt/netbox/netbox/media:rw + - netbox-reports-files:/opt/netbox/netbox/reports:rw + - netbox-scripts-files:/opt/netbox/netbox/scripts:rw + netbox-worker: + <<: *netbox + depends_on: + netbox: + condition: service_healthy + command: + - /opt/netbox/venv/bin/python + - /opt/netbox/netbox/manage.py + - rqworker + healthcheck: + start_period: 20s + timeout: 3s + interval: 15s + test: "ps -aux | grep -v grep | grep -q rqworker || exit 1" + ports: [] + netbox-housekeeping: + <<: *netbox + depends_on: + netbox: + condition: service_healthy + command: + - /opt/netbox/housekeeping.sh + healthcheck: + start_period: 20s + timeout: 3s + interval: 15s + test: "ps -aux | grep -v grep | grep -q housekeeping || exit 1" + ports: [] + + # postgres + postgres: + image: docker.io/postgres:16-alpine + env_file: env/postgres.env + volumes: + - netbox-postgres-data:/var/lib/postgresql/data + + # redis + redis: + image: docker.io/redis:7-alpine + command: + - sh + - -c # this is to evaluate the $REDIS_PASSWORD from the env + - redis-server --appendonly yes --requirepass $$REDIS_PASSWORD ## $$ because of docker-compose + env_file: env/redis.env + volumes: + - netbox-redis-data:/data + redis-cache: + image: docker.io/redis:7-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-cache.env + volumes: + - netbox-redis-cache-data:/data + +volumes: + netbox-media-files: + driver: local + netbox-postgres-data: + driver: local + netbox-redis-cache-data: + driver: local + netbox-redis-data: + driver: local + netbox-reports-files: + driver: local + netbox-scripts-files: + driver: local \ No newline at end of file diff --git a/docker/env/netbox.env b/docker/env/netbox.env new file mode 100644 index 0000000..607c1bb --- /dev/null +++ b/docker/env/netbox.env @@ -0,0 +1,38 @@ +CORS_ORIGIN_ALLOW_ALL=True +DB_HOST=postgres +DB_NAME=netbox +DB_PASSWORD=J5brHrAXFLQSif0K +DB_USER=netbox +EMAIL_FROM=netbox@bar.com +EMAIL_PASSWORD= +EMAIL_PORT=25 +EMAIL_SERVER=localhost +EMAIL_SSL_CERTFILE= +EMAIL_SSL_KEYFILE= +EMAIL_TIMEOUT=5 +EMAIL_USERNAME=netbox +# 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 +GRAPHQL_ENABLED=true +HOUSEKEEPING_INTERVAL=86400 +MEDIA_ROOT=/opt/netbox/netbox/media +METRICS_ENABLED=false +REDIS_CACHE_DATABASE=1 +REDIS_CACHE_HOST=redis-cache +REDIS_CACHE_INSECURE_SKIP_TLS_VERIFY=false +REDIS_CACHE_PASSWORD=t4Ph722qJ5QHeQ1qfu36 +REDIS_CACHE_SSL=false +REDIS_DATABASE=0 +REDIS_HOST=redis +REDIS_INSECURE_SKIP_TLS_VERIFY=false +REDIS_PASSWORD=H733Kdjndks81 +REDIS_SSL=false +RELEASE_CHECK_URL=https://api.github.com/repos/netbox-community/netbox/releases +SECRET_KEY='r(m)9nLGnz$(_q3N4z1k(EFsMCjjjzx08x9VhNVcfd%6RF#r!6DE@+V5Zk2X' +SKIP_SUPERUSER=false +SUPERUSER_API_TOKEN= +SUPERUSER_EMAIL= +SUPERUSER_NAME=admin +SUPERUSER_PASSWORD=admin +WEBHOOKS_ENABLED=true diff --git a/docker/env/postgres.env b/docker/env/postgres.env new file mode 100644 index 0000000..bb7b53c --- /dev/null +++ b/docker/env/postgres.env @@ -0,0 +1,3 @@ +POSTGRES_DB=netbox +POSTGRES_PASSWORD=J5brHrAXFLQSif0K +POSTGRES_USER=netbox diff --git a/docker/env/redis-cache.env b/docker/env/redis-cache.env new file mode 100644 index 0000000..6285c33 --- /dev/null +++ b/docker/env/redis-cache.env @@ -0,0 +1 @@ +REDIS_PASSWORD=t4Ph722qJ5QHeQ1qfu36 diff --git a/docker/env/redis.env b/docker/env/redis.env new file mode 100644 index 0000000..44a1987 --- /dev/null +++ b/docker/env/redis.env @@ -0,0 +1 @@ +REDIS_PASSWORD=H733Kdjndks81 From 8b1ee6ba2b8f272691b3f483a648d77e2e52bdca Mon Sep 17 00:00:00 2001 From: Michal Fiedorowicz Date: Fri, 9 Aug 2024 12:39:14 +0200 Subject: [PATCH 03/23] add Makefile recipes for docker compose Signed-off-by: Michal Fiedorowicz --- Makefile | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 Makefile diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..a5cdadb --- /dev/null +++ b/Makefile @@ -0,0 +1,18 @@ +ifneq ($(shell docker compose version 2>/dev/null),) + DOCKER_COMPOSE := docker compose +else + DOCKER_COMPOSE := docker-compose +endif + +.PHONY: docker-compose-up +docker-compose-up: + @$(DOCKER_COMPOSE) -f docker/docker-compose.yaml up -d + +.PHONY: docker-compose-down +docker-compose-down: + @$(DOCKER_COMPOSE) -f docker/docker-compose.yaml down + +.PHONY: docker-compose-test +docker-compose-test: + -@$(DOCKER_COMPOSE) -f docker/docker-compose.yaml run -u root --rm netbox ./manage.py test --keepdb netbox_branching + @$(MAKE) docker-compose-down From c8a2e3d121ea5350f1429c6c289bbbdad45594fa Mon Sep 17 00:00:00 2001 From: Michal Fiedorowicz Date: Fri, 9 Aug 2024 12:40:10 +0200 Subject: [PATCH 04/23] add GHA workflow to run lint and test Signed-off-by: Michal Fiedorowicz --- .github/lint-tests.yml | 44 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 .github/lint-tests.yml diff --git a/.github/lint-tests.yml b/.github/lint-tests.yml new file mode 100644 index 0000000..537be43 --- /dev/null +++ b/.github/lint-tests.yml @@ -0,0 +1,44 @@ +name: Lint and tests +on: + workflow_dispatch: + pull_request: + push: + branches: + - "!release" + +concurrency: + group: ${{ github.workflow }} + cancel-in-progress: false + +permissions: + contents: write + checks: write + pull-requests: write + +jobs: + tests: + runs-on: ubuntu-latest + timeout-minutes: 10 + strategy: + matrix: + python: [ "3.10" ] + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python }} + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install . + pip install .[dev] + pip install .[test] + - name: Lint with Ruff + run: | + ruff check --output-format=github netbox_branching/ + continue-on-error: true + - name: Test + run: | + make docker-compose-test From bbc62c3ab6e0739d1da12947c2ca9cec103ccb68 Mon Sep 17 00:00:00 2001 From: Michal Fiedorowicz Date: Fri, 9 Aug 2024 12:42:24 +0200 Subject: [PATCH 05/23] tidy up docker-compose.yaml Signed-off-by: Michal Fiedorowicz --- docker/docker-compose.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/docker-compose.yaml b/docker/docker-compose.yaml index d31a224..dd5ff0f 100644 --- a/docker/docker-compose.yaml +++ b/docker/docker-compose.yaml @@ -89,4 +89,4 @@ volumes: netbox-reports-files: driver: local netbox-scripts-files: - driver: local \ No newline at end of file + driver: local From d9113946ef83e4217a787408aa57c09822f18969 Mon Sep 17 00:00:00 2001 From: Michal Fiedorowicz Date: Fri, 9 Aug 2024 12:51:23 +0200 Subject: [PATCH 06/23] move workflow into correct directory Signed-off-by: Michal Fiedorowicz --- .github/{ => workflows}/lint-tests.yml | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/{ => workflows}/lint-tests.yml (100%) diff --git a/.github/lint-tests.yml b/.github/workflows/lint-tests.yml similarity index 100% rename from .github/lint-tests.yml rename to .github/workflows/lint-tests.yml From 0a2f8404a71a7f352c85e223b94f82c7ec621fa8 Mon Sep 17 00:00:00 2001 From: Michal Fiedorowicz Date: Fri, 9 Aug 2024 15:18:24 +0200 Subject: [PATCH 07/23] fix mounting of local_settings.py Signed-off-by: Michal Fiedorowicz --- docker/docker-compose.yaml | 1 + docker/{configuration => }/local_settings.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) rename docker/{configuration => }/local_settings.py (84%) diff --git a/docker/docker-compose.yaml b/docker/docker-compose.yaml index dd5ff0f..16fc4be 100644 --- a/docker/docker-compose.yaml +++ b/docker/docker-compose.yaml @@ -17,6 +17,7 @@ services: - "8000:8080" volumes: - ./configuration:/etc/netbox/config:z,ro + - ./local_settings.py:/opt/netbox/netbox/netbox/local_settings.py:z,ro - ../netbox_branching:/opt/netbox/netbox/netbox_branching:ro - netbox-media-files:/opt/netbox/netbox/media:rw - netbox-reports-files:/opt/netbox/netbox/reports:rw diff --git a/docker/configuration/local_settings.py b/docker/local_settings.py similarity index 84% rename from docker/configuration/local_settings.py rename to docker/local_settings.py index cacc0b7..10de74b 100644 --- a/docker/configuration/local_settings.py +++ b/docker/local_settings.py @@ -1,5 +1,5 @@ from netbox_branching.utilities import DynamicSchemaDict -from netbox.configuration.configuration import DATABASE +from .configuration import DATABASE # Wrap DATABASES with DynamicSchemaDict for dynamic schema support DATABASES = DynamicSchemaDict({ From d94c7b822cd78c6bf3615e6a5704bc2b10b650da Mon Sep 17 00:00:00 2001 From: Michal Fiedorowicz Date: Fri, 9 Aug 2024 15:27:09 +0200 Subject: [PATCH 08/23] ignore missing docstrings checks Signed-off-by: Michal Fiedorowicz --- pyproject.toml | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index a3ec3bb..0892843 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,10 +6,10 @@ readme = "README.md" requires-python = ">=3.10" license = { text = "PolyForm Shield License 1.0.0" } authors = [ - {name = "NetBox Labs", email = "support@netboxlabs.com" } + { name = "NetBox Labs", email = "support@netboxlabs.com" } ] maintainers = [ - {name = "NetBox Labs", email = "support@netboxlabs.com" } + { name = "NetBox Labs", email = "support@netboxlabs.com" } ] classifiers = [ @@ -40,8 +40,8 @@ test = ["coverage", "pytest", "pytest-cov"] packages = [ "netbox_branching", ] -package-data = {"netbox_branching" = ["**/*", "templates/**"]} -exclude-package-data = {netbox_branching = ["tests/*"]} +package-data = { "netbox_branching" = ["**/*", "templates/**"] } +exclude-package-data = { netbox_branching = ["tests/*"] } license-files = ["LICENSE.md"] [build-system] @@ -57,4 +57,19 @@ indent-style = "space" [tool.ruff.lint] select = ["C", "D", "E", "F", "I", "R", "UP", "W"] -ignore = ["F401", "D203", "D212", "D400", "D401", "D404", "RET504"] +ignore = [ + "F401", + "D203", + "D212", + "D400", + "D401", + "D404", + "RET504", + "D100", + "D101", + "D102", + "D104", + "D105", + "D106", + "D107" +] From 8404909745b0e690e5e61046fb8ac76935e66f10 Mon Sep 17 00:00:00 2001 From: Michal Fiedorowicz Date: Fri, 9 Aug 2024 15:54:45 +0200 Subject: [PATCH 09/23] add step for building documentation Signed-off-by: Michal Fiedorowicz --- .github/workflows/lint-tests.yml | 5 +++-- pyproject.toml | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/lint-tests.yml b/.github/workflows/lint-tests.yml index 537be43..30bf8d9 100644 --- a/.github/workflows/lint-tests.yml +++ b/.github/workflows/lint-tests.yml @@ -35,10 +35,11 @@ jobs: pip install . pip install .[dev] pip install .[test] + - name: Build documentation + run: mkdocs build - name: Lint with Ruff run: | ruff check --output-format=github netbox_branching/ continue-on-error: true - name: Test - run: | - make docker-compose-test + run: make docker-compose-test diff --git a/pyproject.toml b/pyproject.toml index 0892843..ac2fb53 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -28,7 +28,7 @@ dependencies = [ ] [project.optional-dependencies] -dev = ["black", "check-manifest", "ruff"] +dev = ["black", "check-manifest", "ruff", "mkdocs", "mkdocs-material"] test = ["coverage", "pytest", "pytest-cov"] [project.urls] From d3346aa554a847af3bdf95e663cfd3320cbc922a Mon Sep 17 00:00:00 2001 From: Michal Fiedorowicz Date: Fri, 9 Aug 2024 17:05:24 +0200 Subject: [PATCH 10/23] catch make docker-compose-test exit code (test) Signed-off-by: Michal Fiedorowicz --- .github/workflows/lint-tests.yml | 2 +- Makefile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/lint-tests.yml b/.github/workflows/lint-tests.yml index 30bf8d9..fa17257 100644 --- a/.github/workflows/lint-tests.yml +++ b/.github/workflows/lint-tests.yml @@ -42,4 +42,4 @@ jobs: ruff check --output-format=github netbox_branching/ continue-on-error: true - name: Test - run: make docker-compose-test + run: make docker-compose-test || true diff --git a/Makefile b/Makefile index a5cdadb..a05a322 100644 --- a/Makefile +++ b/Makefile @@ -14,5 +14,5 @@ docker-compose-down: .PHONY: docker-compose-test docker-compose-test: - -@$(DOCKER_COMPOSE) -f docker/docker-compose.yaml run -u root --rm netbox ./manage.py test --keepdb netbox_branching + @$(DOCKER_COMPOSE) -f docker/docker-compose.yaml run -u root --rm netbox ./manage.py test --keepdb netbox_branchinga @$(MAKE) docker-compose-down From e8ac7c82ff54607565ab13b4993d0928b8c72ed7 Mon Sep 17 00:00:00 2001 From: Michal Fiedorowicz Date: Fri, 9 Aug 2024 17:19:46 +0200 Subject: [PATCH 11/23] catch make docker-compose-test exit code (test 2) Signed-off-by: Michal Fiedorowicz --- .github/workflows/lint-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/lint-tests.yml b/.github/workflows/lint-tests.yml index fa17257..30bf8d9 100644 --- a/.github/workflows/lint-tests.yml +++ b/.github/workflows/lint-tests.yml @@ -42,4 +42,4 @@ jobs: ruff check --output-format=github netbox_branching/ continue-on-error: true - name: Test - run: make docker-compose-test || true + run: make docker-compose-test From c2fadb6b48fd873e8fbb1cd29c1bb70a8985b20c Mon Sep 17 00:00:00 2001 From: Michal Fiedorowicz Date: Fri, 9 Aug 2024 17:22:31 +0200 Subject: [PATCH 12/23] tidy up make docker-compose-test Signed-off-by: Michal Fiedorowicz --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index a05a322..89048d0 100644 --- a/Makefile +++ b/Makefile @@ -14,5 +14,5 @@ docker-compose-down: .PHONY: docker-compose-test docker-compose-test: - @$(DOCKER_COMPOSE) -f docker/docker-compose.yaml run -u root --rm netbox ./manage.py test --keepdb netbox_branchinga + @$(DOCKER_COMPOSE) -f docker/docker-compose.yaml run -u root --rm netbox ./manage.py test --keepdb netbox_branching @$(MAKE) docker-compose-down From 3134545281e283627c8f7d1c4adadc14b3d16c22 Mon Sep 17 00:00:00 2001 From: Michal Fiedorowicz Date: Fri, 9 Aug 2024 17:28:29 +0200 Subject: [PATCH 13/23] rename GHA job Signed-off-by: Michal Fiedorowicz --- .github/workflows/lint-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/lint-tests.yml b/.github/workflows/lint-tests.yml index 30bf8d9..3f47950 100644 --- a/.github/workflows/lint-tests.yml +++ b/.github/workflows/lint-tests.yml @@ -16,7 +16,7 @@ permissions: pull-requests: write jobs: - tests: + lint-tests: runs-on: ubuntu-latest timeout-minutes: 10 strategy: From 31c6e87eebb8667836295a7b98feaf5f8fd7532f Mon Sep 17 00:00:00 2001 From: Michal Fiedorowicz Date: Fri, 9 Aug 2024 17:45:30 +0200 Subject: [PATCH 14/23] ignore all missing docstrings Signed-off-by: Michal Fiedorowicz --- pyproject.toml | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index ac2fb53..0c5dd39 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -65,11 +65,5 @@ ignore = [ "D401", "D404", "RET504", - "D100", - "D101", - "D102", - "D104", - "D105", - "D106", - "D107" + "D1" ] From 4751e8a5107dffc8ef6ada56ad5436185c998a83 Mon Sep 17 00:00:00 2001 From: Michal Fiedorowicz Date: Fri, 9 Aug 2024 20:25:46 +0200 Subject: [PATCH 15/23] change workflow file ext Signed-off-by: Michal Fiedorowicz --- .github/workflows/{lint-tests.yml => lint-tests.yaml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/workflows/{lint-tests.yml => lint-tests.yaml} (100%) diff --git a/.github/workflows/lint-tests.yml b/.github/workflows/lint-tests.yaml similarity index 100% rename from .github/workflows/lint-tests.yml rename to .github/workflows/lint-tests.yaml From 3b60250be2a18f020aa2ae798ea074b363ce8fc9 Mon Sep 17 00:00:00 2001 From: Michal Fiedorowicz Date: Mon, 19 Aug 2024 21:22:41 +0200 Subject: [PATCH 16/23] run tests with more native way with matrix of python versions Signed-off-by: Michal Fiedorowicz --- .github/workflows/lint-tests.yaml | 66 ++++- Makefile | 18 -- docker/configuration/configuration.py | 324 ----------------------- docker/configuration/extra.py | 49 ---- docker/configuration/ldap/extra.py | 28 -- docker/configuration/ldap/ldap_config.py | 113 -------- docker/configuration/logging.py | 55 ---- docker/configuration/plugins.py | 7 - docker/docker-compose.yaml | 93 ------- docker/env/netbox.env | 38 --- docker/env/postgres.env | 3 - docker/env/redis-cache.env | 1 - docker/env/redis.env | 1 - testing/configuration.py | 38 +++ {docker => testing}/local_settings.py | 0 15 files changed, 97 insertions(+), 737 deletions(-) delete mode 100644 Makefile delete mode 100644 docker/configuration/configuration.py delete mode 100644 docker/configuration/extra.py delete mode 100644 docker/configuration/ldap/extra.py delete mode 100644 docker/configuration/ldap/ldap_config.py delete mode 100644 docker/configuration/logging.py delete mode 100644 docker/configuration/plugins.py delete mode 100644 docker/docker-compose.yaml delete mode 100644 docker/env/netbox.env delete mode 100644 docker/env/postgres.env delete mode 100644 docker/env/redis-cache.env delete mode 100644 docker/env/redis.env create mode 100644 testing/configuration.py rename {docker => testing}/local_settings.py (100%) diff --git a/.github/workflows/lint-tests.yaml b/.github/workflows/lint-tests.yaml index 3f47950..8569267 100644 --- a/.github/workflows/lint-tests.yaml +++ b/.github/workflows/lint-tests.yaml @@ -16,19 +16,16 @@ permissions: pull-requests: write jobs: - lint-tests: + lint: runs-on: ubuntu-latest timeout-minutes: 10 - strategy: - matrix: - python: [ "3.10" ] steps: - name: Checkout uses: actions/checkout@v4 - name: Setup Python uses: actions/setup-python@v5 with: - python-version: ${{ matrix.python }} + python-version: "3.10" - name: Install dependencies run: | python -m pip install --upgrade pip @@ -41,5 +38,60 @@ jobs: run: | ruff check --output-format=github netbox_branching/ continue-on-error: true - - name: Test - run: make docker-compose-test + tests: + runs-on: ubuntu-latest + timeout-minutes: 10 + strategy: + matrix: + python-version: [ "3.10" ] + services: + redis: + image: redis + ports: + - 6379:6379 + postgres: + image: postgres + env: + POSTGRES_USER: netbox + POSTGRES_PASSWORD: netbox + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + ports: + - 5432:5432 + + steps: + - name: Checkout netbox-branching + uses: actions/checkout@v4 + with: + path: netbox-branching + - name: Setup Python ${{ matrix.python }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python }} + - name: Checkout netbox + uses: actions/checkout@v4 + with: + repository: "netbox-community/netbox" + path: netbox + ref: v4.1-beta1 + - name: Install netbox-branching + working-directory: netbox-branching + run: | + python -m pip install --upgrade pip + pip install . + pip install .[test] + - name: Install dependencies & configure plugin + working-directory: netbox + run: | + ln -s $(pwd)/../netbox-branching/testing/configuration.py netbox/netbox/configuration.py + ln -s $(pwd)/../netbox-branching/testing/local_settings.py netbox/netbox/local_settings.py + + python -m pip install --upgrade pip + pip install -r requirements.txt -U + - name: Run tests + working-directory: netbox + run: | + python netbox/manage.py test netbox_branching.tests diff --git a/Makefile b/Makefile deleted file mode 100644 index 89048d0..0000000 --- a/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -ifneq ($(shell docker compose version 2>/dev/null),) - DOCKER_COMPOSE := docker compose -else - DOCKER_COMPOSE := docker-compose -endif - -.PHONY: docker-compose-up -docker-compose-up: - @$(DOCKER_COMPOSE) -f docker/docker-compose.yaml up -d - -.PHONY: docker-compose-down -docker-compose-down: - @$(DOCKER_COMPOSE) -f docker/docker-compose.yaml down - -.PHONY: docker-compose-test -docker-compose-test: - @$(DOCKER_COMPOSE) -f docker/docker-compose.yaml run -u root --rm netbox ./manage.py test --keepdb netbox_branching - @$(MAKE) docker-compose-down diff --git a/docker/configuration/configuration.py b/docker/configuration/configuration.py deleted file mode 100644 index cc51c59..0000000 --- a/docker/configuration/configuration.py +++ /dev/null @@ -1,324 +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 import environ -from os.path import abspath, dirname, join -from typing import Any, Callable - -# For reference see https://docs.netbox.dev/en/stable/configuration/ -# Based on https://github.com/netbox-community/netbox/blob/develop/netbox/netbox/configuration_example.py - -### -# NetBox-Docker Helper functions -### - -# Read secret from file -def _read_secret(secret_name: str, default: str | None = None) -> str | None: - try: - f = open('/run/secrets/' + secret_name, encoding='utf-8') - except OSError: - return default - else: - with f: - return f.readline().strip() - - -# If the `map_fn` isn't defined, then the value that is read from the environment (or the default value if not found) is returned. -# If the `map_fn` is defined, then `map_fn` is invoked and the value (that was read from the environment or the default value if not found) -# is passed to it as a parameter. The value returned from `map_fn` is then the return value of this function. -# The `map_fn` is not invoked, if the value (that was read from the environment or the default value if not found) is None. -def _environ_get_and_map(variable_name: str, default: str | None = None, - map_fn: Callable[[str], Any | None] = None) -> Any | None: - env_value = environ.get(variable_name, default) - - if env_value is None: - return env_value - - if not map_fn: - return env_value - - return map_fn(env_value) - - -_AS_BOOL = lambda value: value.lower() == 'true' -_AS_INT = lambda value: int(value) -_AS_LIST = lambda value: list(filter(None, value.split(' '))) - -_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(' ') -# ensure that '*' or 'localhost' is always in ALLOWED_HOSTS (needed for health checks) -if '*' not in ALLOWED_HOSTS and 'localhost' not in ALLOWED_HOSTS: - ALLOWED_HOSTS.append('localhost') - -# 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': _environ_get_and_map('DB_CONN_MAX_AGE', '300', _AS_INT), - # Max database connection age - 'DISABLE_SERVER_SIDE_CURSORS': _environ_get_and_map('DB_DISABLE_SERVER_SIDE_CURSORS', 'False', _AS_BOOL), - # Disable the use of server-side cursors transaction pooling -} - -# 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': _environ_get_and_map('REDIS_PORT', 6379, _AS_INT), - 'USERNAME': environ.get('REDIS_USERNAME', ''), - 'PASSWORD': _read_secret('redis_password', environ.get('REDIS_PASSWORD', '')), - 'DATABASE': _environ_get_and_map('REDIS_DATABASE', 0, _AS_INT), - 'SSL': _environ_get_and_map('REDIS_SSL', 'False', _AS_BOOL), - 'INSECURE_SKIP_TLS_VERIFY': _environ_get_and_map('REDIS_INSECURE_SKIP_TLS_VERIFY', 'False', _AS_BOOL), - }, - 'caching': { - 'HOST': environ.get('REDIS_CACHE_HOST', environ.get('REDIS_HOST', 'localhost')), - 'PORT': _environ_get_and_map('REDIS_CACHE_PORT', environ.get('REDIS_PORT', '6379'), _AS_INT), - 'USERNAME': environ.get('REDIS_CACHE_USERNAME', environ.get('REDIS_USERNAME', '')), - 'PASSWORD': _read_secret('redis_cache_password', - environ.get('REDIS_CACHE_PASSWORD', environ.get('REDIS_PASSWORD', ''))), - 'DATABASE': _environ_get_and_map('REDIS_CACHE_DATABASE', '1', _AS_INT), - 'SSL': _environ_get_and_map('REDIS_CACHE_SSL', environ.get('REDIS_SSL', 'False'), _AS_BOOL), - 'INSECURE_SKIP_TLS_VERIFY': _environ_get_and_map('REDIS_CACHE_INSECURE_SKIP_TLS_VERIFY', - environ.get('REDIS_INSECURE_SKIP_TLS_VERIFY', 'False'), - _AS_BOOL), - }, -} - -# 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'], -# ] - -if 'ALLOWED_URL_SCHEMES' in environ: - ALLOWED_URL_SCHEMES = _environ_get_and_map('ALLOWED_URL_SCHEMES', None, _AS_LIST) - -# 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. -if 'BANNER_TOP' in environ: - BANNER_TOP = environ.get('BANNER_TOP', None) -if 'BANNER_BOTTOM' in environ: - BANNER_BOTTOM = environ.get('BANNER_BOTTOM', None) - -# Text to include on the login page above the login form. HTML is allowed. -if 'BANNER_LOGIN' in environ: - BANNER_LOGIN = environ.get('BANNER_LOGIN', None) - -# Maximum number of days to retain logged changes. Set to 0 to retain changes indefinitely. (Default: 90) -if 'CHANGELOG_RETENTION' in environ: - CHANGELOG_RETENTION = _environ_get_and_map('CHANGELOG_RETENTION', None, _AS_INT) - -# Maximum number of days to retain job results (scripts and reports). Set to 0 to retain job results in the database indefinitely. (Default: 90) -if 'JOB_RETENTION' in environ: - JOB_RETENTION = _environ_get_and_map('JOB_RETENTION', None, _AS_INT) -# JOBRESULT_RETENTION was renamed to JOB_RETENTION in the v3.5.0 release of NetBox. For backwards compatibility, map JOBRESULT_RETENTION to JOB_RETENTION -elif 'JOBRESULT_RETENTION' in environ: - JOB_RETENTION = _environ_get_and_map('JOBRESULT_RETENTION', None, _AS_INT) - -# 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_and_map('CORS_ORIGIN_ALLOW_ALL', 'False', _AS_BOOL) -CORS_ORIGIN_WHITELIST = _environ_get_and_map('CORS_ORIGIN_WHITELIST', 'https://localhost', _AS_LIST) -CORS_ORIGIN_REGEX_WHITELIST = [re.compile(r) for r in _environ_get_and_map('CORS_ORIGIN_REGEX_WHITELIST', '', _AS_LIST)] - -# 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_and_map('DEBUG', 'False', _AS_BOOL) - -# This parameter serves as a safeguard to prevent some potentially dangerous behavior, -# such as generating new database schema migrations. -# Set this to True only if you are actively developing the NetBox code base. -DEVELOPER = _environ_get_and_map('DEVELOPER', 'False', _AS_BOOL) - -# Email settings -EMAIL = { - 'SERVER': environ.get('EMAIL_SERVER', 'localhost'), - 'PORT': _environ_get_and_map('EMAIL_PORT', 25, _AS_INT), - 'USERNAME': environ.get('EMAIL_USERNAME', ''), - 'PASSWORD': _read_secret('email_password', environ.get('EMAIL_PASSWORD', '')), - 'USE_SSL': _environ_get_and_map('EMAIL_USE_SSL', 'False', _AS_BOOL), - 'USE_TLS': _environ_get_and_map('EMAIL_USE_TLS', 'False', _AS_BOOL), - 'SSL_CERTFILE': environ.get('EMAIL_SSL_CERTFILE', ''), - 'SSL_KEYFILE': environ.get('EMAIL_SSL_KEYFILE', ''), - 'TIMEOUT': _environ_get_and_map('EMAIL_TIMEOUT', 10, _AS_INT), # 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. -if 'ENFORCE_GLOBAL_UNIQUE' in environ: - ENFORCE_GLOBAL_UNIQUE = _environ_get_and_map('ENFORCE_GLOBAL_UNIQUE', None, _AS_BOOL) - -# Exempt certain models from the enforcement of view permissions. Models listed here will be viewable by all users and -# by anonymous users. List models in the form `.`. Add '*' to this list to exempt all models. -EXEMPT_VIEW_PERMISSIONS = _environ_get_and_map('EXEMPT_VIEW_PERMISSIONS', '', _AS_LIST) - -# HTTP proxies NetBox should use when sending outbound HTTP requests (e.g. for webhooks). -# HTTP_PROXIES = { -# 'http': 'http://10.10.1.10:3128', -# 'https': 'http://10.10.1.10:1080', -# } - -# IP addresses recognized as internal to the system. The debugging toolbar will be available only to clients accessing -# NetBox from an internal IP. -INTERNAL_IPS = _environ_get_and_map('INTERNAL_IPS', '127.0.0.1 ::1', _AS_LIST) - -# Enable GraphQL API. -if 'GRAPHQL_ENABLED' in environ: - GRAPHQL_ENABLED = _environ_get_and_map('GRAPHQL_ENABLED', None, _AS_BOOL) - -# # Enable custom logging. Please see the Django documentation for detailed guidance on configuring custom logs: -# # https://docs.djangoproject.com/en/stable/topics/logging/ -# LOGGING = {} - -# Automatically reset the lifetime of a valid session upon each authenticated request. Enables users to remain -# authenticated to NetBox indefinitely. -LOGIN_PERSISTENCE = _environ_get_and_map('LOGIN_PERSISTENCE', 'False', _AS_BOOL) - -# 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_and_map('LOGIN_REQUIRED', 'False', _AS_BOOL) - -# 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_and_map('LOGIN_TIMEOUT', 1209600, _AS_INT) - -# Setting this to True will display a "maintenance mode" banner at the top of every page. -if 'MAINTENANCE_MODE' in environ: - MAINTENANCE_MODE = _environ_get_and_map('MAINTENANCE_MODE', None, _AS_BOOL) - -# Maps provider -if 'MAPS_URL' in environ: - MAPS_URL = environ.get('MAPS_URL', None) - -# 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". -if 'MAX_PAGE_SIZE' in environ: - MAX_PAGE_SIZE = _environ_get_and_map('MAX_PAGE_SIZE', None, _AS_INT) - -# 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_and_map('METRICS_ENABLED', 'False', _AS_BOOL) - -# Determine how many objects to display per page within a list. (Default: 50) -if 'PAGINATE_COUNT' in environ: - PAGINATE_COUNT = _environ_get_and_map('PAGINATE_COUNT', None, _AS_INT) - -# # 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. -if 'PREFER_IPV4' in environ: - PREFER_IPV4 = _environ_get_and_map('PREFER_IPV4', None, _AS_BOOL) - -# The default value for the amperage field when creating new power feeds. -if 'POWERFEED_DEFAULT_AMPERAGE' in environ: - POWERFEED_DEFAULT_AMPERAGE = _environ_get_and_map('POWERFEED_DEFAULT_AMPERAGE', None, _AS_INT) - -# The default value (percentage) for the max_utilization field when creating new power feeds. -if 'POWERFEED_DEFAULT_MAX_UTILIZATION' in environ: - POWERFEED_DEFAULT_MAX_UTILIZATION = _environ_get_and_map('POWERFEED_DEFAULT_MAX_UTILIZATION', None, _AS_INT) - -# The default value for the voltage field when creating new power feeds. -if 'POWERFEED_DEFAULT_VOLTAGE' in environ: - POWERFEED_DEFAULT_VOLTAGE = _environ_get_and_map('POWERFEED_DEFAULT_VOLTAGE', None, _AS_INT) - -# Rack elevation size defaults, in pixels. For best results, the ratio of width to height should be roughly 10:1. -if 'RACK_ELEVATION_DEFAULT_UNIT_HEIGHT' in environ: - RACK_ELEVATION_DEFAULT_UNIT_HEIGHT = _environ_get_and_map('RACK_ELEVATION_DEFAULT_UNIT_HEIGHT', None, _AS_INT) -if 'RACK_ELEVATION_DEFAULT_UNIT_WIDTH' in environ: - RACK_ELEVATION_DEFAULT_UNIT_WIDTH = _environ_get_and_map('RACK_ELEVATION_DEFAULT_UNIT_WIDTH', None, _AS_INT) - -# Remote authentication support -REMOTE_AUTH_ENABLED = _environ_get_and_map('REMOTE_AUTH_ENABLED', 'False', _AS_BOOL) -REMOTE_AUTH_BACKEND = _environ_get_and_map('REMOTE_AUTH_BACKEND', 'netbox.authentication.RemoteUserBackend', _AS_LIST) -REMOTE_AUTH_HEADER = environ.get('REMOTE_AUTH_HEADER', 'HTTP_REMOTE_USER') -REMOTE_AUTH_AUTO_CREATE_USER = _environ_get_and_map('REMOTE_AUTH_AUTO_CREATE_USER', 'False', _AS_BOOL) -REMOTE_AUTH_DEFAULT_GROUPS = _environ_get_and_map('REMOTE_AUTH_DEFAULT_GROUPS', '', _AS_LIST) -# REMOTE_AUTH_DEFAULT_PERMISSIONS = {} - -# 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. -RELEASE_CHECK_URL = environ.get('RELEASE_CHECK_URL', None) -# RELEASE_CHECK_URL = 'https://api.github.com/repos/netbox-community/netbox/releases' - -# Maximum execution time for background tasks, in seconds. -RQ_DEFAULT_TIMEOUT = _environ_get_and_map('RQ_DEFAULT_TIMEOUT', 300, _AS_INT) - -# The name to use for the csrf token cookie. -CSRF_COOKIE_NAME = environ.get('CSRF_COOKIE_NAME', 'csrftoken') - -# Cross-Site-Request-Forgery-Attack settings. If Netbox is sitting behind a reverse proxy, you might need to set the CSRF_TRUSTED_ORIGINS flag. -# Django 4.0 requires to specify the URL Scheme in this setting. An example environment variable could be specified like: -# CSRF_TRUSTED_ORIGINS=https://demo.netbox.dev http://demo.netbox.dev -CSRF_TRUSTED_ORIGINS = _environ_get_and_map('CSRF_TRUSTED_ORIGINS', '', _AS_LIST) - -# The name to use for the session cookie. -SESSION_COOKIE_NAME = environ.get('SESSION_COOKIE_NAME', 'sessionid') - -# 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('SESSION_FILE_PATH', environ.get('SESSIONS_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') -BASE_PATH = environ.get('BASE_PATH', '') diff --git a/docker/configuration/extra.py b/docker/configuration/extra.py deleted file mode 100644 index 8bd1337..0000000 --- a/docker/configuration/extra.py +++ /dev/null @@ -1,49 +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', -# ) - -## 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'This instance started on {now}.' diff --git a/docker/configuration/ldap/extra.py b/docker/configuration/ldap/extra.py deleted file mode 100644 index 4505197..0000000 --- a/docker/configuration/ldap/extra.py +++ /dev/null @@ -1,28 +0,0 @@ -#### -## This file contains extra configuration options that can't be configured -## directly through environment variables. -## All vairables set here overwrite any existing found in ldap_config.py -#### - -# # This Python script inherits all the imports from ldap_config.py -# from django_auth_ldap.config import LDAPGroupQuery # Imported since not in ldap_config.py - -# # Sets a base requirement of membetship to netbox-user-ro, netbox-user-rw, or netbox-user-admin. -# AUTH_LDAP_REQUIRE_GROUP = ( -# LDAPGroupQuery("cn=netbox-user-ro,ou=groups,dc=example,dc=com") -# | LDAPGroupQuery("cn=netbox-user-rw,ou=groups,dc=example,dc=com") -# | LDAPGroupQuery("cn=netbox-user-admin,ou=groups,dc=example,dc=com") -# ) - -# # Sets LDAP Flag groups variables with example. -# AUTH_LDAP_USER_FLAGS_BY_GROUP = { -# "is_staff": ( -# LDAPGroupQuery("cn=netbox-user-ro,ou=groups,dc=example,dc=com") -# | LDAPGroupQuery("cn=netbox-user-rw,ou=groups,dc=example,dc=com") -# | LDAPGroupQuery("cn=netbox-user-admin,ou=groups,dc=example,dc=com") -# ), -# "is_superuser": "cn=netbox-user-admin,ou=groups,dc=example,dc=com", -# } - -# # Sets LDAP Mirror groups variables with example groups -# AUTH_LDAP_MIRROR_GROUPS = ["netbox-user-ro", "netbox-user-rw", "netbox-user-admin"] diff --git a/docker/configuration/ldap/ldap_config.py b/docker/configuration/ldap/ldap_config.py deleted file mode 100644 index 32743c7..0000000 --- a/docker/configuration/ldap/ldap_config.py +++ /dev/null @@ -1,113 +0,0 @@ -from importlib import import_module -from os import environ - -import ldap -from django_auth_ldap.config import LDAPSearch - - -# Read secret from file -def _read_secret(secret_name, default=None): - try: - f = open('/run/secrets/' + secret_name, encoding='utf-8') - except OSError: - 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 -} - -AUTH_LDAP_BIND_AS_AUTHENTICATING_USER = environ.get('AUTH_LDAP_BIND_AS_AUTHENTICATING_USER', 'False').lower() == 'true' - -# Set the DN and password for the NetBox service account if needed. -if not AUTH_LDAP_BIND_AS_AUTHENTICATING_USER: - 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' - -# Include this setting if you want to validate the LDAP server certificates against a CA certificate directory on your server -# Note that this is a NetBox-specific setting which sets: -# ldap.set_option(ldap.OPT_X_TLS_CACERTDIR, LDAP_CA_CERT_DIR) -LDAP_CA_CERT_DIR = environ.get('LDAP_CA_CERT_DIR', None) - -# Include this setting if you want to validate the LDAP server certificates against your own CA. -# Note that this is a NetBox-specific setting which sets: -# ldap.set_option(ldap.OPT_X_TLS_CACERTFILE, LDAP_CA_CERT_FILE) -LDAP_CA_CERT_FILE = environ.get('LDAP_CA_CERT_FILE', None) - -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_FILTER: str = environ.get( - 'AUTH_LDAP_USER_SEARCH_FILTER', f'({AUTH_LDAP_USER_SEARCH_ATTR}=%(user)s)' -) - -AUTH_LDAP_USER_SEARCH = LDAPSearch( - AUTH_LDAP_USER_SEARCH_BASEDN, ldap.SCOPE_SUBTREE, AUTH_LDAP_USER_SEARCH_FILTER -) - -# 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_FILTER: str = environ.get( - 'AUTH_LDAP_GROUP_SEARCH_FILTER', f'(objectclass={AUTH_LDAP_GROUP_SEARCH_CLASS})' -) -AUTH_LDAP_GROUP_SEARCH = LDAPSearch( - AUTH_LDAP_GROUP_SEARCH_BASEDN, ldap.SCOPE_SUBTREE, AUTH_LDAP_GROUP_SEARCH_FILTER -) -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 = {} - -if AUTH_LDAP_REQUIRE_GROUP is not None: - 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') -} diff --git a/docker/configuration/logging.py b/docker/configuration/logging.py deleted file mode 100644 index d786768..0000000 --- a/docker/configuration/logging.py +++ /dev/null @@ -1,55 +0,0 @@ -# # Remove first comment(#) on each line to implement this working logging example. -# # Add LOGLEVEL environment variable to netbox if you use this example & want a different log level. -# from os import environ - -# # Set LOGLEVEL in netbox.env or docker-compose.overide.yml to override a logging level of INFO. -# LOGLEVEL = environ.get('LOGLEVEL', 'INFO') - -# LOGGING = { - -# 'version': 1, -# 'disable_existing_loggers': False, -# 'formatters': { -# 'verbose': { -# 'format': '{levelname} {asctime} {module} {process:d} {thread:d} {message}', -# 'style': '{', -# }, -# 'simple': { -# 'format': '{levelname} {message}', -# 'style': '{', -# }, -# }, -# 'filters': { -# 'require_debug_false': { -# '()': 'django.utils.log.RequireDebugFalse', -# }, -# }, -# 'handlers': { -# 'console': { -# 'level': LOGLEVEL, -# 'filters': ['require_debug_false'], -# 'class': 'logging.StreamHandler', -# 'formatter': 'simple' -# }, -# 'mail_admins': { -# 'level': 'ERROR', -# 'class': 'django.utils.log.AdminEmailHandler', -# 'filters': ['require_debug_false'] -# } -# }, -# 'loggers': { -# 'django': { -# 'handlers': ['console'], -# 'propagate': True, -# }, -# 'django.request': { -# 'handlers': ['mail_admins'], -# 'level': 'ERROR', -# 'propagate': False, -# }, -# 'django_auth_ldap': { -# 'handlers': ['console',], -# 'level': LOGLEVEL, -# } -# } -# } diff --git a/docker/configuration/plugins.py b/docker/configuration/plugins.py deleted file mode 100644 index adba7c4..0000000 --- a/docker/configuration/plugins.py +++ /dev/null @@ -1,7 +0,0 @@ -# Add your plugins and plugin settings here. -# Of course uncomment this file out. - -# To learn how to build images with your required plugins -# See https://github.com/netbox-community/netbox-docker/wiki/Using-Netbox-Plugins - -PLUGINS = ["netbox_branching"] diff --git a/docker/docker-compose.yaml b/docker/docker-compose.yaml deleted file mode 100644 index 16fc4be..0000000 --- a/docker/docker-compose.yaml +++ /dev/null @@ -1,93 +0,0 @@ -name: netbox-branching -services: - netbox: &netbox - image: netboxcommunity/netbox:v4.1-beta1-2.9.1 - depends_on: - - postgres - - redis - - redis-cache - env_file: env/netbox.env - user: 'unit:root' - healthcheck: - start_period: 60s - timeout: 3s - interval: 15s - test: "curl -f http://localhost:8080/login/ || exit 1" - ports: - - "8000:8080" - volumes: - - ./configuration:/etc/netbox/config:z,ro - - ./local_settings.py:/opt/netbox/netbox/netbox/local_settings.py:z,ro - - ../netbox_branching:/opt/netbox/netbox/netbox_branching:ro - - netbox-media-files:/opt/netbox/netbox/media:rw - - netbox-reports-files:/opt/netbox/netbox/reports:rw - - netbox-scripts-files:/opt/netbox/netbox/scripts:rw - netbox-worker: - <<: *netbox - depends_on: - netbox: - condition: service_healthy - command: - - /opt/netbox/venv/bin/python - - /opt/netbox/netbox/manage.py - - rqworker - healthcheck: - start_period: 20s - timeout: 3s - interval: 15s - test: "ps -aux | grep -v grep | grep -q rqworker || exit 1" - ports: [] - netbox-housekeeping: - <<: *netbox - depends_on: - netbox: - condition: service_healthy - command: - - /opt/netbox/housekeeping.sh - healthcheck: - start_period: 20s - timeout: 3s - interval: 15s - test: "ps -aux | grep -v grep | grep -q housekeeping || exit 1" - ports: [] - - # postgres - postgres: - image: docker.io/postgres:16-alpine - env_file: env/postgres.env - volumes: - - netbox-postgres-data:/var/lib/postgresql/data - - # redis - redis: - image: docker.io/redis:7-alpine - command: - - sh - - -c # this is to evaluate the $REDIS_PASSWORD from the env - - redis-server --appendonly yes --requirepass $$REDIS_PASSWORD ## $$ because of docker-compose - env_file: env/redis.env - volumes: - - netbox-redis-data:/data - redis-cache: - image: docker.io/redis:7-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-cache.env - volumes: - - netbox-redis-cache-data:/data - -volumes: - netbox-media-files: - driver: local - netbox-postgres-data: - driver: local - netbox-redis-cache-data: - driver: local - netbox-redis-data: - driver: local - netbox-reports-files: - driver: local - netbox-scripts-files: - driver: local diff --git a/docker/env/netbox.env b/docker/env/netbox.env deleted file mode 100644 index 607c1bb..0000000 --- a/docker/env/netbox.env +++ /dev/null @@ -1,38 +0,0 @@ -CORS_ORIGIN_ALLOW_ALL=True -DB_HOST=postgres -DB_NAME=netbox -DB_PASSWORD=J5brHrAXFLQSif0K -DB_USER=netbox -EMAIL_FROM=netbox@bar.com -EMAIL_PASSWORD= -EMAIL_PORT=25 -EMAIL_SERVER=localhost -EMAIL_SSL_CERTFILE= -EMAIL_SSL_KEYFILE= -EMAIL_TIMEOUT=5 -EMAIL_USERNAME=netbox -# 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 -GRAPHQL_ENABLED=true -HOUSEKEEPING_INTERVAL=86400 -MEDIA_ROOT=/opt/netbox/netbox/media -METRICS_ENABLED=false -REDIS_CACHE_DATABASE=1 -REDIS_CACHE_HOST=redis-cache -REDIS_CACHE_INSECURE_SKIP_TLS_VERIFY=false -REDIS_CACHE_PASSWORD=t4Ph722qJ5QHeQ1qfu36 -REDIS_CACHE_SSL=false -REDIS_DATABASE=0 -REDIS_HOST=redis -REDIS_INSECURE_SKIP_TLS_VERIFY=false -REDIS_PASSWORD=H733Kdjndks81 -REDIS_SSL=false -RELEASE_CHECK_URL=https://api.github.com/repos/netbox-community/netbox/releases -SECRET_KEY='r(m)9nLGnz$(_q3N4z1k(EFsMCjjjzx08x9VhNVcfd%6RF#r!6DE@+V5Zk2X' -SKIP_SUPERUSER=false -SUPERUSER_API_TOKEN= -SUPERUSER_EMAIL= -SUPERUSER_NAME=admin -SUPERUSER_PASSWORD=admin -WEBHOOKS_ENABLED=true diff --git a/docker/env/postgres.env b/docker/env/postgres.env deleted file mode 100644 index bb7b53c..0000000 --- a/docker/env/postgres.env +++ /dev/null @@ -1,3 +0,0 @@ -POSTGRES_DB=netbox -POSTGRES_PASSWORD=J5brHrAXFLQSif0K -POSTGRES_USER=netbox diff --git a/docker/env/redis-cache.env b/docker/env/redis-cache.env deleted file mode 100644 index 6285c33..0000000 --- a/docker/env/redis-cache.env +++ /dev/null @@ -1 +0,0 @@ -REDIS_PASSWORD=t4Ph722qJ5QHeQ1qfu36 diff --git a/docker/env/redis.env b/docker/env/redis.env deleted file mode 100644 index 44a1987..0000000 --- a/docker/env/redis.env +++ /dev/null @@ -1 +0,0 @@ -REDIS_PASSWORD=H733Kdjndks81 diff --git a/testing/configuration.py b/testing/configuration.py new file mode 100644 index 0000000..2721e48 --- /dev/null +++ b/testing/configuration.py @@ -0,0 +1,38 @@ +################################################################### +# This file serves as a base configuration for testing purposes # +# only. It is not intended for production use. # +################################################################### + +ALLOWED_HOSTS = ["*"] + +DATABASE = { + "NAME": "netbox", + "USER": "netbox", + "PASSWORD": "netbox", + "HOST": "localhost", + "PORT": "", + "CONN_MAX_AGE": 300, +} + +PLUGINS = [ + "netbox_branching", +] + +REDIS = { + "tasks": { + "HOST": "localhost", + "PORT": 6379, + "PASSWORD": "", + "DATABASE": 0, + "SSL": False, + }, + "caching": { + "HOST": "localhost", + "PORT": 6379, + "PASSWORD": "", + "DATABASE": 1, + "SSL": False, + }, +} + +SECRET_KEY = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" diff --git a/docker/local_settings.py b/testing/local_settings.py similarity index 100% rename from docker/local_settings.py rename to testing/local_settings.py From 111a641f71cfb05d11c818e561f26f43e2df11c0 Mon Sep 17 00:00:00 2001 From: Michal Fiedorowicz Date: Mon, 19 Aug 2024 21:26:54 +0200 Subject: [PATCH 17/23] fix matrix with python version Signed-off-by: Michal Fiedorowicz --- .github/workflows/lint-tests.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/lint-tests.yaml b/.github/workflows/lint-tests.yaml index 8569267..beb184c 100644 --- a/.github/workflows/lint-tests.yaml +++ b/.github/workflows/lint-tests.yaml @@ -67,10 +67,10 @@ jobs: uses: actions/checkout@v4 with: path: netbox-branching - - name: Setup Python ${{ matrix.python }} + - name: Setup Python ${{ matrix.python-version }} uses: actions/setup-python@v5 with: - python-version: ${{ matrix.python }} + python-version: ${{ matrix.python-version }} - name: Checkout netbox uses: actions/checkout@v4 with: From 8632f4a451d3318efd573e295aa2efcd0cdd8398 Mon Sep 17 00:00:00 2001 From: Michal Fiedorowicz Date: Mon, 19 Aug 2024 21:29:51 +0200 Subject: [PATCH 18/23] fix test command for plugin Signed-off-by: Michal Fiedorowicz --- .github/workflows/lint-tests.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/lint-tests.yaml b/.github/workflows/lint-tests.yaml index beb184c..a1ecbf9 100644 --- a/.github/workflows/lint-tests.yaml +++ b/.github/workflows/lint-tests.yaml @@ -94,4 +94,4 @@ jobs: - name: Run tests working-directory: netbox run: | - python netbox/manage.py test netbox_branching.tests + python netbox/manage.py test netbox_branching From 114304fb8e8564cfe2d13ca8d35c791c02f52251 Mon Sep 17 00:00:00 2001 From: Michal Fiedorowicz Date: Mon, 19 Aug 2024 21:36:05 +0200 Subject: [PATCH 19/23] list tests Signed-off-by: Michal Fiedorowicz --- .github/workflows/lint-tests.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/lint-tests.yaml b/.github/workflows/lint-tests.yaml index a1ecbf9..962d692 100644 --- a/.github/workflows/lint-tests.yaml +++ b/.github/workflows/lint-tests.yaml @@ -83,6 +83,7 @@ jobs: python -m pip install --upgrade pip pip install . pip install .[test] + ls -alt tests - name: Install dependencies & configure plugin working-directory: netbox run: | From ec39e30cff5a87a906b22cc92918e02007d314f4 Mon Sep 17 00:00:00 2001 From: Michal Fiedorowicz Date: Mon, 19 Aug 2024 21:38:20 +0200 Subject: [PATCH 20/23] comment out exclude-package-data from pyproject.toml Signed-off-by: Michal Fiedorowicz --- .github/workflows/lint-tests.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/lint-tests.yaml b/.github/workflows/lint-tests.yaml index 962d692..c83a332 100644 --- a/.github/workflows/lint-tests.yaml +++ b/.github/workflows/lint-tests.yaml @@ -80,6 +80,9 @@ jobs: - name: Install netbox-branching working-directory: netbox-branching run: | + # include tests directory for test + sed -i 's/exclude-package-data/#exclude-package-data/g' pyproject.toml + python -m pip install --upgrade pip pip install . pip install .[test] From 99c7a9a772fc8be52a542dc93567fe14fac7abdb Mon Sep 17 00:00:00 2001 From: Michal Fiedorowicz Date: Mon, 19 Aug 2024 21:39:56 +0200 Subject: [PATCH 21/23] tidy up Signed-off-by: Michal Fiedorowicz --- .github/workflows/lint-tests.yaml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/lint-tests.yaml b/.github/workflows/lint-tests.yaml index c83a332..b24380a 100644 --- a/.github/workflows/lint-tests.yaml +++ b/.github/workflows/lint-tests.yaml @@ -86,7 +86,6 @@ jobs: python -m pip install --upgrade pip pip install . pip install .[test] - ls -alt tests - name: Install dependencies & configure plugin working-directory: netbox run: | @@ -98,4 +97,4 @@ jobs: - name: Run tests working-directory: netbox run: | - python netbox/manage.py test netbox_branching + python netbox/manage.py test netbox_branching.tests From 3c558a4d7007311ad60e0bdbc26654c9d8538f9e Mon Sep 17 00:00:00 2001 From: Michal Fiedorowicz Date: Mon, 19 Aug 2024 21:46:53 +0200 Subject: [PATCH 22/23] keep db when running tests Signed-off-by: Michal Fiedorowicz --- .github/workflows/lint-tests.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/lint-tests.yaml b/.github/workflows/lint-tests.yaml index b24380a..0888d0d 100644 --- a/.github/workflows/lint-tests.yaml +++ b/.github/workflows/lint-tests.yaml @@ -43,7 +43,7 @@ jobs: timeout-minutes: 10 strategy: matrix: - python-version: [ "3.10" ] + python-version: [ "3.10", "3.11", "3.12" ] services: redis: image: redis @@ -97,4 +97,4 @@ jobs: - name: Run tests working-directory: netbox run: | - python netbox/manage.py test netbox_branching.tests + python netbox/manage.py test netbox_branching.tests --keepdb From ee9bed5e959b357480498eafbf2600a50ecce3e7 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Wed, 4 Sep 2024 08:26:51 -0400 Subject: [PATCH 23/23] Remove v4.1-beta1 tag --- .github/workflows/lint-tests.yaml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/lint-tests.yaml b/.github/workflows/lint-tests.yaml index 0888d0d..fcedae3 100644 --- a/.github/workflows/lint-tests.yaml +++ b/.github/workflows/lint-tests.yaml @@ -61,7 +61,6 @@ jobs: --health-retries 5 ports: - 5432:5432 - steps: - name: Checkout netbox-branching uses: actions/checkout@v4 @@ -76,13 +75,11 @@ jobs: with: repository: "netbox-community/netbox" path: netbox - ref: v4.1-beta1 - name: Install netbox-branching working-directory: netbox-branching run: | - # include tests directory for test + # Include tests directory for test sed -i 's/exclude-package-data/#exclude-package-data/g' pyproject.toml - python -m pip install --upgrade pip pip install . pip install .[test]