diff --git a/.devcontainer/.bashrc b/.devcontainer/.bashrc new file mode 100644 index 0000000..168d37a --- /dev/null +++ b/.devcontainer/.bashrc @@ -0,0 +1,104 @@ +# If you come from bash you might have to change your $PATH. +# export PATH=$HOME/bin:/usr/local/bin:$PATH + +# Path to your oh-my-zsh installation. +export ZSH="$HOME/.oh-my-zsh" + +# Set name of the theme to load --- if set to "random", it will +# load a random theme each time oh-my-zsh is loaded, in which case, +# to know which specific one was loaded, run: echo $RANDOM_THEME +# See https://github.com/ohmyzsh/ohmyzsh/wiki/Themes +ZSH_THEME="robbyrussell" + +# Set list of themes to pick from when loading at random +# Setting this variable when ZSH_THEME=random will cause zsh to load +# a theme from this variable instead of looking in $ZSH/themes/ +# If set to an empty array, this variable will have no effect. +# ZSH_THEME_RANDOM_CANDIDATES=( "robbyrussell" "agnoster" ) + +# Uncomment the following line to use case-sensitive completion. +# CASE_SENSITIVE="true" + +# Uncomment the following line to use hyphen-insensitive completion. +# Case-sensitive completion must be off. _ and - will be interchangeable. +# HYPHEN_INSENSITIVE="true" + +# Uncomment one of the following lines to change the auto-update behavior +# zstyle ':omz:update' mode disabled # disable automatic updates +# zstyle ':omz:update' mode auto # update automatically without asking +# zstyle ':omz:update' mode reminder # just remind me to update when it's time + +# Uncomment the following line to change how often to auto-update (in days). +# zstyle ':omz:update' frequency 13 + +# Uncomment the following line if pasting URLs and other text is messed up. +# DISABLE_MAGIC_FUNCTIONS="true" + +# Uncomment the following line to disable colors in ls. +# DISABLE_LS_COLORS="true" + +# Uncomment the following line to disable auto-setting terminal title. +# DISABLE_AUTO_TITLE="true" + +# Uncomment the following line to enable command auto-correction. +# ENABLE_CORRECTION="true" + +# Uncomment the following line to display red dots whilst waiting for completion. +# You can also set it to another string to have that shown instead of the default red dots. +# e.g. COMPLETION_WAITING_DOTS="%F{yellow}waiting...%f" +# Caution: this setting can cause issues with multiline prompts in zsh < 5.7.1 (see #5765) +# COMPLETION_WAITING_DOTS="true" + +# Uncomment the following line if you want to disable marking untracked files +# under VCS as dirty. This makes repository status check for large repositories +# much, much faster. +# DISABLE_UNTRACKED_FILES_DIRTY="true" + +# Uncomment the following line if you want to change the command execution time +# stamp shown in the history command output. +# You can set one of the optional three formats: +# "mm/dd/yyyy"|"dd.mm.yyyy"|"yyyy-mm-dd" +# or set a custom format using the strftime function format specifications, +# see 'man strftime' for details. +# HIST_STAMPS="mm/dd/yyyy" + +# Would you like to use another custom folder than $ZSH/custom? +# ZSH_CUSTOM=/path/to/new-custom-folder + +# Which plugins would you like to load? +# Standard plugins can be found in $ZSH/plugins/ +# Custom plugins may be added to $ZSH_CUSTOM/plugins/ +# Example format: plugins=(rails git textmate ruby lighthouse) +# Add wisely, as too many plugins slow down shell startup. +plugins=(common-aliases colored-man-pages colorize docker docker-compose emoji safe-paste git git-auto-fetch git-extras history jsontools pip) + +source $ZSH/oh-my-zsh.sh + +# User configuration + +# export MANPATH="/usr/local/man:$MANPATH" + +# You may need to manually set your language environment +# export LANG=en_US.UTF-8 + +# Preferred editor for local and remote sessions +# if [[ -n $SSH_CONNECTION ]]; then +# export EDITOR='vim' +# else +# export EDITOR='mvim' +# fi + +# Compilation flags +# export ARCHFLAGS="-arch x86_64" + +# Set personal aliases, overriding those provided by oh-my-zsh libs, +# plugins, and themes. Aliases can be placed here, though oh-my-zsh +# users are encouraged to define aliases within the ZSH_CUSTOM folder. +# For a full list of active aliases, run `alias`. +# +# Example aliases +# alias zshconfig="mate ~/.zshrc" +# alias ohmyzsh="mate ~/.oh-my-zsh" + +# Activate Python venv in terminal +source /opt/netbox/venv/bin/activate diff --git a/.devcontainer/.zshrc b/.devcontainer/.zshrc new file mode 100644 index 0000000..168d37a --- /dev/null +++ b/.devcontainer/.zshrc @@ -0,0 +1,104 @@ +# If you come from bash you might have to change your $PATH. +# export PATH=$HOME/bin:/usr/local/bin:$PATH + +# Path to your oh-my-zsh installation. +export ZSH="$HOME/.oh-my-zsh" + +# Set name of the theme to load --- if set to "random", it will +# load a random theme each time oh-my-zsh is loaded, in which case, +# to know which specific one was loaded, run: echo $RANDOM_THEME +# See https://github.com/ohmyzsh/ohmyzsh/wiki/Themes +ZSH_THEME="robbyrussell" + +# Set list of themes to pick from when loading at random +# Setting this variable when ZSH_THEME=random will cause zsh to load +# a theme from this variable instead of looking in $ZSH/themes/ +# If set to an empty array, this variable will have no effect. +# ZSH_THEME_RANDOM_CANDIDATES=( "robbyrussell" "agnoster" ) + +# Uncomment the following line to use case-sensitive completion. +# CASE_SENSITIVE="true" + +# Uncomment the following line to use hyphen-insensitive completion. +# Case-sensitive completion must be off. _ and - will be interchangeable. +# HYPHEN_INSENSITIVE="true" + +# Uncomment one of the following lines to change the auto-update behavior +# zstyle ':omz:update' mode disabled # disable automatic updates +# zstyle ':omz:update' mode auto # update automatically without asking +# zstyle ':omz:update' mode reminder # just remind me to update when it's time + +# Uncomment the following line to change how often to auto-update (in days). +# zstyle ':omz:update' frequency 13 + +# Uncomment the following line if pasting URLs and other text is messed up. +# DISABLE_MAGIC_FUNCTIONS="true" + +# Uncomment the following line to disable colors in ls. +# DISABLE_LS_COLORS="true" + +# Uncomment the following line to disable auto-setting terminal title. +# DISABLE_AUTO_TITLE="true" + +# Uncomment the following line to enable command auto-correction. +# ENABLE_CORRECTION="true" + +# Uncomment the following line to display red dots whilst waiting for completion. +# You can also set it to another string to have that shown instead of the default red dots. +# e.g. COMPLETION_WAITING_DOTS="%F{yellow}waiting...%f" +# Caution: this setting can cause issues with multiline prompts in zsh < 5.7.1 (see #5765) +# COMPLETION_WAITING_DOTS="true" + +# Uncomment the following line if you want to disable marking untracked files +# under VCS as dirty. This makes repository status check for large repositories +# much, much faster. +# DISABLE_UNTRACKED_FILES_DIRTY="true" + +# Uncomment the following line if you want to change the command execution time +# stamp shown in the history command output. +# You can set one of the optional three formats: +# "mm/dd/yyyy"|"dd.mm.yyyy"|"yyyy-mm-dd" +# or set a custom format using the strftime function format specifications, +# see 'man strftime' for details. +# HIST_STAMPS="mm/dd/yyyy" + +# Would you like to use another custom folder than $ZSH/custom? +# ZSH_CUSTOM=/path/to/new-custom-folder + +# Which plugins would you like to load? +# Standard plugins can be found in $ZSH/plugins/ +# Custom plugins may be added to $ZSH_CUSTOM/plugins/ +# Example format: plugins=(rails git textmate ruby lighthouse) +# Add wisely, as too many plugins slow down shell startup. +plugins=(common-aliases colored-man-pages colorize docker docker-compose emoji safe-paste git git-auto-fetch git-extras history jsontools pip) + +source $ZSH/oh-my-zsh.sh + +# User configuration + +# export MANPATH="/usr/local/man:$MANPATH" + +# You may need to manually set your language environment +# export LANG=en_US.UTF-8 + +# Preferred editor for local and remote sessions +# if [[ -n $SSH_CONNECTION ]]; then +# export EDITOR='vim' +# else +# export EDITOR='mvim' +# fi + +# Compilation flags +# export ARCHFLAGS="-arch x86_64" + +# Set personal aliases, overriding those provided by oh-my-zsh libs, +# plugins, and themes. Aliases can be placed here, though oh-my-zsh +# users are encouraged to define aliases within the ZSH_CUSTOM folder. +# For a full list of active aliases, run `alias`. +# +# Example aliases +# alias zshconfig="mate ~/.zshrc" +# alias ohmyzsh="mate ~/.oh-my-zsh" + +# Activate Python venv in terminal +source /opt/netbox/venv/bin/activate diff --git a/.devcontainer/Dockerfile-plugin_dev b/.devcontainer/Dockerfile-plugin_dev new file mode 100644 index 0000000..22c8134 --- /dev/null +++ b/.devcontainer/Dockerfile-plugin_dev @@ -0,0 +1,42 @@ +ARG VARIANT=latest + +FROM tgenannt/netbox:${VARIANT} + +ARG DEBIAN_FRONTEND=noninteractive + +# Install APT packages +RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ + && apt-get -y install --no-install-recommends curl git make openssh-client sudo wget zsh \ + && apt-get autoremove -y && apt-get clean -y && rm -rf /var/lib/apt/lists/* + +# Install development & ide dependencies +COPY requirements-dev.txt /tmp/pip-tmp/ +RUN /opt/netbox/venv/bin/python3 -m pip install --disable-pip-version-check --no-cache-dir install -r /tmp/pip-tmp/requirements-dev.txt \ + && rm -rf /tmp/* + +ARG USERNAME=vscode +ARG USER_UID=1000 +ARG USER_GID=$USER_UID + +RUN useradd -md /home/vscode -s /usr/bin/zsh -u $USER_UID $USERNAME \ + && usermod -aG sudo $USERNAME \ + && echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers \ + && mkdir /opt/netbox/netbox/netbox-access-lists \ + && chown $USERNAME:$USERNAME /opt/netbox /etc/netbox -R + +USER $USERNAME + +# Add oh my zsh +RUN wget --quiet https://github.com/robbyrussell/oh-my-zsh/raw/master/tools/install.sh -O - | zsh || true + +COPY .bashrc /home/vscode/.bashrc +COPY .zshrc /home/vscode/.zshrc + +WORKDIR /opt/netbox/netbox/netbox-access-lists + +USER root + +COPY entrypoint-dev.sh /bin/entrypoint.sh +RUN chmod +x /bin/entrypoint.sh + +CMD ["/bin/entrypoint.sh"] diff --git a/.devcontainer/configuration/configuration.py b/.devcontainer/configuration/configuration.py new file mode 100644 index 0000000..1db6051 --- /dev/null +++ b/.devcontainer/configuration/configuration.py @@ -0,0 +1,248 @@ +#### +## 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 + +# For reference see https://netbox.readthedocs.io/en/stable/configuration/ +# Based on https://github.com/netbox-community/netbox/blob/master/netbox/netbox/configuration.example.py + +# Read secret from file +def _read_secret(secret_name, default = None): + try: + f = open('/run/secrets/' + secret_name, 'r', encoding='utf-8') + except EnvironmentError: + return default + else: + with f: + return f.readline().strip() + +_BASE_DIR = dirname(dirname(abspath(__file__))) + +######################### +# # +# Required settings # +# # +######################### + +# This is a list of valid fully-qualified domain names (FQDNs) for the NetBox server. NetBox will not permit write +# access to the server via any other hostnames. The first FQDN in the list will be treated as the preferred name. +# +# Example: ALLOWED_HOSTS = ['netbox.example.com', 'netbox.internal.local'] +ALLOWED_HOSTS = environ.get('ALLOWED_HOSTS', '*').split(' ') + +# PostgreSQL database configuration. See the Django documentation for a complete list of available parameters: +# https://docs.djangoproject.com/en/stable/ref/settings/#databases +DATABASE = { + 'NAME': environ.get('DB_NAME', 'netbox'), # Database name + 'USER': environ.get('DB_USER', ''), # PostgreSQL username + 'PASSWORD': _read_secret('db_password', environ.get('DB_PASSWORD', '')), + # PostgreSQL password + 'HOST': environ.get('DB_HOST', 'localhost'), # Database server + 'PORT': environ.get('DB_PORT', ''), # Database port (leave blank for default) + 'OPTIONS': {'sslmode': environ.get('DB_SSLMODE', 'prefer')}, + # Database connection SSLMODE + 'CONN_MAX_AGE': int(environ.get('DB_CONN_MAX_AGE', '300')), + # Max database connection age + 'DISABLE_SERVER_SIDE_CURSORS': environ.get('DB_DISABLE_SERVER_SIDE_CURSORS', 'False').lower() == 'true', + # 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': int(environ.get('REDIS_PORT', 6379)), + 'PASSWORD': _read_secret('redis_password', environ.get('REDIS_PASSWORD', '')), + 'DATABASE': int(environ.get('REDIS_DATABASE', 0)), + 'SSL': environ.get('REDIS_SSL', 'False').lower() == 'true', + 'INSECURE_SKIP_TLS_VERIFY': environ.get('REDIS_INSECURE_SKIP_TLS_VERIFY', 'False').lower() == 'true', + }, + 'caching': { + 'HOST': environ.get('REDIS_CACHE_HOST', environ.get('REDIS_HOST', 'localhost')), + 'PORT': int(environ.get('REDIS_CACHE_PORT', environ.get('REDIS_PORT', 6379))), + 'PASSWORD': _read_secret('redis_cache_password', environ.get('REDIS_CACHE_PASSWORD', environ.get('REDIS_PASSWORD', ''))), + 'DATABASE': int(environ.get('REDIS_CACHE_DATABASE', 1)), + 'SSL': environ.get('REDIS_CACHE_SSL', environ.get('REDIS_SSL', 'False')).lower() == 'true', + 'INSECURE_SKIP_TLS_VERIFY': environ.get('REDIS_CACHE_INSECURE_SKIP_TLS_VERIFY', environ.get('REDIS_INSECURE_SKIP_TLS_VERIFY', 'False')).lower() == 'true', + }, +} + +# This key is used for secure generation of random numbers and strings. It must never be exposed outside of this file. +# For optimal security, SECRET_KEY should be at least 50 characters in length and contain a mix of letters, numbers, and +# symbols. NetBox will not run without this defined. For more information, see +# https://docs.djangoproject.com/en/stable/ref/settings/#std:setting-SECRET_KEY +SECRET_KEY = _read_secret('secret_key', environ.get('SECRET_KEY', '')) + + +######################### +# # +# Optional settings # +# # +######################### + +# Specify one or more name and email address tuples representing NetBox administrators. These people will be notified of +# application errors (assuming correct email settings are provided). +ADMINS = [ + # ['John Doe', 'jdoe@example.com'], +] + +# URL schemes that are allowed within links in NetBox +ALLOWED_URL_SCHEMES = ( + 'file', 'ftp', 'ftps', 'http', 'https', 'irc', 'mailto', 'sftp', 'ssh', 'tel', 'telnet', 'tftp', 'vnc', 'xmpp', +) + +# Optionally display a persistent banner at the top and/or bottom of every page. HTML is allowed. To display the same +# content in both banners, define BANNER_TOP and set BANNER_BOTTOM = BANNER_TOP. +BANNER_TOP = environ.get('BANNER_TOP', '') +BANNER_BOTTOM = environ.get('BANNER_BOTTOM', '') + +# Text to include on the login page above the login form. HTML is allowed. +BANNER_LOGIN = environ.get('BANNER_LOGIN', '') + +# Base URL path if accessing NetBox within a directory. For example, if installed at http://example.com/netbox/, set: +# BASE_PATH = 'netbox/' +BASE_PATH = environ.get('BASE_PATH', '') + +# Maximum number of days to retain logged changes. Set to 0 to retain changes indefinitely. (Default: 90) +CHANGELOG_RETENTION = int(environ.get('CHANGELOG_RETENTION', 90)) + +# API Cross-Origin Resource Sharing (CORS) settings. If CORS_ORIGIN_ALLOW_ALL is set to True, all origins will be +# allowed. Otherwise, define a list of allowed origins using either CORS_ORIGIN_WHITELIST or +# CORS_ORIGIN_REGEX_WHITELIST. For more information, see https://github.com/ottoyiu/django-cors-headers +CORS_ORIGIN_ALLOW_ALL = environ.get('CORS_ORIGIN_ALLOW_ALL', 'False').lower() == 'true' +CORS_ORIGIN_WHITELIST = list(filter(None, environ.get('CORS_ORIGIN_WHITELIST', 'https://localhost').split(' '))) +CORS_ORIGIN_REGEX_WHITELIST = [re.compile(r) for r in list(filter(None, environ.get('CORS_ORIGIN_REGEX_WHITELIST', '').split(' ')))] + +# Set to True to enable server debugging. WARNING: Debugging introduces a substantial performance penalty and may reveal +# sensitive information about your installation. Only enable debugging while performing testing. Never enable debugging +# on a production system. +DEBUG = environ.get('DEBUG', 'False').lower() == 'true' + +# Email settings +EMAIL = { + 'SERVER': environ.get('EMAIL_SERVER', 'localhost'), + 'PORT': int(environ.get('EMAIL_PORT', 25)), + 'USERNAME': environ.get('EMAIL_USERNAME', ''), + 'PASSWORD': _read_secret('email_password', environ.get('EMAIL_PASSWORD', '')), + 'USE_SSL': environ.get('EMAIL_USE_SSL', 'False').lower() == 'true', + 'USE_TLS': environ.get('EMAIL_USE_TLS', 'False').lower() == 'true', + 'SSL_CERTFILE': environ.get('EMAIL_SSL_CERTFILE', ''), + 'SSL_KEYFILE': environ.get('EMAIL_SSL_KEYFILE', ''), + 'TIMEOUT': int(environ.get('EMAIL_TIMEOUT', 10)), # seconds + 'FROM_EMAIL': environ.get('EMAIL_FROM', ''), +} + +# Enforcement of unique IP space can be toggled on a per-VRF basis. To enforce unique IP space within the global table +# (all prefixes and IP addresses not assigned to a VRF), set ENFORCE_GLOBAL_UNIQUE to True. +ENFORCE_GLOBAL_UNIQUE = environ.get('ENFORCE_GLOBAL_UNIQUE', 'False').lower() == 'true' + +# Exempt certain models from the enforcement of view permissions. Models listed here will be viewable by all users and +# by anonymous users. List models in the form `.`. Add '*' to this list to exempt all models. +EXEMPT_VIEW_PERMISSIONS = list(filter(None, environ.get('EXEMPT_VIEW_PERMISSIONS', '').split(' '))) + +# Enable GraphQL API. +GRAPHQL_ENABLED = environ.get('GRAPHQL_ENABLED', 'True').lower() == 'true' + +# Enable custom logging. Please see the Django documentation for detailed guidance on configuring custom logs: +# https://docs.djangoproject.com/en/stable/topics/logging/ +LOGGING = {} + +# Setting this to True will permit only authenticated users to access any part of NetBox. By default, anonymous users +# are permitted to access most data in NetBox (excluding secrets) but not make any changes. +LOGIN_REQUIRED = environ.get('LOGIN_REQUIRED', 'False').lower() == 'true' + +# The length of time (in seconds) for which a user will remain logged into the web UI before being prompted to +# re-authenticate. (Default: 1209600 [14 days]) +LOGIN_TIMEOUT = int(environ.get('LOGIN_TIMEOUT', 1209600)) + +# Setting this to True will display a "maintenance mode" banner at the top of every page. +MAINTENANCE_MODE = environ.get('MAINTENANCE_MODE', 'False').lower() == 'true' + +# An API consumer can request an arbitrary number of objects =by appending the "limit" parameter to the URL (e.g. +# "?limit=1000"). This setting defines the maximum limit. Setting it to 0 or None will allow an API consumer to request +# all objects by specifying "?limit=0". +MAX_PAGE_SIZE = int(environ.get('MAX_PAGE_SIZE', 1000)) + +# The file path where uploaded media such as image attachments are stored. A trailing slash is not needed. Note that +# the default value of this setting is derived from the installed location. +MEDIA_ROOT = environ.get('MEDIA_ROOT', join(_BASE_DIR, 'media')) + +# Expose Prometheus monitoring metrics at the HTTP endpoint '/metrics' +METRICS_ENABLED = environ.get('METRICS_ENABLED', 'False').lower() == 'true' + +# Credentials that NetBox will uses to authenticate to devices when connecting via NAPALM. +NAPALM_USERNAME = environ.get('NAPALM_USERNAME', '') +NAPALM_PASSWORD = _read_secret('napalm_password', environ.get('NAPALM_PASSWORD', '')) + +# NAPALM timeout (in seconds). (Default: 30) +NAPALM_TIMEOUT = int(environ.get('NAPALM_TIMEOUT', 30)) + +# NAPALM optional arguments (see http://napalm.readthedocs.io/en/latest/support/#optional-arguments). Arguments must +# be provided as a dictionary. +NAPALM_ARGS = {} + +# Determine how many objects to display per page within a list. (Default: 50) +PAGINATE_COUNT = int(environ.get('PAGINATE_COUNT', 50)) + +# Enable installed plugins. Add the name of each plugin to the list. +PLUGINS = [] + +# Plugins configuration settings. These settings are used by various plugins that the user may have installed. +# Each key in the dictionary is the name of an installed plugin and its value is a dictionary of settings. +PLUGINS_CONFIG = { +} + +# When determining the primary IP address for a device, IPv6 is preferred over IPv4 by default. Set this to True to +# prefer IPv4 instead. +PREFER_IPV4 = environ.get('PREFER_IPV4', 'False').lower() == 'true' + +# Rack elevation size defaults, in pixels. For best results, the ratio of width to height should be roughly 10:1. +RACK_ELEVATION_DEFAULT_UNIT_HEIGHT = int(environ.get('RACK_ELEVATION_DEFAULT_UNIT_HEIGHT', 22)) +RACK_ELEVATION_DEFAULT_UNIT_WIDTH = int(environ.get('RACK_ELEVATION_DEFAULT_UNIT_WIDTH', 220)) + +# Remote authentication support +REMOTE_AUTH_ENABLED = environ.get('REMOTE_AUTH_ENABLED', 'False').lower() == 'true' +REMOTE_AUTH_BACKEND = environ.get('REMOTE_AUTH_BACKEND', 'netbox.authentication.RemoteUserBackend') +REMOTE_AUTH_HEADER = environ.get('REMOTE_AUTH_HEADER', 'HTTP_REMOTE_USER') +REMOTE_AUTH_AUTO_CREATE_USER = environ.get('REMOTE_AUTH_AUTO_CREATE_USER', 'True').lower() == 'true' +REMOTE_AUTH_DEFAULT_GROUPS = list(filter(None, environ.get('REMOTE_AUTH_DEFAULT_GROUPS', '').split(' '))) + +# This repository is used to check whether there is a new release of NetBox available. Set to None to disable the +# version check or use the URL below to check for release in the official NetBox repository. +# https://api.github.com/repos/netbox-community/netbox/releases +RELEASE_CHECK_URL = environ.get('RELEASE_CHECK_URL', None) + +# The file path where custom reports will be stored. A trailing slash is not needed. Note that the default value of +# this setting is derived from the installed location. +REPORTS_ROOT = environ.get('REPORTS_ROOT', '/etc/netbox/reports') + +# Maximum execution time for background tasks, in seconds. +RQ_DEFAULT_TIMEOUT = int(environ.get('RQ_DEFAULT_TIMEOUT', 300)) + +# The file path where custom scripts will be stored. A trailing slash is not needed. Note that the default value of +# this setting is derived from the installed location. +SCRIPTS_ROOT = environ.get('SCRIPTS_ROOT', '/etc/netbox/scripts') + +# By default, NetBox will store session data in the database. Alternatively, a file path can be specified here to use +# local file storage instead. (This can be useful for enabling authentication on a standby instance with read-only +# database access.) Note that the user as which NetBox runs must have read and write permissions to this path. +SESSION_FILE_PATH = environ.get('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') diff --git a/.devcontainer/configuration/logging.py b/.devcontainer/configuration/logging.py new file mode 100644 index 0000000..30632e0 --- /dev/null +++ b/.devcontainer/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/.devcontainer/configuration/plugins.py b/.devcontainer/configuration/plugins.py new file mode 100644 index 0000000..cc5b291 --- /dev/null +++ b/.devcontainer/configuration/plugins.py @@ -0,0 +1,13 @@ +# 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_access_lists" + ] + +PLUGINS_CONFIG = { + "netbox_access_lists":{} +} diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..a56c043 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,85 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at: +// https://github.com/microsoft/vscode-dev-containers/tree/v0.238.0/containers/python-3-postgres +// Update the VARIANT arg in docker-compose.yml to pick a Python version +{ + "name": "NetBox Plugin Develoment", + "dockerComposeFile": [ + "docker-compose.yml", + "docker-compose.override.yml" + ], + "service": "netbox", + //"workspaceMount": "source=${localWorkspaceFolder},target=/opt/netbox/netbox/netbox-access-lists,type=bind,consistency=cached", + "workspaceFolder": "/opt/netbox/netbox/netbox-access-lists", + + "overrideCommand":false, + + // Configure tool-specific properties. + "customizations": { + // Configure properties specific to VS Code. + "vscode": { + // Set *default* container specific settings.json values on container create. + "settings": { + //"[python]": { + // "editor.codeActionsOnSave": { + // "source.organizeImports": true + // } + //}, + //"python.sortImports.args": [ + // "--profile=black" + //], + //"python.sortImports.path": "/opt/netbox/venv/bin/isort", + "python.analysis.typeCheckingMode": "strict", + "python.analysis.extraPaths": [ + "/opt/netbox/", + "/opt/netbox/netbox" + ], + "python.autoComplete.extraPaths": [ + "/opt/netbox/", + "/opt/netbox/netbox" + ], + "python.defaultInterpreterPath": "/opt/netbox/venv/bin/python", + "python.formatting.autopep8Path": "/opt/netbox/venv/lib/python3.9/site-packages/autopep8", + "python.formatting.blackPath": "/opt/netbox/venv/lib/python3.9/site-packages/black", + "python.formatting.provider": "black", + "python.formatting.yapfPath": "/opt/netbox/venv/lib/python3.9/site-packages/yapf", + "python.linting.banditPath": "/opt/netbox/venv/lib/python3.9/site-packages/bandit", + "python.linting.enabled": true, + "python.linting.flake8Path": "/opt/netbox/venv/lib/python3.9/site-packages/flake8", + "python.linting.mypyPath": "/opt/netbox/venv/lib/python3.9/site-packages/mypy", + "python.linting.pycodestylePath": "/opt/netbox/venv/lib/python3.9/site-packages/pycodestyle", + "python.linting.pydocstylePath": "/opt/netbox/venv/lib/python3.9/site-packages/pydocstyle", + "python.linting.pylintEnabled": true, + "python.linting.pylintPath": "/opt/netbox/venv/lib/python3.9/site-packages/pylint", + "python.pythonPath": "/opt/netbox/venv/bin/python", + "python.terminal.activateEnvironment": true, + "python.venvPath": "/opt/netbox/" + }, + + // Add the IDs of extensions you want installed when the container is created. + "extensions": [ + "ms-python.python", + "ms-python.vscode-pylance", + "DavidAnson.vscode-markdownlint", + "searKing.preview-vscode", + "esbenp.prettier-vscode", + "aaron-bond.better-comments", + "GitHub.codespaces", + "codezombiech.gitignore", + "Tyriar.sort-lines" + ] + } + }, + + // Use 'forwardPorts' to make a list of ports inside the container available locally. + // This can be used to network with other containers or the host. + // "forwardPorts": [5000, 5432], + + // Use 'postCreateCommand' to run commands after the container is created. + // "postCreateCommand": "pip install --user -r requirements-dev.txt", + + //"postAttachCommand": "source /opt/netbox/venv/bin/activate", + + // Comment out to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root. + "remoteUser": "vscode" + +} diff --git a/.devcontainer/docker-compose.override.yml b/.devcontainer/docker-compose.override.yml new file mode 100644 index 0000000..49e1618 --- /dev/null +++ b/.devcontainer/docker-compose.override.yml @@ -0,0 +1,12 @@ +version: '3.4' +services: + netbox: + image: netbox-plugin_dev + build: + dockerfile: Dockerfile-plugin_dev + ports: + - 8000:8080 + volumes: + - ../:/opt/netbox/netbox/netbox-access-lists + - ~/.gitconfig:/home/vscode/.gitconfig:z,ro + - ~/.ssh:/home/vscode/.ssh diff --git a/.devcontainer/docker-compose.yml b/.devcontainer/docker-compose.yml new file mode 100644 index 0000000..47ed4f9 --- /dev/null +++ b/.devcontainer/docker-compose.yml @@ -0,0 +1,64 @@ +version: '3.4' +services: + netbox: &netbox + image: tgenannt/netbox:${VARIANT-latest} + depends_on: + - postgres + - redis + #- redis-cache + - netbox-worker + env_file: env/netbox.env + user: 'unit:root' + volumes: + - ./initializers:/opt/netbox/initializers:z,ro + - ./configuration:/etc/netbox/config:z,ro + #- netbox-media-files:/opt/netbox/netbox/media:z + netbox-worker: + <<: *netbox + depends_on: + - redis + - postgres + command: + - /opt/netbox/venv/bin/python + - /opt/netbox/netbox/manage.py + - rqworker + #netbox-housekeeping: + # <<: *netbox + # depends_on: + # - redis + # - postgres + # command: + # - /opt/netbox/housekeeping.sh + + # postgres + postgres: + image: postgres:14-alpine + env_file: env/postgres.env + volumes: + - netbox-postgres-data:/var/lib/postgresql/data + + # redis + redis: + image: redis:6-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: redis:6-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-media-files: + # driver: local + netbox-postgres-data: + driver: local + #netbox-redis-data: + # driver: local diff --git a/.devcontainer/entrypoint-dev.sh b/.devcontainer/entrypoint-dev.sh new file mode 100644 index 0000000..463fbb9 --- /dev/null +++ b/.devcontainer/entrypoint-dev.sh @@ -0,0 +1,32 @@ +#!/bin/bash + +USER=vscode + +# Reconfigure User id if set by user +if [ ! -z "${USER_UID}" ] && [ "${USER_UID}" != "`id -u ${USER}`" ] ; then + echo -n "Update uid for user ${USER} with ${USER_UID}" + usermod -u ${USER_UID} ${USER} + echo "... updated" +else + echo "skipping UID configuration" +fi + +if [ -n "${USER_GID}" ] && [ "${USER_GID}" != "`id -g ${USER}`" ] ; then + echo -n "Update gid for group ${USER} with ${USER_GID}" + usermod -u ${USER_UID} ${USER} + echo "... updated" +else + echo "skipping GID configuration" +fi + +#if [ -z "$SSH_AUTH_SOCK" ]; then +# # Check for a currently running instance of the agent +# RUNNING_AGENT="`ps -ax | grep 'ssh-agent -s' | grep -v grep | wc -l | tr -d '[:space:]'`" +# if [ "$RUNNING_AGENT" = "0" ]; then +# # Launch a new instance of the agent +# ssh-agent -s &> $HOME/.ssh/ssh-agent +# fi +# eval `cat $HOME/.ssh/ssh-agent` +#fi + +/bin/sh -c "while sleep 1000; do :; done" diff --git a/.devcontainer/env/netbox.env b/.devcontainer/env/netbox.env new file mode 100644 index 0000000..ef8607a --- /dev/null +++ b/.devcontainer/env/netbox.env @@ -0,0 +1,20 @@ +ALLOWED_HOSTS=* +CORS_ORIGIN_ALLOW_ALL=True +DB_HOST=postgres +DB_NAME=netbox +DB_PASSWORD=J5brHrAXFLQSif0K +DB_USER=netbox +DEBUG=true +GRAPHQL_ENABLED=true +MAX_PAGE_SIZE=1000 +MEDIA_ROOT=/opt/netbox/netbox/media +REDIS_DATABASE=0 +REDIS_HOST=redis +REDIS_INSECURE_SKIP_TLS_VERIFY=false +REDIS_PASSWORD=H733Kdjndks81 +SECRET_KEY=r8OwDznj!!dciP9ghmRfdu1Ysxm0AiPeDCQhKE+N_rClfWNj +SUPERUSER_API_TOKEN=0123456789abcdef0123456789abcdef01234567 +SUPERUSER_EMAIL=admin@example.com +SUPERUSER_NAME=admin +SUPERUSER_PASSWORD=admin +WEBHOOKS_ENABLED=true diff --git a/.devcontainer/env/postgres.env b/.devcontainer/env/postgres.env new file mode 100644 index 0000000..bb7b53c --- /dev/null +++ b/.devcontainer/env/postgres.env @@ -0,0 +1,3 @@ +POSTGRES_DB=netbox +POSTGRES_PASSWORD=J5brHrAXFLQSif0K +POSTGRES_USER=netbox diff --git a/.devcontainer/env/redis.env b/.devcontainer/env/redis.env new file mode 100644 index 0000000..44a1987 --- /dev/null +++ b/.devcontainer/env/redis.env @@ -0,0 +1 @@ +REDIS_PASSWORD=H733Kdjndks81 diff --git a/.devcontainer/initializers/aggregates.yml b/.devcontainer/initializers/aggregates.yml new file mode 100644 index 0000000..ae92ec0 --- /dev/null +++ b/.devcontainer/initializers/aggregates.yml @@ -0,0 +1,7 @@ +- prefix: 10.0.0.0/16 + rir: RFC1918 + tenant: tenant1 +- prefix: fd00:ccdd::/32 + rir: RFC4193 ULA +- prefix: 2001:db8::/32 + rir: RFC3849 diff --git a/.devcontainer/initializers/asns.yml b/.devcontainer/initializers/asns.yml new file mode 100644 index 0000000..8e6393e --- /dev/null +++ b/.devcontainer/initializers/asns.yml @@ -0,0 +1,7 @@ +- asn: 1 + rir: RFC1918 + tenant: tenant1 +- asn: 2 + rir: RFC4193 ULA +- asn: 3 + rir: RFC3849 diff --git a/.devcontainer/initializers/circuit_types.yml b/.devcontainer/initializers/circuit_types.yml new file mode 100644 index 0000000..95dee30 --- /dev/null +++ b/.devcontainer/initializers/circuit_types.yml @@ -0,0 +1,6 @@ +- name: VPLS + slug: vpls +- name: MPLS + slug: mpls +- name: Internet + slug: internet diff --git a/.devcontainer/initializers/circuits.yml b/.devcontainer/initializers/circuits.yml new file mode 100644 index 0000000..6dd8602 --- /dev/null +++ b/.devcontainer/initializers/circuits.yml @@ -0,0 +1,7 @@ +- cid: Circuit_ID-1 + provider: Provider1 + type: Internet + tenant: tenant1 +- cid: Circuit_ID-2 + provider: Provider2 + type: MPLS diff --git a/.devcontainer/initializers/cluster_groups.yml b/.devcontainer/initializers/cluster_groups.yml new file mode 100644 index 0000000..b8a54b4 --- /dev/null +++ b/.devcontainer/initializers/cluster_groups.yml @@ -0,0 +1,4 @@ +- name: Group 1 + slug: group-1 +- name: Group 2 + slug: group-2 diff --git a/.devcontainer/initializers/cluster_types.yml b/.devcontainer/initializers/cluster_types.yml new file mode 100644 index 0000000..0ca1f8d --- /dev/null +++ b/.devcontainer/initializers/cluster_types.yml @@ -0,0 +1,2 @@ +- name: Hyper-V + slug: hyper-v diff --git a/.devcontainer/initializers/clusters.yml b/.devcontainer/initializers/clusters.yml new file mode 100644 index 0000000..3ed7c8e --- /dev/null +++ b/.devcontainer/initializers/clusters.yml @@ -0,0 +1,7 @@ +- name: cluster1 + type: Hyper-V + group: Group 1 + tenant: tenant1 +- name: cluster2 + type: Hyper-V + site: SING 1 diff --git a/.devcontainer/initializers/dcim_interfaces.yml b/.devcontainer/initializers/dcim_interfaces.yml new file mode 100644 index 0000000..2d23b3e --- /dev/null +++ b/.devcontainer/initializers/dcim_interfaces.yml @@ -0,0 +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 + name: to-server02 +- device: server02 + enabled: true + type: virtual + name: to-server01 diff --git a/.devcontainer/initializers/device_roles.yml b/.devcontainer/initializers/device_roles.yml new file mode 100644 index 0000000..2f327e1 --- /dev/null +++ b/.devcontainer/initializers/device_roles.yml @@ -0,0 +1,15 @@ +- name: switch + slug: switch + color: Grey +- name: router + slug: router + color: Cyan +- name: load-balancer + slug: load-balancer + color: Red +- name: server + slug: server + color: Blue +- name: patchpanel + slug: patchpanel + color: Black diff --git a/.devcontainer/initializers/device_types.yml b/.devcontainer/initializers/device_types.yml new file mode 100644 index 0000000..2a9d851 --- /dev/null +++ b/.devcontainer/initializers/device_types.yml @@ -0,0 +1,15 @@ +- model: Model 1 + manufacturer: Manufacturer 1 + slug: model-1 + u_height: 2 +- model: Model 2 + manufacturer: Manufacturer 1 + slug: model-2 +- model: Model 3 + manufacturer: Manufacturer 1 + slug: model-3 + is_full_depth: false + u_height: 0 +- model: Other + manufacturer: No Name + slug: other diff --git a/.devcontainer/initializers/devices.yml b/.devcontainer/initializers/devices.yml new file mode 100644 index 0000000..dce7795 --- /dev/null +++ b/.devcontainer/initializers/devices.yml @@ -0,0 +1,45 @@ +#Possible Choices: +# face: +# - front +# - rear +# status: +# - offline +# - active +# - planned +# - staged +# - failed +# - inventory +# - decommissioning +## +#Examples: + +- name: server01 + device_role: server + device_type: Other + site: AMS 1 + rack: rack-01 + face: front + position: 1 +- name: server02 + device_role: server + device_type: Other + site: AMS 2 + rack: rack-02 + face: front + position: 2 + primary_ip4: 10.1.1.2/24 + primary_ip6: 2001:db8:a000:1::2/64 +- name: server03 + device_role: server + device_type: Other + site: SING 1 + rack: rack-03 + face: front + position: 3 +- name: server04 + device_role: server + device_type: Other + site: SING 1 + location: cage 101 + face: front + position: 3 diff --git a/.devcontainer/initializers/groups.yml b/.devcontainer/initializers/groups.yml new file mode 100644 index 0000000..15213a6 --- /dev/null +++ b/.devcontainer/initializers/groups.yml @@ -0,0 +1,9 @@ +# applications: +# users: +# - technical_user +# readers: +# users: +# - reader +# writers: +# users: +# - writer diff --git a/.devcontainer/initializers/ip_addresses.yml b/.devcontainer/initializers/ip_addresses.yml new file mode 100644 index 0000000..22b2a4f --- /dev/null +++ b/.devcontainer/initializers/ip_addresses.yml @@ -0,0 +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 + vrf: vrf1 +- address: 2001:db8:a000:1::1/64 + device: server01 + interface: to-server02 + status: active + vrf: vrf1 +- address: 10.1.1.2/24 + device: server02 + interface: to-server01 + status: active +- address: 2001:db8:a000:1::2/64 + device: server02 + interface: to-server01 + status: active +- address: 10.1.1.10/24 + description: reserved IP + status: reserved + tenant: tenant1 +- address: 2001:db8:a000:1::10/64 + description: reserved IP + status: reserved + tenant: tenant1 diff --git a/.devcontainer/initializers/locations.yml b/.devcontainer/initializers/locations.yml new file mode 100644 index 0000000..ff8cb42 --- /dev/null +++ b/.devcontainer/initializers/locations.yml @@ -0,0 +1,3 @@ +- name: cage 101 + slug: cage-101 + site: SING 1 diff --git a/.devcontainer/initializers/manufacturers.yml b/.devcontainer/initializers/manufacturers.yml new file mode 100644 index 0000000..f8e5cca --- /dev/null +++ b/.devcontainer/initializers/manufacturers.yml @@ -0,0 +1,6 @@ +- name: Manufacturer 1 + slug: manufacturer-1 +- name: Manufacturer 2 + slug: manufacturer-2 +- name: No Name + slug: no-name diff --git a/.devcontainer/initializers/object_permissions.yml b/.devcontainer/initializers/object_permissions.yml new file mode 100644 index 0000000..332011f --- /dev/null +++ b/.devcontainer/initializers/object_permissions.yml @@ -0,0 +1,48 @@ +# all.ro: +# actions: +# - view +# description: 'Read Only for All Objects' +# enabled: true +# groups: +# - applications +# - readers +# object_types: all +# users: +# - jdoe +# all.rw: +# actions: +# - add +# - change +# - delete +# - view +# description: 'Read/Write for All Objects' +# enabled: true +# groups: +# - writers +# object_types: all +# network_team.rw: +# actions: +# - add +# - change +# - delete +# - view +# description: "Network Team Permissions" +# enabled: true +# object_types: +# circuits: +# - circuit +# - circuittermination +# - circuittype +# - provider +# dcim: all +# ipam: +# - aggregate +# - ipaddress +# - prefix +# - rir +# - role +# - routetarget +# - service +# - vlan +# - vlangroup +# - vrf diff --git a/.devcontainer/initializers/platforms.yml b/.devcontainer/initializers/platforms.yml new file mode 100644 index 0000000..8fc82be --- /dev/null +++ b/.devcontainer/initializers/platforms.yml @@ -0,0 +1,15 @@ +- name: Platform 1 + slug: platform-1 + manufacturer: Manufacturer 1 + napalm_driver: driver1 + napalm_args: "{'arg1': 'value1', 'arg2': 'value2'}" +- name: Platform 2 + slug: platform-2 + manufacturer: Manufacturer 2 + napalm_driver: driver2 + napalm_args: "{'arg1': 'value1', 'arg2': 'value2'}" +- name: Platform 3 + slug: platform-3 + manufacturer: No Name + napalm_driver: driver3 + napalm_args: "{'arg1': 'value1', 'arg2': 'value2'}" diff --git a/.devcontainer/initializers/power_feeds.yml b/.devcontainer/initializers/power_feeds.yml new file mode 100644 index 0000000..595c3d2 --- /dev/null +++ b/.devcontainer/initializers/power_feeds.yml @@ -0,0 +1,14 @@ +- name: power feed 1 + power_panel: power panel AMS 1 + voltage: 208 + amperage: 50 + max_utilization: 80 + phase: Single phase + rack: rack-01 +- name: power feed 2 + power_panel: power panel SING 1 + voltage: 208 + amperage: 50 + max_utilization: 80 + phase: Three-phase + rack: rack-03 diff --git a/.devcontainer/initializers/power_panels.yml b/.devcontainer/initializers/power_panels.yml new file mode 100644 index 0000000..4bb656b --- /dev/null +++ b/.devcontainer/initializers/power_panels.yml @@ -0,0 +1,5 @@ +- name: power panel AMS 1 + site: AMS 1 +- name: power panel SING 1 + site: SING 1 + location: cage 101 diff --git a/.devcontainer/initializers/prefix_vlan_roles.yml b/.devcontainer/initializers/prefix_vlan_roles.yml new file mode 100644 index 0000000..20043c9 --- /dev/null +++ b/.devcontainer/initializers/prefix_vlan_roles.yml @@ -0,0 +1,2 @@ +- name: Main Management + slug: main-management diff --git a/.devcontainer/initializers/prefixes.yml b/.devcontainer/initializers/prefixes.yml new file mode 100644 index 0000000..6aea9c5 --- /dev/null +++ b/.devcontainer/initializers/prefixes.yml @@ -0,0 +1,29 @@ +#Possible Choices: +# status: +# - container +# - active +# - reserved +# - deprecated +## +#Examples: + +- description: prefix1 + prefix: 10.1.1.0/24 + site: AMS 1 + status: active + tenant: tenant1 + vlan: vlan1 +- description: prefix2 + prefix: 10.1.2.0/24 + site: AMS 2 + status: active + tenant: tenant2 + vlan: vlan2 + is_pool: true + vrf: vrf2 +- description: ipv6 prefix1 + prefix: 2001:db8:a000:1::/64 + site: AMS 2 + status: active + tenant: tenant2 + vlan: vlan2 diff --git a/.devcontainer/initializers/providers.yml b/.devcontainer/initializers/providers.yml new file mode 100644 index 0000000..4d0e5b0 --- /dev/null +++ b/.devcontainer/initializers/providers.yml @@ -0,0 +1,6 @@ +- name: Provider1 + slug: provider1 + asn: 121 +- name: Provider2 + slug: provider2 + asn: 122 diff --git a/.devcontainer/initializers/rack_roles.yml b/.devcontainer/initializers/rack_roles.yml new file mode 100644 index 0000000..7af7a74 --- /dev/null +++ b/.devcontainer/initializers/rack_roles.yml @@ -0,0 +1,12 @@ +- name: Role 1 + slug: role-1 + color: Pink +- name: Role 2 + slug: role-2 + color: Cyan +- name: Role 3 + slug: role-3 + color: Grey +- name: Role 4 + slug: role-4 + color: Teal diff --git a/.devcontainer/initializers/racks.yml b/.devcontainer/initializers/racks.yml new file mode 100644 index 0000000..2a691c3 --- /dev/null +++ b/.devcontainer/initializers/racks.yml @@ -0,0 +1,35 @@ +#Possible Choices: +# width: +# - 19 +# - 23 +# types: +# - 2-post-frame +# - 4-post-frame +# - 4-post-cabinet +# - wall-frame +# - wall-cabinet +# outer_unit: +# - mm +# - in +## +#Examples: + +- site: AMS 1 + name: rack-01 + role: Role 1 + type: 4-post-cabinet + width: 19 + u_height: 47 +- site: AMS 2 + name: rack-02 + role: Role 2 + type: 4-post-cabinet + width: 19 + u_height: 47 +- site: SING 1 + name: rack-03 + location: cage 101 + role: Role 3 + type: 4-post-cabinet + width: 19 + u_height: 47 diff --git a/.devcontainer/initializers/regions.yml b/.devcontainer/initializers/regions.yml new file mode 100644 index 0000000..11db5bf --- /dev/null +++ b/.devcontainer/initializers/regions.yml @@ -0,0 +1,10 @@ +- name: Singapore + slug: singapore +- name: Amsterdam + slug: amsterdam +- name: Downtown + slug: downtown + parent: Amsterdam +- name: Suburbs + slug: suburbs + parent: Amsterdam diff --git a/.devcontainer/initializers/rirs.yml b/.devcontainer/initializers/rirs.yml new file mode 100644 index 0000000..a74d484 --- /dev/null +++ b/.devcontainer/initializers/rirs.yml @@ -0,0 +1,9 @@ +- is_private: true + name: RFC1918 + slug: rfc1918 +- is_private: true + name: RFC4193 ULA + slug: rfc4193-ula +- is_private: true + name: RFC3849 + slug: rfc3849 diff --git a/.devcontainer/initializers/route_targets.yml b/.devcontainer/initializers/route_targets.yml new file mode 100644 index 0000000..786d24e --- /dev/null +++ b/.devcontainer/initializers/route_targets.yml @@ -0,0 +1,3 @@ +- name: 65000:1001 + tenant: tenant1 +- name: 65000:1002 diff --git a/.devcontainer/initializers/services.yml b/.devcontainer/initializers/services.yml new file mode 100644 index 0000000..e04bee8 --- /dev/null +++ b/.devcontainer/initializers/services.yml @@ -0,0 +1,15 @@ +- name: DNS + protocol: TCP + ports: + - 53 + virtual_machine: virtual machine 1 +- name: DNS + protocol: UDP + ports: + - 53 + virtual_machine: virtual machine 1 +- name: MISC + protocol: UDP + ports: + - 4000 + device: server01 diff --git a/.devcontainer/initializers/sites.yml b/.devcontainer/initializers/sites.yml new file mode 100644 index 0000000..9933538 --- /dev/null +++ b/.devcontainer/initializers/sites.yml @@ -0,0 +1,22 @@ +- name: AMS 1 + slug: ams1 + region: Downtown + status: active + facility: Amsterdam 1 +- name: AMS 2 + slug: ams2 + region: Downtown + status: active + facility: Amsterdam 2 +- name: AMS 3 + slug: ams3 + region: Suburbs + status: active + facility: Amsterdam 3 + tenant: tenant1 +- name: SING 1 + slug: sing1 + region: Singapore + status: active + facility: Singapore 1 + tenant: tenant2 diff --git a/.devcontainer/initializers/tags.yml b/.devcontainer/initializers/tags.yml new file mode 100644 index 0000000..ff582d3 --- /dev/null +++ b/.devcontainer/initializers/tags.yml @@ -0,0 +1,12 @@ +- name: Tag 1 + slug: tag-1 + color: Pink +- name: Tag 2 + slug: tag-2 + color: Cyan +- name: Tag 3 + slug: tag-3 + color: Grey +- name: Tag 4 + slug: tag-4 + color: Teal diff --git a/.devcontainer/initializers/tenant_groups.yml b/.devcontainer/initializers/tenant_groups.yml new file mode 100644 index 0000000..a535b25 --- /dev/null +++ b/.devcontainer/initializers/tenant_groups.yml @@ -0,0 +1,4 @@ +- name: Tenant Group 1 + slug: tenant-group-1 +- name: Tenant Group 2 + slug: tenant-group-2 diff --git a/.devcontainer/initializers/tenants.yml b/.devcontainer/initializers/tenants.yml new file mode 100644 index 0000000..fd63d1c --- /dev/null +++ b/.devcontainer/initializers/tenants.yml @@ -0,0 +1,5 @@ +- name: tenant1 + slug: tenant1 +- name: tenant2 + slug: tenant2 + group: Tenant Group 2 diff --git a/.devcontainer/initializers/users.yml b/.devcontainer/initializers/users.yml new file mode 100644 index 0000000..cf08c36 --- /dev/null +++ b/.devcontainer/initializers/users.yml @@ -0,0 +1,6 @@ +admin: + api_token: 0123456789admin789abcdef01234567admin + is_active: True + is_staff: True + is_superuser: True + password: admin diff --git a/.devcontainer/initializers/virtual_machines.yml b/.devcontainer/initializers/virtual_machines.yml new file mode 100644 index 0000000..bedd8f0 --- /dev/null +++ b/.devcontainer/initializers/virtual_machines.yml @@ -0,0 +1,28 @@ +#Possible Choices: +# status: +# - active +# - offline +# - staged +## +#Examples: + +- cluster: cluster1 + comments: VM1 + disk: 200 + memory: 4096 + name: virtual machine 1 + platform: Platform 2 + status: active + tenant: tenant1 + vcpus: 8 +- cluster: cluster1 + comments: VM2 + disk: 100 + memory: 2048 + name: virtual machine 2 + platform: Platform 2 + primary_ip4: 10.1.1.10/24 + primary_ip6: 2001:db8:a000:1::10/64 + status: active + tenant: tenant1 + vcpus: 8 diff --git a/.devcontainer/initializers/virtualization_interfaces.yml b/.devcontainer/initializers/virtualization_interfaces.yml new file mode 100644 index 0000000..29e9965 --- /dev/null +++ b/.devcontainer/initializers/virtualization_interfaces.yml @@ -0,0 +1,12 @@ +- description: Network Interface 1 + enabled: true + mac_address: 00:77:77:77:77:77 + mtu: 1500 + name: Network Interface 1 + virtual_machine: virtual machine 1 +- description: Network Interface 2 + enabled: true + mac_address: 00:55:55:55:55:55 + mtu: 1500 + name: Network Interface 2 + virtual_machine: virtual machine 1 diff --git a/.devcontainer/initializers/vlan_groups.yml b/.devcontainer/initializers/vlan_groups.yml new file mode 100644 index 0000000..c385b44 --- /dev/null +++ b/.devcontainer/initializers/vlan_groups.yml @@ -0,0 +1,24 @@ +- name: VLAN group 1 + scope_type: dcim.region + scope: Amsterdam + slug: vlan-group-1 +- name: VLAN group 2 + scope_type: dcim.site + scope: AMS 1 + slug: vlan-group-2 +- name: VLAN group 3 + scope_type: dcim.location + scope: cage 101 + slug: vlan-group-3 +- name: VLAN group 4 + scope_type: dcim.rack + scope: rack-01 + slug: vlan-group-4 +- name: VLAN group 5 + scope_type: virtualization.cluster + scope: cluster1 + slug: vlan-group-5 +- name: VLAN group 6 + scope_type: virtualization.clustergroup + scope: Group 1 + slug: vlan-group-6 diff --git a/.devcontainer/initializers/vlans.yml b/.devcontainer/initializers/vlans.yml new file mode 100644 index 0000000..c4e1706 --- /dev/null +++ b/.devcontainer/initializers/vlans.yml @@ -0,0 +1,19 @@ +#Possible Choices: +# status: +# - active +# - reserved +# - deprecated +## +#Examples: + +- name: vlan1 + site: AMS 1 + status: active + vid: 5 + role: Main Management + description: VLAN 5 for MGMT +- group: VLAN group 2 + name: vlan2 + site: AMS 1 + status: active + vid: 1300 diff --git a/.devcontainer/initializers/vrfs.yml b/.devcontainer/initializers/vrfs.yml new file mode 100644 index 0000000..6f91b90 --- /dev/null +++ b/.devcontainer/initializers/vrfs.yml @@ -0,0 +1,8 @@ +- enforce_unique: true + name: vrf1 + tenant: tenant1 + description: main VRF +- enforce_unique: true + name: vrf2 + rd: "6500:6500" + tenant: tenant2 diff --git a/.devcontainer/initializers/webhooks.yml b/.devcontainer/initializers/webhooks.yml new file mode 100644 index 0000000..ce21fda --- /dev/null +++ b/.devcontainer/initializers/webhooks.yml @@ -0,0 +1,27 @@ +#Possible Choices: +# object_types: +# - device +# - site +# - any-other-content-type +# types: +# - type_create +# - type_update +# - type_delete +#Examples: + +- name: device_creation + payload_url: 'http://localhost:8080' + object_types: + - device + - cable + type_create: True +- name: device_update + payload_url: 'http://localhost:8080' + object_types: + - device + type_update: True +- name: device_delete + payload_url: 'http://localhost:8080' + object_types: + - device + type_delete: True diff --git a/.devcontainer/requirements-dev.txt b/.devcontainer/requirements-dev.txt new file mode 100644 index 0000000..9f60b96 --- /dev/null +++ b/.devcontainer/requirements-dev.txt @@ -0,0 +1,11 @@ +autopep8 +bandit +black +flake8 +isort +mypy +pre-commit +pycodestyle +pydocstyle +pylint +yapf diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7059dd0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,163 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/#use-with-ide +.pdm.toml + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +#.env +.venv +#env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ + +# VS Code +.vscode/ diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..4655193 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,57 @@ +repos: + - repo: 'https://github.com/pre-commit/pre-commit-hooks' + rev: v4.3.0 + hooks: + - id: trailing-whitespace + - id: end-of-file-fixer + - id: check-yaml + - id: check-merge-conflict + - id: debug-statements + - id: name-tests-test + - id: requirements-txt-fixer + - id: check-docstring-first + - repo: 'https://github.com/asottile/add-trailing-comma' + rev: v2.2.3 + hooks: + - id: add-trailing-comma + args: + - '--py36-plus' + - repo: 'https://github.com/asottile/pyupgrade' + rev: v2.34.0 + hooks: + - id: pyupgrade + args: + - '--py37-plus' + - repo: 'https://github.com/PyCQA/isort' + rev: 5.10.1 + hooks: + - id: isort + args: + - '--filter-files' + - repo: 'https://github.com/psf/black' + rev: 22.6.0 + hooks: + - id: black + language_version: python3 + #- repo: 'https://github.com/adrienverge/yamllint' + # rev: v1.26.3 + # hooks: + # - id: yamllint + - repo: 'https://github.com/psf/black' + rev: 22.6.0 + hooks: + - id: black + - repo: 'https://github.com/igorshubovych/markdownlint-cli' + rev: v0.31.1 + hooks: + - id: markdownlint + - repo: local + hooks: + - repo: local + hooks: + - id: wily + name: wily + entry: wily diff + verbose: true + language: python + additional_dependencies: [wily] diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..2012c6b --- /dev/null +++ b/Makefile @@ -0,0 +1,82 @@ +PLUGIN_NAME=netbox_access_lists +REPO_PATH=/opt/netbox/netbox/netbox-access-lists +VENV_PY_PATH=/opt/netbox/venv/bin/python3 +NETBOX_MANAGE_PATH=/opt/netbox/netbox/manage.py +VERFILE=./version.py + +.PHONY: help +help: ## Display help message + @grep -E '^[0-9a-zA-Z_-]+\.*[0-9a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' + +################# +# DOCKER # +################# + +# Outside of Devcontainer + +.PHONY: cleanup +cleanup: ## Clean associated docker resources. + -docker-compose -p netbox-access-lists_devcontainer rm -fv + +################## +# PLUGIN DEV # +################## + +# in VS Code Devcontianer + +.PHONY: setup +setup: ## Copy plugin settings. Setup NetBox plugin. + -${VENV_PY_PATH} -m pip install --disable-pip-version-check --no-cache-dir -e ${REPO_PATH} +#-python3 setup.py develop + +.PHONY: makemigrations +makemigrations: ## Run makemigrations + -${VENV_PY_PATH} ${NETBOX_MANAGE_PATH} makemigrations --name ${PLUGIN_NAME} + +.PHONY: migrate +migrate: ## Run migrate + -${VENV_PY_PATH} ${NETBOX_MANAGE_PATH} migrate + +.PHONY: startup_scripts +startup_scripts: + -echo "import runpy; runpy.run_path('/opt/netbox/startup_scripts')" | ${NETBOX_MANAGE_PATH} shell --interface python + +.PHONY: collectstatic +collectstatic: + -${VENV_PY_PATH} ${NETBOX_MANAGE_PATH} collectstatic --no-input + +.PHONY: start +start: ## Start NetBox + -${VENV_PY_PATH} ${NETBOX_MANAGE_PATH} runserver + +.PHONY: all +all: setup makemigrations migrate collectstatic startup_scripts start ## Run all PLUGIN DEV targets + +#.PHONY: test +#test: +# ${VENV_PY_PATH} /opt/netbox/netbox/manage.py runserver test ${PLUGIN_NAME} + +#relpatch: +# $(eval GSTATUS := $(shell git status --porcelain)) +#ifneq ($(GSTATUS),) +# $(error Git status is not clean. $(GSTATUS)) +#endif +# git checkout develop +# git remote update +# git pull origin develop +# $(eval CURVER := $(shell cat $(VERFILE) | grep -oE '[0-9]+\.[0-9]+\.[0-9]+')) +# $(eval NEWVER := $(shell pysemver bump patch $(CURVER))) +# $(eval RDATE := $(shell date '+%Y-%m-%d')) +# git checkout -b release-$(NEWVER) origin/develop +# echo '__version__ = "$(NEWVER)"' > $(VERFILE) +# git commit -am 'bump ver' +# git push origin release-$(NEWVER) +# git checkout develop + +#pbuild: +# ${VENV_PY_PATH} -m pip install --upgrade build +# ${VENV_PY_PATH} -m build +# +#pypipub: +# ${VENV_PY_PATH} -m pip install --upgrade twine +# ${VENV_PY_PATH} -m twine upload dist/* diff --git a/TODO b/TODO new file mode 100644 index 0000000..6319ddc --- /dev/null +++ b/TODO @@ -0,0 +1,4 @@ +- https://code.visualstudio.com/remote/advancedcontainers/connect-multiple-containers +- docker from docker +- slim down netbox-docker +- make diff --git a/netbox_access_lists/version.py b/netbox_access_lists/version.py new file mode 100644 index 0000000..6c8e6b9 --- /dev/null +++ b/netbox_access_lists/version.py @@ -0,0 +1 @@ +__version__ = "0.0.0" diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..d3e69f4 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,29 @@ +[tool.black] +line-length = 100 + +[tool.pylint] + +[tool.pylint.format] +max-line-length = 100 + +[tool.pylint.master] +# pylint defaults + fh for with open .. as (f|fh) +good-names = "i,j,k,ex,Run,_,f,fh" +no-docstring-rgx = "__.*__" + +[tool.pylint.messages_control] +# missing module docstring will be picked up by pydocstyle +# could not do infile b/c older version of pylint didn't have it +# and ansible-test sanity uses older version in earlier ansible +# pointless-string-statement allows for attribute docstring in dataclasses +disable = [ + "duplicate-code", + "fixme", + "missing-module-docstring", + "pointless-string-statement", + "too-few-public-methods", + "unsubscriptable-object", +] +enable = [ + "useless-suppression", # Identify unneeded pylint disable statements +] diff --git a/setup.py b/setup.py index 0e40846..9af2d7e 100644 --- a/setup.py +++ b/setup.py @@ -1,9 +1,36 @@ +#import codecs +#import os.path +# from setuptools import find_packages, setup +# +# +#with open("README.md", "r") as fh: +# long_description = fh.read() +# +# +#def read(rel_path): +# here = os.path.abspath(os.path.dirname(__file__)) +# with codecs.open(os.path.join(here, rel_path), 'r') as fp: +# return fp.read() +# +# +#def get_version(rel_path): +# for line in read(rel_path).splitlines(): +# if line.startswith('__version__'): +# delim = '"' if '"' in line else "'" +# return line.split(delim)[1] +# else: +# raise RuntimeError("Unable to find version string.") +# setup( name='netbox-access-lists', - version='0.2', + version='0.1.0', + #version=get_version('netbox_access_lists/version.py'), description='A NetBox plugin for Access-List management', + #long_description=long_description, + long_description_content_type="text/markdown", + url='https://github.com/ryanmerolle/netbox-access-lists', install_requires=[], packages=find_packages(), include_package_data=True,