Merge pull request #427 from netbox-community/AddEditorconfig

Introduce Linting-Step in Build
This commit is contained in:
Christian Mäder 2021-02-10 12:35:48 +01:00 committed by GitHub
commit f7337ed1e9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
73 changed files with 1118 additions and 1013 deletions

23
.ecrc Normal file
View File

@ -0,0 +1,23 @@
{
"Verbose": false,
"Debug": false,
"IgnoreDefaults": false,
"SpacesAftertabs": false,
"NoColor": false,
"Exclude": [
"LICENSE",
"\\.initializers",
"\\.vscode"
],
"AllowedContentTypes": [],
"PassedFiles": [],
"Disable": {
// set these options to true to disable specific checks
"EndOfLine": false,
"Indentation": false,
"InsertFinalNewline": false,
"TrimTrailingWhitespace": false,
"IndentSize": true,
"MaxLineLength": false
}
}

11
.editorconfig Normal file
View File

@ -0,0 +1,11 @@
root = true
[*]
end_of_line = lf
insert_final_newline = true
charset = utf-8
indent_style = space
indent_size = 2
[*.py]
indent_size = 4

7
.flake8 Normal file
View File

@ -0,0 +1,7 @@
[flake8]
max-line-length = 100
extend-ignore = E203, W503
per-file-ignores =
configuration/*:E131,E251,E266,E302,E305,E501,E722
startup_scripts/startup_script_utils/__init__.py:F401
docker/*:E266,E722

View File

@ -9,6 +9,29 @@ on:
- release - release
jobs: jobs:
lint:
runs-on: ubuntu-latest
name: Checks syntax of our code
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
- name: Lint Code Base
uses: github/super-linter@v3
env:
DEFAULT_BRANCH: develop
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SUPPRESS_POSSUM: true
LINTER_RULES_PATH: /
VALIDATE_ALL_CODEBASE: false
VALIDATE_DOCKERFILE: false
FILTER_REGEX_EXCLUDE: (.*/)?(LICENSE|configuration/.*)
EDITORCONFIG_FILE_NAME: .ecrc
DOCKERFILE_HADOLINT_FILE_NAME: .hadolint.yaml
MARKDOWN_CONFIG_FILE: .markdown-lint.yml
PYTHON_BLACK_CONFIG_FILE: pyproject.toml
PYTHON_FLAKE8_CONFIG_FILE: .flake8
PYTHON_ISORT_CONFIG_FILE: pyproject.toml
build: build:
continue-on-error: ${{ matrix.docker_from == 'alpine:edge' }} continue-on-error: ${{ matrix.docker_from == 'alpine:edge' }}
strategy: strategy:

1
.gitignore vendored
View File

@ -9,3 +9,4 @@ configuration/*
configuration/ldap/* configuration/ldap/*
!configuration/ldap/ldap_config.py !configuration/ldap/ldap_config.py
prometheus.yml prometheus.yml
super-linter.log

3
.hadolint.yaml Normal file
View File

@ -0,0 +1,3 @@
ignored:
- DL3006
- DL3018

2
.markdown-lint.yml Normal file
View File

@ -0,0 +1,2 @@
MD013: false
MD041: false

View File

@ -18,8 +18,8 @@ RUN apk add --no-cache \
postgresql-dev \ postgresql-dev \
py3-pip \ py3-pip \
python3-dev \ python3-dev \
&& python3 -m venv /opt/netbox/venv \ && python3 -m venv /opt/netbox/venv \
&& /opt/netbox/venv/bin/python3 -m pip install --upgrade \ && /opt/netbox/venv/bin/python3 -m pip install --upgrade \
pip \ pip \
setuptools \ setuptools \
wheel wheel

View File

@ -5,4 +5,4 @@ push_image_to_registry() {
echo "⏫ Pushing '${target_tag}'" echo "⏫ Pushing '${target_tag}'"
$DRY docker push "${target_tag}" $DRY docker push "${target_tag}"
echo "✅ Finished pushing the Docker image '${target_tag}'." echo "✅ Finished pushing the Docker image '${target_tag}'."
} }

View File

@ -45,16 +45,16 @@ _get_image_configuration() {
--silent \ --silent \
--location \ --location \
--header "Authorization: Bearer $token" \ --header "Authorization: Bearer $token" \
"https://registry-1.docker.io/v2/$image/blobs/$digest" \ "https://registry-1.docker.io/v2/$image/blobs/$digest" |
| jq -r ".config.Labels.\"$label\"" jq -r ".config.Labels.\"$label\""
} }
_get_token() { _get_token() {
local image=$1 local image=$1
curl \ curl \
--silent \ --silent \
"https://auth.docker.io/token?scope=repository:$image:pull&service=registry.docker.io" \ "https://auth.docker.io/token?scope=repository:$image:pull&service=registry.docker.io" |
| jq -r '.token' jq -r '.token'
} }
_get_digest() { _get_digest() {
@ -65,8 +65,8 @@ _get_digest() {
--silent \ --silent \
--header "Accept: application/vnd.docker.distribution.manifest.v2+json" \ --header "Accept: application/vnd.docker.distribution.manifest.v2+json" \
--header "Authorization: Bearer $token" \ --header "Authorization: Bearer $token" \
"https://registry-1.docker.io/v2/$image/manifests/$tag" \ "https://registry-1.docker.io/v2/$image/manifests/$tag" |
| jq -r '.config.digest' jq -r '.config.digest'
} }
_get_layers() { _get_layers() {
@ -77,6 +77,6 @@ _get_layers() {
--silent \ --silent \
--header "Accept: application/vnd.docker.distribution.manifest.v2+json" \ --header "Accept: application/vnd.docker.distribution.manifest.v2+json" \
--header "Authorization: Bearer $token" \ --header "Authorization: Bearer $token" \
"https://registry-1.docker.io/v2/$image/manifests/$tag" \ "https://registry-1.docker.io/v2/$image/manifests/$tag" |
| jq -r '.layers[].digest' jq -r '.layers[].digest'
} }

View File

@ -19,7 +19,7 @@ fi
# Checking if PRERELEASE is either unset, 'true' or 'false' # Checking if PRERELEASE is either unset, 'true' or 'false'
### ###
if [ -n "${PRERELEASE}" ] && if [ -n "${PRERELEASE}" ] &&
{ [ "${PRERELEASE}" != "true" ] && [ "${PRERELEASE}" != "false" ]; }; then { [ "${PRERELEASE}" != "true" ] && [ "${PRERELEASE}" != "false" ]; }; then
if [ -z "${DEBUG}" ]; then if [ -z "${DEBUG}" ]; then
echo "⚠️ PRERELEASE must be either unset, 'true' or 'false', but was '${PRERELEASE}'!" echo "⚠️ PRERELEASE must be either unset, 'true' or 'false', but was '${PRERELEASE}'!"
@ -60,9 +60,10 @@ if [ "${PRERELEASE}" == "true" ]; then
# shellcheck disable=SC2003 # shellcheck disable=SC2003
MINOR_UNSTABLE=$(expr match "${VERSION}" 'v[0-9]\+\.\([0-9]\+\)') MINOR_UNSTABLE=$(expr match "${VERSION}" 'v[0-9]\+\.\([0-9]\+\)')
if { [ "${MAJOR_STABLE}" -eq "${MAJOR_UNSTABLE}" ] \ if {
&& [ "${MINOR_STABLE}" -ge "${MINOR_UNSTABLE}" ]; [ "${MAJOR_STABLE}" -eq "${MAJOR_UNSTABLE}" ] &&
} || [ "${MAJOR_STABLE}" -gt "${MAJOR_UNSTABLE}" ]; then [ "${MINOR_STABLE}" -ge "${MINOR_UNSTABLE}" ]
} || [ "${MAJOR_STABLE}" -gt "${MAJOR_UNSTABLE}" ]; then
echo "❎ Latest unstable version '${VERSION}' is not higher than the latest stable version '$STABLE_VERSION'." echo "❎ Latest unstable version '${VERSION}' is not higher than the latest stable version '$STABLE_VERSION'."
if [ -z "$DEBUG" ]; then if [ -z "$DEBUG" ]; then

View File

@ -117,7 +117,7 @@ NETBOX_PATH="${NETBOX_PATH-.netbox}"
### ###
# Fetching the NetBox source # Fetching the NetBox source
### ###
if [ "${2}" != "--push-only" ] && [ -z "${SKIP_GIT}" ] ; then if [ "${2}" != "--push-only" ] && [ -z "${SKIP_GIT}" ]; then
echo "🌐 Checking out '${NETBOX_BRANCH}' of NetBox from the url '${URL}' into '${NETBOX_PATH}'" echo "🌐 Checking out '${NETBOX_BRANCH}' of NetBox from the url '${URL}' into '${NETBOX_PATH}'"
if [ ! -d "${NETBOX_PATH}" ]; then if [ ! -d "${NETBOX_PATH}" ]; then
$DRY git clone -q --depth 10 -b "${NETBOX_BRANCH}" "${URL}" "${NETBOX_PATH}" $DRY git clone -q --depth 10 -b "${NETBOX_BRANCH}" "${URL}" "${NETBOX_PATH}"
@ -174,9 +174,18 @@ PROJECT_VERSION="${PROJECT_VERSION-$(sed -e 's/^[[:space:]]*//' -e 's/[[:space:]
# Get the Git information from the netbox directory # Get the Git information from the netbox directory
if [ -d "${NETBOX_PATH}/.git" ]; then if [ -d "${NETBOX_PATH}/.git" ]; then
NETBOX_GIT_REF=$(cd "${NETBOX_PATH}"; git rev-parse HEAD) NETBOX_GIT_REF=$(
NETBOX_GIT_BRANCH=$(cd "${NETBOX_PATH}"; git rev-parse --abbrev-ref HEAD) cd "${NETBOX_PATH}"
NETBOX_GIT_URL=$(cd "${NETBOX_PATH}"; git remote get-url origin) git rev-parse HEAD
)
NETBOX_GIT_BRANCH=$(
cd "${NETBOX_PATH}"
git rev-parse --abbrev-ref HEAD
)
NETBOX_GIT_URL=$(
cd "${NETBOX_PATH}"
git remote get-url origin
)
fi fi
### ###
@ -186,19 +195,22 @@ DOCKER_REGISTRY="${DOCKER_REGISTRY-docker.io}"
DOCKER_ORG="${DOCKER_ORG-netboxcommunity}" DOCKER_ORG="${DOCKER_ORG-netboxcommunity}"
DOCKER_REPO="${DOCKER_REPO-netbox}" DOCKER_REPO="${DOCKER_REPO-netbox}"
case "${NETBOX_BRANCH}" in case "${NETBOX_BRANCH}" in
master) master)
TAG="${TAG-latest}";; TAG="${TAG-latest}"
develop) ;;
TAG="${TAG-snapshot}";; develop)
*) TAG="${TAG-snapshot}"
TAG="${TAG-$NETBOX_BRANCH}";; ;;
*)
TAG="${TAG-$NETBOX_BRANCH}"
;;
esac esac
### ###
# Determine targets to build # Determine targets to build
### ###
DEFAULT_DOCKER_TARGETS=("main" "ldap") DEFAULT_DOCKER_TARGETS=("main" "ldap")
DOCKER_TARGETS=( "${DOCKER_TARGET:-"${DEFAULT_DOCKER_TARGETS[@]}"}") DOCKER_TARGETS=("${DOCKER_TARGET:-"${DEFAULT_DOCKER_TARGETS[@]}"}")
echo "🏭 Building the following targets:" "${DOCKER_TARGETS[@]}" echo "🏭 Building the following targets:" "${DOCKER_TARGETS[@]}"
### ###
@ -216,7 +228,7 @@ for DOCKER_TARGET in "${DOCKER_TARGETS[@]}"; do
TARGET_DOCKER_TAG="${TARGET_DOCKER_TAG}-${DOCKER_TARGET}" TARGET_DOCKER_TAG="${TARGET_DOCKER_TAG}-${DOCKER_TARGET}"
fi fi
if [ -n "${GH_ACTION}" ]; then if [ -n "${GH_ACTION}" ]; then
echo "FINAL_DOCKER_TAG=${TARGET_DOCKER_TAG}" >> $GITHUB_ENV echo "FINAL_DOCKER_TAG=${TARGET_DOCKER_TAG}" >>"$GITHUB_ENV"
echo "::set-output name=skipped::false" echo "::set-output name=skipped::false"
fi fi
@ -242,7 +254,7 @@ for DOCKER_TARGET in "${DOCKER_TARGETS[@]}"; do
### ###
# Proceeding to buils stage, except if `--push-only` is passed # Proceeding to buils stage, except if `--push-only` is passed
### ###
if [ "${2}" != "--push-only" ] ; then if [ "${2}" != "--push-only" ]; then
### ###
# Checking if the build is necessary, # Checking if the build is necessary,
# meaning build only if one of those values changed: # meaning build only if one of those values changed:
@ -259,7 +271,7 @@ for DOCKER_TARGET in "${DOCKER_TARGETS[@]}"; do
BUILD_REASON="${BUILD_REASON} interactive" BUILD_REASON="${BUILD_REASON} interactive"
elif [ "$DOCKER_REGISTRY" = "docker.io" ]; then elif [ "$DOCKER_REGISTRY" = "docker.io" ]; then
source ./build-functions/get-public-image-config.sh source ./build-functions/get-public-image-config.sh
IFS=':' read -ra DOCKER_FROM_SPLIT <<< "${DOCKER_FROM}" IFS=':' read -ra DOCKER_FROM_SPLIT <<<"${DOCKER_FROM}"
if ! [[ ${DOCKER_FROM_SPLIT[0]} =~ .*/.* ]]; then if ! [[ ${DOCKER_FROM_SPLIT[0]} =~ .*/.* ]]; then
# Need to use "library/..." for images the have no two part name # Need to use "library/..." for images the have no two part name
DOCKER_FROM_SPLIT[0]="library/${DOCKER_FROM_SPLIT[0]}" DOCKER_FROM_SPLIT[0]="library/${DOCKER_FROM_SPLIT[0]}"
@ -295,8 +307,8 @@ for DOCKER_TARGET in "${DOCKER_TARGETS[@]}"; do
-t "${TARGET_DOCKER_TAG}" -t "${TARGET_DOCKER_TAG}"
) )
if [ -n "${TARGET_DOCKER_SHORT_TAG}" ]; then if [ -n "${TARGET_DOCKER_SHORT_TAG}" ]; then
DOCKER_BUILD_ARGS+=( -t "${TARGET_DOCKER_SHORT_TAG}" ) DOCKER_BUILD_ARGS+=(-t "${TARGET_DOCKER_SHORT_TAG}")
DOCKER_BUILD_ARGS+=( -t "${TARGET_DOCKER_LATEST_TAG}" ) DOCKER_BUILD_ARGS+=(-t "${TARGET_DOCKER_LATEST_TAG}")
fi fi
# --label # --label
@ -323,22 +335,22 @@ for DOCKER_TARGET in "${DOCKER_TARGETS[@]}"; do
) )
fi fi
if [ -n "${BUILD_REASON}" ]; then if [ -n "${BUILD_REASON}" ]; then
BUILD_REASON=$(sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//' <<< "$BUILD_REASON") BUILD_REASON=$(sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//' <<<"$BUILD_REASON")
DOCKER_BUILD_ARGS+=( --label "BUILD_REASON=${BUILD_REASON}" ) DOCKER_BUILD_ARGS+=(--label "BUILD_REASON=${BUILD_REASON}")
fi fi
# --build-arg # --build-arg
DOCKER_BUILD_ARGS+=( --build-arg "NETBOX_PATH=${NETBOX_PATH}" ) DOCKER_BUILD_ARGS+=(--build-arg "NETBOX_PATH=${NETBOX_PATH}")
if [ -n "${DOCKER_FROM}" ]; then if [ -n "${DOCKER_FROM}" ]; then
DOCKER_BUILD_ARGS+=( --build-arg "FROM=${DOCKER_FROM}" ) DOCKER_BUILD_ARGS+=(--build-arg "FROM=${DOCKER_FROM}")
fi fi
if [ -n "${HTTP_PROXY}" ]; then if [ -n "${HTTP_PROXY}" ]; then
DOCKER_BUILD_ARGS+=( --build-arg "http_proxy=${HTTP_PROXY}" ) DOCKER_BUILD_ARGS+=(--build-arg "http_proxy=${HTTP_PROXY}")
DOCKER_BUILD_ARGS+=( --build-arg "https_proxy=${HTTPS_PROXY}" ) DOCKER_BUILD_ARGS+=(--build-arg "https_proxy=${HTTPS_PROXY}")
fi fi
if [ -n "${NO_PROXY}" ]; then if [ -n "${NO_PROXY}" ]; then
DOCKER_BUILD_ARGS+=( --build-arg "no_proxy=${NO_PROXY}" ) DOCKER_BUILD_ARGS+=(--build-arg "no_proxy=${NO_PROXY}")
fi fi
### ###
@ -360,7 +372,7 @@ for DOCKER_TARGET in "${DOCKER_TARGETS[@]}"; do
### ###
# Pushing the docker images if either `--push` or `--push-only` are passed # Pushing the docker images if either `--push` or `--push-only` are passed
### ###
if [ "${2}" == "--push" ] || [ "${2}" == "--push-only" ] ; then if [ "${2}" == "--push" ] || [ "${2}" == "--push-only" ]; then
source ./build-functions/docker-functions.sh source ./build-functions/docker-functions.sh
push_image_to_registry "${TARGET_DOCKER_TAG}" push_image_to_registry "${TARGET_DOCKER_TAG}"

View File

@ -5,9 +5,8 @@
#### ####
import re import re
from os.path import dirname, abspath, join
from os import environ from os import environ
from os.path import abspath, dirname, join
# For reference see https://netbox.readthedocs.io/en/stable/configuration/ # 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 # Based on https://github.com/netbox-community/netbox/blob/master/netbox/netbox/configuration.example.py
@ -39,16 +38,16 @@ ALLOWED_HOSTS = environ.get('ALLOWED_HOSTS', '*').split(' ')
# PostgreSQL database configuration. See the Django documentation for a complete list of available parameters: # PostgreSQL database configuration. See the Django documentation for a complete list of available parameters:
# https://docs.djangoproject.com/en/stable/ref/settings/#databases # https://docs.djangoproject.com/en/stable/ref/settings/#databases
DATABASE = { DATABASE = {
'NAME': environ.get('DB_NAME', 'netbox'), # Database name 'NAME': environ.get('DB_NAME', 'netbox'), # Database name
'USER': environ.get('DB_USER', ''), # PostgreSQL username 'USER': environ.get('DB_USER', ''), # PostgreSQL username
'PASSWORD': _read_secret('db_password', environ.get('DB_PASSWORD', '')), 'PASSWORD': _read_secret('db_password', environ.get('DB_PASSWORD', '')),
# PostgreSQL password # PostgreSQL password
'HOST': environ.get('DB_HOST', 'localhost'), # Database server 'HOST': environ.get('DB_HOST', 'localhost'), # Database server
'PORT': environ.get('DB_PORT', ''), # Database port (leave blank for default) 'PORT': environ.get('DB_PORT', ''), # Database port (leave blank for default)
'OPTIONS': {'sslmode': environ.get('DB_SSLMODE', 'prefer')}, 'OPTIONS': {'sslmode': environ.get('DB_SSLMODE', 'prefer')},
# Database connection SSLMODE # Database connection SSLMODE
'CONN_MAX_AGE': int(environ.get('DB_CONN_MAX_AGE', '300')), 'CONN_MAX_AGE': int(environ.get('DB_CONN_MAX_AGE', '300')),
# Max database connection age # Max database connection age
} }
# Redis database settings. Redis is used for caching and for queuing background tasks such as webhook events. A separate # Redis database settings. Redis is used for caching and for queuing background tasks such as webhook events. A separate

View File

@ -1,9 +1,10 @@
import ldap
from django_auth_ldap.config import LDAPSearch
from importlib import import_module from importlib import import_module
from os import environ from os import environ
import ldap
from django_auth_ldap.config import LDAPSearch
# Read secret from file # Read secret from file
def _read_secret(secret_name, default=None): def _read_secret(secret_name, default=None):
try: try:
@ -47,9 +48,11 @@ LDAP_IGNORE_CERT_ERRORS = environ.get('LDAP_IGNORE_CERT_ERRORS', 'False').lower(
AUTH_LDAP_USER_SEARCH_BASEDN = environ.get('AUTH_LDAP_USER_SEARCH_BASEDN', '') 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_ATTR = environ.get('AUTH_LDAP_USER_SEARCH_ATTR', 'sAMAccountName')
AUTH_LDAP_USER_SEARCH = LDAPSearch(AUTH_LDAP_USER_SEARCH_BASEDN, AUTH_LDAP_USER_SEARCH = LDAPSearch(
ldap.SCOPE_SUBTREE, AUTH_LDAP_USER_SEARCH_BASEDN,
"(" + AUTH_LDAP_USER_SEARCH_ATTR + "=%(user)s)") ldap.SCOPE_SUBTREE,
"(" + AUTH_LDAP_USER_SEARCH_ATTR + "=%(user)s)"
)
# This search ought to return all groups to which the user belongs. django_auth_ldap uses this to determine group # This search ought to return all groups to which the user belongs. django_auth_ldap uses this to determine group
# heirarchy. # heirarchy.

View File

@ -4,58 +4,58 @@
# #
# They can be imported by other code (see `ldap_config.py` for an example). # They can be imported by other code (see `ldap_config.py` for an example).
from os.path import abspath, isfile
from os import scandir
import importlib.util import importlib.util
import sys import sys
from os import scandir
from os.path import abspath, isfile
def _filename(f): def _filename(f):
return f.name return f.name
def _import(module_name, path, loaded_configurations): def _import(module_name, path, loaded_configurations):
spec = importlib.util.spec_from_file_location('', path) spec = importlib.util.spec_from_file_location("", path)
module = importlib.util.module_from_spec(spec) module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module) spec.loader.exec_module(module)
sys.modules[module_name] = module sys.modules[module_name] = module
loaded_configurations.insert(0, module) loaded_configurations.insert(0, module)
print(f"🧬 loaded config '{path}'") print(f"🧬 loaded config '{path}'")
def read_configurations(config_module, config_dir, main_config): def read_configurations(config_module, config_dir, main_config):
loaded_configurations = [] loaded_configurations = []
main_config_path = abspath(f'{config_dir}/{main_config}.py') main_config_path = abspath(f"{config_dir}/{main_config}.py")
if isfile(main_config_path): if isfile(main_config_path):
_import(f'{config_module}.{main_config}', main_config_path, loaded_configurations) _import(f"{config_module}.{main_config}", main_config_path, loaded_configurations)
else: else:
print(f"⚠️ Main configuration '{main_config_path}' not found.") print(f"⚠️ Main configuration '{main_config_path}' not found.")
with scandir(config_dir) as it: with scandir(config_dir) as it:
for f in sorted(it, key=_filename): for f in sorted(it, key=_filename):
if not f.is_file(): if not f.is_file():
continue continue
if f.name.startswith('__'): if f.name.startswith("__"):
continue continue
if not f.name.endswith('.py'): if not f.name.endswith(".py"):
continue continue
if f.name == f'{config_dir}.py': if f.name == f"{config_dir}.py":
continue continue
module_name = f"{config_module}.{f.name[:-len('.py')]}".replace(".", "_") module_name = f"{config_module}.{f.name[:-len('.py')]}".replace(".", "_")
_import(module_name, f.path, loaded_configurations) _import(module_name, f.path, loaded_configurations)
if len(loaded_configurations) == 0: if len(loaded_configurations) == 0:
print(f"‼️ No configuration files found in '{config_dir}'.") print(f"‼️ No configuration files found in '{config_dir}'.")
raise ImportError(f"No configuration files found in '{config_dir}'.") raise ImportError(f"No configuration files found in '{config_dir}'.")
return loaded_configurations return loaded_configurations
## Specific Parts ## Specific Parts
@ -66,15 +66,16 @@ def read_configurations(config_module, config_dir, main_config):
_loaded_configurations = read_configurations( _loaded_configurations = read_configurations(
config_dir = '/etc/netbox/config/', config_dir="/etc/netbox/config/",
config_module = 'netbox.configuration', config_module="netbox.configuration",
main_config = 'configuration') main_config="configuration",
)
def __getattr__(name): def __getattr__(name):
for config in _loaded_configurations: for config in _loaded_configurations:
try: try:
return getattr(config, name) return getattr(config, name)
except: except:
pass pass
raise AttributeError raise AttributeError

View File

@ -8,6 +8,7 @@ set -e
umask 002 umask 002
# Load correct Python3 env # Load correct Python3 env
# shellcheck disable=SC1091
source /opt/netbox/venv/bin/activate source /opt/netbox/venv/bin/activate
# Try to connect to the DB # Try to connect to the DB
@ -17,7 +18,7 @@ CUR_DB_WAIT_TIME=0
while ! ./manage.py migrate 2>&1 && [ "${CUR_DB_WAIT_TIME}" -lt "${MAX_DB_WAIT_TIME}" ]; do while ! ./manage.py migrate 2>&1 && [ "${CUR_DB_WAIT_TIME}" -lt "${MAX_DB_WAIT_TIME}" ]; do
echo "⏳ Waiting on DB... (${CUR_DB_WAIT_TIME}s / ${MAX_DB_WAIT_TIME}s)" echo "⏳ Waiting on DB... (${CUR_DB_WAIT_TIME}s / ${MAX_DB_WAIT_TIME}s)"
sleep "${DB_WAIT_TIMEOUT}" sleep "${DB_WAIT_TIMEOUT}"
CUR_DB_WAIT_TIME=$(( CUR_DB_WAIT_TIME + DB_WAIT_TIMEOUT )) CUR_DB_WAIT_TIME=$((CUR_DB_WAIT_TIME + DB_WAIT_TIMEOUT))
done done
if [ "${CUR_DB_WAIT_TIME}" -ge "${MAX_DB_WAIT_TIME}" ]; then if [ "${CUR_DB_WAIT_TIME}" -ge "${MAX_DB_WAIT_TIME}" ]; then
echo "❌ Waited ${MAX_DB_WAIT_TIME}s or more for the DB to become ready." echo "❌ Waited ${MAX_DB_WAIT_TIME}s or more for the DB to become ready."
@ -35,17 +36,17 @@ else
SUPERUSER_EMAIL='admin@example.com' SUPERUSER_EMAIL='admin@example.com'
fi fi
if [ -f "/run/secrets/superuser_password" ]; then if [ -f "/run/secrets/superuser_password" ]; then
SUPERUSER_PASSWORD="$(< /run/secrets/superuser_password)" SUPERUSER_PASSWORD="$(</run/secrets/superuser_password)"
elif [ -z ${SUPERUSER_PASSWORD+x} ]; then elif [ -z ${SUPERUSER_PASSWORD+x} ]; then
SUPERUSER_PASSWORD='admin' SUPERUSER_PASSWORD='admin'
fi fi
if [ -f "/run/secrets/superuser_api_token" ]; then if [ -f "/run/secrets/superuser_api_token" ]; then
SUPERUSER_API_TOKEN="$(< /run/secrets/superuser_api_token)" SUPERUSER_API_TOKEN="$(</run/secrets/superuser_api_token)"
elif [ -z ${SUPERUSER_API_TOKEN+x} ]; then elif [ -z ${SUPERUSER_API_TOKEN+x} ]; then
SUPERUSER_API_TOKEN='0123456789abcdef0123456789abcdef01234567' SUPERUSER_API_TOKEN='0123456789abcdef0123456789abcdef01234567'
fi fi
./manage.py shell --interface python << END ./manage.py shell --interface python <<END
from django.contrib.auth.models import User from django.contrib.auth.models import User
from users.models import Token from users.models import Token
if not User.objects.filter(username='${SUPERUSER_NAME}'): if not User.objects.filter(username='${SUPERUSER_NAME}'):

View File

@ -22,17 +22,18 @@ load_configuration() {
# this curl call will get a reply once unit is fully launched # this curl call will get a reply once unit is fully launched
curl --silent --output /dev/null --request GET --unix-socket $UNIT_SOCKET http://localhost/ curl --silent --output /dev/null --request GET --unix-socket $UNIT_SOCKET http://localhost/
echo "⚙️ Applying configuration from $UNIT_CONFIG"; echo "⚙️ Applying configuration from $UNIT_CONFIG"
RESP_CODE=$(curl \ RESP_CODE=$(
--silent \ curl \
--output /dev/null \ --silent \
--write-out '%{http_code}' \ --output /dev/null \
--request PUT \ --write-out '%{http_code}' \
--data-binary "@${UNIT_CONFIG}" \ --request PUT \
--unix-socket $UNIT_SOCKET \ --data-binary "@${UNIT_CONFIG}" \
http://localhost/config --unix-socket $UNIT_SOCKET \
) http://localhost/config
)
if [ "$RESP_CODE" != "200" ]; then if [ "$RESP_CODE" != "200" ]; then
echo "⚠️ Could no load Unit configuration" echo "⚠️ Could no load Unit configuration"
kill "$(cat /opt/unit/unit.pid)" kill "$(cat /opt/unit/unit.pid)"
@ -45,9 +46,9 @@ load_configuration() {
load_configuration & load_configuration &
exec unitd \ exec unitd \
--no-daemon \ --no-daemon \
--control unix:$UNIT_SOCKET \ --control unix:$UNIT_SOCKET \
--pid /opt/unit/unit.pid \ --pid /opt/unit/unit.pid \
--log /dev/stdout \ --log /dev/stdout \
--state /opt/unit/state/ \ --state /opt/unit/state/ \
--tmp /opt/unit/tmp/ --tmp /opt/unit/tmp/

View File

@ -1,21 +1,23 @@
from .configuration import read_configurations from .configuration import read_configurations
_loaded_configurations = read_configurations( _loaded_configurations = read_configurations(
config_dir = '/etc/netbox/config/ldap/', config_dir="/etc/netbox/config/ldap/",
config_module = 'netbox.configuration.ldap', config_module="netbox.configuration.ldap",
main_config = 'ldap_config') main_config="ldap_config",
)
def __getattr__(name): def __getattr__(name):
for config in _loaded_configurations: for config in _loaded_configurations:
try: try:
return getattr(config, name) return getattr(config, name)
except: except:
pass pass
raise AttributeError raise AttributeError
def __dir__(): def __dir__():
names = [] names = []
for config in _loaded_configurations: for config in _loaded_configurations:
names.extend(config.__dir__()) names.extend(config.__dir__())
return names return names

View File

@ -1,40 +1,40 @@
{ {
"listeners": { "listeners": {
"*:8080": { "*:8080": {
"pass": "routes" "pass": "routes"
} }
},
"routes": [
{
"match": {
"uri": "/static/*"
},
"action": {
"share": "/opt/netbox/netbox"
}
}, },
"routes": [ {
{ "action": {
"match": { "pass": "applications/netbox"
"uri": "/static/*" }
}, }
"action": { ],
"share": "/opt/netbox/netbox"
}
},
{ "applications": {
"action": { "netbox": {
"pass": "applications/netbox" "type": "python 3",
} "path": "/opt/netbox/netbox/",
} "module": "netbox.wsgi",
], "home": "/opt/netbox/venv",
"processes": {
"max": 4,
"spare": 1,
"idle_timeout": 120
}
}
},
"applications": { "access_log": "/dev/stdout"
"netbox": {
"type": "python 3",
"path": "/opt/netbox/netbox/",
"module": "netbox.wsgi",
"home": "/opt/netbox/venv",
"processes": {
"max": 4,
"spare": 1,
"idle_timeout": 120
}
}
},
"access_log": "/dev/stdout"
} }

38
env/netbox.env vendored
View File

@ -1,39 +1,39 @@
CORS_ORIGIN_ALLOW_ALL=True CORS_ORIGIN_ALLOW_ALL=True
DB_NAME=netbox
DB_USER=netbox
DB_PASSWORD=J5brHrAXFLQSif0K
DB_HOST=postgres DB_HOST=postgres
EMAIL_SERVER=localhost DB_NAME=netbox
EMAIL_PORT=25 DB_PASSWORD=J5brHrAXFLQSif0K
EMAIL_USERNAME=netbox DB_USER=netbox
EMAIL_PASSWORD=
EMAIL_TIMEOUT=5
EMAIL_FROM=netbox@bar.com 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 and EMAIL_USE_TLS are mutually exclusive, i.e. they can't both be `true`!
EMAIL_USE_SSL=false EMAIL_USE_SSL=false
EMAIL_USE_TLS=false EMAIL_USE_TLS=false
EMAIL_SSL_CERTFILE=
EMAIL_SSL_KEYFILE=
MAX_PAGE_SIZE=1000 MAX_PAGE_SIZE=1000
MEDIA_ROOT=/opt/netbox/netbox/media MEDIA_ROOT=/opt/netbox/netbox/media
METRICS_ENABLED=false METRICS_ENABLED=false
NAPALM_USERNAME=
NAPALM_PASSWORD= NAPALM_PASSWORD=
NAPALM_TIMEOUT=10 NAPALM_TIMEOUT=10
REDIS_HOST=redis NAPALM_USERNAME=
REDIS_PASSWORD=H733Kdjndks81 REDIS_CACHE_DATABASE=1
REDIS_DATABASE=0
REDIS_SSL=false
REDIS_CACHE_HOST=redis-cache REDIS_CACHE_HOST=redis-cache
REDIS_CACHE_PASSWORD=t4Ph722qJ5QHeQ1qfu36 REDIS_CACHE_PASSWORD=t4Ph722qJ5QHeQ1qfu36
REDIS_CACHE_DATABASE=1
REDIS_CACHE_SSL=false REDIS_CACHE_SSL=false
REDIS_DATABASE=0
REDIS_HOST=redis
REDIS_PASSWORD=H733Kdjndks81
REDIS_SSL=false
RELEASE_CHECK_URL=https://api.github.com/repos/netbox-community/netbox/releases RELEASE_CHECK_URL=https://api.github.com/repos/netbox-community/netbox/releases
SECRET_KEY=r8OwDznj!!dci#P9ghmRfdu1Ysxm0AiPeDCQhKE+N_rClfWNj SECRET_KEY=r8OwDznj!!dci#P9ghmRfdu1Ysxm0AiPeDCQhKE+N_rClfWNj
SKIP_STARTUP_SCRIPTS=false SKIP_STARTUP_SCRIPTS=false
SKIP_SUPERUSER=false SKIP_SUPERUSER=false
SUPERUSER_NAME=admin
SUPERUSER_EMAIL=admin@example.com
SUPERUSER_PASSWORD=admin
SUPERUSER_API_TOKEN=0123456789abcdef0123456789abcdef01234567 SUPERUSER_API_TOKEN=0123456789abcdef0123456789abcdef01234567
SUPERUSER_EMAIL=admin@example.com
SUPERUSER_NAME=admin
SUPERUSER_PASSWORD=admin
WEBHOOKS_ENABLED=true WEBHOOKS_ENABLED=true

4
env/postgres.env vendored
View File

@ -1,3 +1,3 @@
POSTGRES_USER=netbox
POSTGRES_PASSWORD=J5brHrAXFLQSif0K
POSTGRES_DB=netbox POSTGRES_DB=netbox
POSTGRES_PASSWORD=J5brHrAXFLQSif0K
POSTGRES_USER=netbox

View File

@ -53,20 +53,20 @@
# - Fifth Item # - Fifth Item
# - Fourth Item # - Fourth Item
# select_field_legacy_format: # select_field_legacy_format:
# type: select # type: select
# label: Choose between items # label: Choose between items
# required: false # required: false
# filter_logic: loose # filter_logic: loose
# weight: 30 # weight: 30
# on_objects: # on_objects:
# - dcim.models.Device # - dcim.models.Device
# choices: # choices:
# - value: A # this is the deprecated format. # - value: A # this is the deprecated format.
# - value: B # we only use it for the tests. # - value: B # we only use it for the tests.
# - value: C # please see above for the new format. # - value: C # please see above for the new format.
# - value: "D like deprecated" # - value: "D like deprecated"
# weight: 999 # weight: 999
# - value: E # - value: E
# boolean_field: # boolean_field:
# type: boolean # type: boolean
# label: Yes Or No? # label: Yes Or No?

26
pyproject.toml Normal file
View File

@ -0,0 +1,26 @@
[tool.black]
line_length = 100
target-version = ['py38']
include = '\.pyi?$'
exclude = '''
(
/(
\.git
| \.venv
| \.netbox
| \.vscode
| configuration
)/
)
'''
[tool.isort]
profile = "black"
multi_line_output = 3
line_length = 100
[tool.pylint.messages_control]
disable = "C0330, C0326"
[tool.pylint.format]
max-line-length = "100"

View File

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

View File

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

View File

@ -3,56 +3,62 @@ import sys
from extras.models import CustomField from extras.models import CustomField
from startup_script_utils import load_yaml from startup_script_utils import load_yaml
def get_class_for_class_path(class_path): def get_class_for_class_path(class_path):
import importlib import importlib
from django.contrib.contenttypes.models import ContentType
module_name, class_name = class_path.rsplit(".", 1) from django.contrib.contenttypes.models import ContentType
module = importlib.import_module(module_name)
clazz = getattr(module, class_name)
return ContentType.objects.get_for_model(clazz)
customfields = load_yaml('/opt/netbox/initializers/custom_fields.yml') module_name, class_name = class_path.rsplit(".", 1)
module = importlib.import_module(module_name)
clazz = getattr(module, class_name)
return ContentType.objects.get_for_model(clazz)
customfields = load_yaml("/opt/netbox/initializers/custom_fields.yml")
if customfields is None: if customfields is None:
sys.exit() sys.exit()
for cf_name, cf_details in customfields.items(): for cf_name, cf_details in customfields.items():
custom_field, created = CustomField.objects.get_or_create(name = cf_name) custom_field, created = CustomField.objects.get_or_create(name=cf_name)
if created: if created:
if cf_details.get('default', False): if cf_details.get("default", False):
custom_field.default = cf_details['default'] custom_field.default = cf_details["default"]
if cf_details.get('description', False): if cf_details.get("description", False):
custom_field.description = cf_details['description'] custom_field.description = cf_details["description"]
if cf_details.get('label', False): if cf_details.get("label", False):
custom_field.label = cf_details['label'] custom_field.label = cf_details["label"]
for object_type in cf_details.get('on_objects', []): for object_type in cf_details.get("on_objects", []):
custom_field.content_types.add(get_class_for_class_path(object_type)) custom_field.content_types.add(get_class_for_class_path(object_type))
if cf_details.get('required', False): if cf_details.get("required", False):
custom_field.required = cf_details['required'] custom_field.required = cf_details["required"]
if cf_details.get('type', False): if cf_details.get("type", False):
custom_field.type = cf_details['type'] custom_field.type = cf_details["type"]
if cf_details.get('weight', -1) >= 0: if cf_details.get("weight", -1) >= 0:
custom_field.weight = cf_details['weight'] custom_field.weight = cf_details["weight"]
if cf_details.get('choices', False): if cf_details.get("choices", False):
custom_field.choices = [] custom_field.choices = []
for choice_detail in cf_details.get('choices', []): for choice_detail in cf_details.get("choices", []):
if isinstance(choice_detail, dict) and 'value' in choice_detail: if isinstance(choice_detail, dict) and "value" in choice_detail:
# legacy mode # legacy mode
print(f"⚠️ Please migrate the choice '{choice_detail['value']}' of '{cf_name}' to the new format, as 'weight' is no longer supported!") print(
custom_field.choices.append(choice_detail['value']) f"⚠️ Please migrate the choice '{choice_detail['value']}' of '{cf_name}'"
else: + " to the new format, as 'weight' is no longer supported!"
custom_field.choices.append(choice_detail) )
custom_field.choices.append(choice_detail["value"])
else:
custom_field.choices.append(choice_detail)
custom_field.save() custom_field.save()
print("🔧 Created custom field", cf_name) print("🔧 Created custom field", cf_name)

View File

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

View File

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

View File

@ -1,32 +1,29 @@
import sys import sys
from dcim.models import Region, Site from dcim.models import Region, Site
from startup_script_utils import * from startup_script_utils import load_yaml, pop_custom_fields, set_custom_fields_values
from tenancy.models import Tenant from tenancy.models import Tenant
sites = load_yaml('/opt/netbox/initializers/sites.yml') sites = load_yaml("/opt/netbox/initializers/sites.yml")
if sites is None: if sites is None:
sys.exit() sys.exit()
optional_assocs = { optional_assocs = {"region": (Region, "name"), "tenant": (Tenant, "name")}
'region': (Region, 'name'),
'tenant': (Tenant, 'name')
}
for params in sites: for params in sites:
custom_field_data = pop_custom_fields(params) custom_field_data = pop_custom_fields(params)
for assoc, details in optional_assocs.items(): for assoc, details in optional_assocs.items():
if assoc in params: if assoc in params:
model, field = details model, field = details
query = { field: params.pop(assoc) } query = {field: params.pop(assoc)}
params[assoc] = model.objects.get(**query) params[assoc] = model.objects.get(**query)
site, created = Site.objects.get_or_create(**params) site, created = Site.objects.get_or_create(**params)
if created: if created:
set_custom_fields_values(site, custom_field_data) set_custom_fields_values(site, custom_field_data)
print("📍 Created site", site.name) print("📍 Created site", site.name)

View File

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

View File

@ -1,42 +1,37 @@
import sys import sys
from dcim.models import DeviceType, Manufacturer, Region from dcim.models import DeviceType, Manufacturer, Region
from startup_script_utils import * from startup_script_utils import load_yaml, pop_custom_fields, set_custom_fields_values
from tenancy.models import Tenant from tenancy.models import Tenant
device_types = load_yaml('/opt/netbox/initializers/device_types.yml') device_types = load_yaml("/opt/netbox/initializers/device_types.yml")
if device_types is None: if device_types is None:
sys.exit() sys.exit()
required_assocs = { required_assocs = {"manufacturer": (Manufacturer, "name")}
'manufacturer': (Manufacturer, 'name')
}
optional_assocs = { optional_assocs = {"region": (Region, "name"), "tenant": (Tenant, "name")}
'region': (Region, 'name'),
'tenant': (Tenant, 'name')
}
for params in device_types: for params in device_types:
custom_field_data = pop_custom_fields(params) custom_field_data = pop_custom_fields(params)
for assoc, details in required_assocs.items(): for assoc, details in required_assocs.items():
model, field = details model, field = details
query = { field: params.pop(assoc) } query = {field: params.pop(assoc)}
params[assoc] = model.objects.get(**query) params[assoc] = model.objects.get(**query)
for assoc, details in optional_assocs.items(): for assoc, details in optional_assocs.items():
if assoc in params: if assoc in params:
model, field = details model, field = details
query = { field: params.pop(assoc) } query = {field: params.pop(assoc)}
params[assoc] = model.objects.get(**query) params[assoc] = model.objects.get(**query)
device_type, created = DeviceType.objects.get_or_create(**params) device_type, created = DeviceType.objects.get_or_create(**params)
if created: if created:
set_custom_fields_values(device_type, custom_field_data) set_custom_fields_values(device_type, custom_field_data)
print("🔡 Created device type", device_type.manufacturer, device_type.model) print("🔡 Created device type", device_type.manufacturer, device_type.model)

View File

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

View File

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

View File

@ -1,43 +1,41 @@
import sys import sys
from dcim.models import Site, RackRole, Rack, RackGroup from dcim.models import Rack, RackGroup, RackRole, Site
from startup_script_utils import * from startup_script_utils import load_yaml, pop_custom_fields, set_custom_fields_values
from tenancy.models import Tenant from tenancy.models import Tenant
racks = load_yaml('/opt/netbox/initializers/racks.yml') racks = load_yaml("/opt/netbox/initializers/racks.yml")
if racks is None: if racks is None:
sys.exit() sys.exit()
required_assocs = { required_assocs = {"site": (Site, "name")}
'site': (Site, 'name')
}
optional_assocs = { optional_assocs = {
'role': (RackRole, 'name'), "role": (RackRole, "name"),
'tenant': (Tenant, 'name'), "tenant": (Tenant, "name"),
'group': (RackGroup, 'name') "group": (RackGroup, "name"),
} }
for params in racks: for params in racks:
custom_field_data = pop_custom_fields(params) custom_field_data = pop_custom_fields(params)
for assoc, details in required_assocs.items(): for assoc, details in required_assocs.items():
model, field = details model, field = details
query = { field: params.pop(assoc) } query = {field: params.pop(assoc)}
params[assoc] = model.objects.get(**query) params[assoc] = model.objects.get(**query)
for assoc, details in optional_assocs.items(): for assoc, details in optional_assocs.items():
if assoc in params: if assoc in params:
model, field = details model, field = details
query = { field: params.pop(assoc) } query = {field: params.pop(assoc)}
params[assoc] = model.objects.get(**query) params[assoc] = model.objects.get(**query)
rack, created = Rack.objects.get_or_create(**params) rack, created = Rack.objects.get_or_create(**params)
if created: if created:
set_custom_fields_values(rack, custom_field_data) set_custom_fields_values(rack, custom_field_data)
print("🔳 Created rack", rack.site, rack.name) print("🔳 Created rack", rack.site, rack.name)

View File

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

View File

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

View File

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

View File

@ -1,30 +1,28 @@
import sys import sys
from startup_script_utils import * from startup_script_utils import load_yaml, pop_custom_fields, set_custom_fields_values
from tenancy.models import Tenant, TenantGroup from tenancy.models import Tenant, TenantGroup
tenants = load_yaml('/opt/netbox/initializers/tenants.yml') tenants = load_yaml("/opt/netbox/initializers/tenants.yml")
if tenants is None: if tenants is None:
sys.exit() sys.exit()
optional_assocs = { optional_assocs = {"group": (TenantGroup, "name")}
'group': (TenantGroup, 'name')
}
for params in tenants: for params in tenants:
custom_field_data = pop_custom_fields(params) custom_field_data = pop_custom_fields(params)
for assoc, details in optional_assocs.items(): for assoc, details in optional_assocs.items():
if assoc in params: if assoc in params:
model, field = details model, field = details
query = { field: params.pop(assoc) } query = {field: params.pop(assoc)}
params[assoc] = model.objects.get(**query) params[assoc] = model.objects.get(**query)
tenant, created = Tenant.objects.get_or_create(**params) tenant, created = Tenant.objects.get_or_create(**params)
if created: if created:
set_custom_fields_values(tenant, custom_field_data) set_custom_fields_values(tenant, custom_field_data)
print("👩‍💻 Created Tenant", tenant.name) print("👩‍💻 Created Tenant", tenant.name)

View File

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

View File

@ -1,14 +1,15 @@
from virtualization.models import ClusterGroup
from startup_script_utils import load_yaml
import sys import sys
cluster_groups = load_yaml('/opt/netbox/initializers/cluster_groups.yml') from startup_script_utils import load_yaml
from virtualization.models import ClusterGroup
cluster_groups = load_yaml("/opt/netbox/initializers/cluster_groups.yml")
if cluster_groups is None: if cluster_groups is None:
sys.exit() sys.exit()
for params in cluster_groups: for params in cluster_groups:
cluster_group, created = ClusterGroup.objects.get_or_create(**params) cluster_group, created = ClusterGroup.objects.get_or_create(**params)
if created: if created:
print("🗄️ Created Cluster Group", cluster_group.name) print("🗄️ Created Cluster Group", cluster_group.name)

View File

@ -1,44 +1,42 @@
import sys import sys
from dcim.models import Site from dcim.models import Site
from startup_script_utils import * from startup_script_utils import load_yaml, pop_custom_fields, set_custom_fields_values
from virtualization.models import Cluster, ClusterType, ClusterGroup
from tenancy.models import Tenant from tenancy.models import Tenant
from virtualization.models import Cluster, ClusterGroup, ClusterType
clusters = load_yaml('/opt/netbox/initializers/clusters.yml') clusters = load_yaml("/opt/netbox/initializers/clusters.yml")
if clusters is None: if clusters is None:
sys.exit() sys.exit()
required_assocs = { required_assocs = {"type": (ClusterType, "name")}
'type': (ClusterType, 'name')
}
optional_assocs = { optional_assocs = {
'site': (Site, 'name'), "site": (Site, "name"),
'group': (ClusterGroup, 'name'), "group": (ClusterGroup, "name"),
'tenant': (Tenant, 'name') "tenant": (Tenant, "name"),
} }
for params in clusters: for params in clusters:
custom_field_data = pop_custom_fields(params) custom_field_data = pop_custom_fields(params)
for assoc, details in required_assocs.items(): for assoc, details in required_assocs.items():
model, field = details model, field = details
query = { field: params.pop(assoc) } query = {field: params.pop(assoc)}
params[assoc] = model.objects.get(**query) params[assoc] = model.objects.get(**query)
for assoc, details in optional_assocs.items(): for assoc, details in optional_assocs.items():
if assoc in params: if assoc in params:
model, field = details model, field = details
query = { field: params.pop(assoc) } query = {field: params.pop(assoc)}
params[assoc] = model.objects.get(**query) params[assoc] = model.objects.get(**query)
cluster, created = Cluster.objects.get_or_create(**params) cluster, created = Cluster.objects.get_or_create(**params)
if created: if created:
set_custom_fields_values(cluster, custom_field_data) set_custom_fields_values(cluster, custom_field_data)
print("🗄️ Created cluster", cluster.name) print("🗄️ Created cluster", cluster.name)

View File

@ -1,44 +1,42 @@
import sys import sys
from dcim.models import Site from dcim.models import Site
from startup_script_utils import * from startup_script_utils import load_yaml, pop_custom_fields, set_custom_fields_values
from virtualization.models import Cluster, ClusterType, ClusterGroup
from tenancy.models import Tenant from tenancy.models import Tenant
from virtualization.models import Cluster, ClusterGroup, ClusterType
clusters = load_yaml('/opt/netbox/initializers/clusters.yml') clusters = load_yaml("/opt/netbox/initializers/clusters.yml")
if clusters is None: if clusters is None:
sys.exit() sys.exit()
required_assocs = { required_assocs = {"type": (ClusterType, "name")}
'type': (ClusterType, 'name')
}
optional_assocs = { optional_assocs = {
'site': (Site, 'name'), "site": (Site, "name"),
'group': (ClusterGroup, 'name'), "group": (ClusterGroup, "name"),
'tenant': (Tenant, 'name') "tenant": (Tenant, "name"),
} }
for params in clusters: for params in clusters:
custom_field_data = pop_custom_fields(params) custom_field_data = pop_custom_fields(params)
for assoc, details in required_assocs.items(): for assoc, details in required_assocs.items():
model, field = details model, field = details
query = { field: params.pop(assoc) } query = {field: params.pop(assoc)}
params[assoc] = model.objects.get(**query) params[assoc] = model.objects.get(**query)
for assoc, details in optional_assocs.items(): for assoc, details in optional_assocs.items():
if assoc in params: if assoc in params:
model, field = details model, field = details
query = { field: params.pop(assoc) } query = {field: params.pop(assoc)}
params[assoc] = model.objects.get(**query) params[assoc] = model.objects.get(**query)
cluster, created = Cluster.objects.get_or_create(**params) cluster, created = Cluster.objects.get_or_create(**params)
if created: if created:
set_custom_fields_values(cluster, custom_field_data) set_custom_fields_values(cluster, custom_field_data)
print("🗄️ Created cluster", cluster.name) print("🗄️ Created cluster", cluster.name)

View File

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

View File

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

View File

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

View File

@ -1,44 +1,42 @@
import sys import sys
from ipam.models import Aggregate, RIR from ipam.models import RIR, Aggregate
from netaddr import IPNetwork from netaddr import IPNetwork
from startup_script_utils import * from startup_script_utils import load_yaml, pop_custom_fields, set_custom_fields_values
from tenancy.models import Tenant from tenancy.models import Tenant
aggregates = load_yaml('/opt/netbox/initializers/aggregates.yml') aggregates = load_yaml("/opt/netbox/initializers/aggregates.yml")
if aggregates is None: if aggregates is None:
sys.exit() sys.exit()
required_assocs = { required_assocs = {"rir": (RIR, "name")}
'rir': (RIR, 'name')
}
optional_assocs = { optional_assocs = {
'tenant': (Tenant, 'name'), "tenant": (Tenant, "name"),
} }
for params in aggregates: for params in aggregates:
custom_field_data = pop_custom_fields(params) custom_field_data = pop_custom_fields(params)
params['prefix'] = IPNetwork(params['prefix']) params["prefix"] = IPNetwork(params["prefix"])
for assoc, details in required_assocs.items(): for assoc, details in required_assocs.items():
model, field = details model, field = details
query = { field: params.pop(assoc) } query = {field: params.pop(assoc)}
params[assoc] = model.objects.get(**query) params[assoc] = model.objects.get(**query)
for assoc, details in optional_assocs.items(): for assoc, details in optional_assocs.items():
if assoc in params: if assoc in params:
model, field = details model, field = details
query = { field: params.pop(assoc) } query = {field: params.pop(assoc)}
params[assoc] = model.objects.get(**query) params[assoc] = model.objects.get(**query)
aggregate, created = Aggregate.objects.get_or_create(**params) aggregate, created = Aggregate.objects.get_or_create(**params)
if created: if created:
set_custom_fields_values(aggregate, custom_field_data) set_custom_fields_values(aggregate, custom_field_data)
print("🗞️ Created Aggregate", aggregate.prefix) print("🗞️ Created Aggregate", aggregate.prefix)

View File

@ -1,14 +1,15 @@
from virtualization.models import ClusterGroup
from startup_script_utils import load_yaml
import sys import sys
cluster_groups = load_yaml('/opt/netbox/initializers/cluster_groups.yml') from startup_script_utils import load_yaml
from virtualization.models import ClusterGroup
cluster_groups = load_yaml("/opt/netbox/initializers/cluster_groups.yml")
if cluster_groups is None: if cluster_groups is None:
sys.exit() sys.exit()
for params in cluster_groups: for params in cluster_groups:
cluster_group, created = ClusterGroup.objects.get_or_create(**params) cluster_group, created = ClusterGroup.objects.get_or_create(**params)
if created: if created:
print("🗄️ Created Cluster Group", cluster_group.name) print("🗄️ Created Cluster Group", cluster_group.name)

View File

@ -1,31 +1,29 @@
import sys import sys
from ipam.models import RouteTarget from ipam.models import RouteTarget
from startup_script_utils import * from startup_script_utils import load_yaml, pop_custom_fields, set_custom_fields_values
from tenancy.models import Tenant from tenancy.models import Tenant
route_targets = load_yaml('/opt/netbox/initializers/route_targets.yml') route_targets = load_yaml("/opt/netbox/initializers/route_targets.yml")
if route_targets is None: if route_targets is None:
sys.exit() sys.exit()
optional_assocs = { optional_assocs = {"tenant": (Tenant, "name")}
'tenant': (Tenant, 'name')
}
for params in route_targets: for params in route_targets:
custom_field_data = pop_custom_fields(params) custom_field_data = pop_custom_fields(params)
for assoc, details in optional_assocs.items(): for assoc, details in optional_assocs.items():
if assoc in params: if assoc in params:
model, field = details model, field = details
query = { field: params.pop(assoc) } query = {field: params.pop(assoc)}
params[assoc] = model.objects.get(**query) params[assoc] = model.objects.get(**query)
route_target, created = RouteTarget.objects.get_or_create(**params) route_target, created = RouteTarget.objects.get_or_create(**params)
if created: if created:
set_custom_fields_values(route_target, custom_field_data) set_custom_fields_values(route_target, custom_field_data)
print("🎯 Created Route Target", route_target.name) print("🎯 Created Route Target", route_target.name)

View File

@ -1,31 +1,29 @@
import sys import sys
from ipam.models import VRF from ipam.models import VRF
from startup_script_utils import * from startup_script_utils import load_yaml, pop_custom_fields, set_custom_fields_values
from tenancy.models import Tenant from tenancy.models import Tenant
vrfs = load_yaml('/opt/netbox/initializers/vrfs.yml') vrfs = load_yaml("/opt/netbox/initializers/vrfs.yml")
if vrfs is None: if vrfs is None:
sys.exit() sys.exit()
optional_assocs = { optional_assocs = {"tenant": (Tenant, "name")}
'tenant': (Tenant, 'name')
}
for params in vrfs: for params in vrfs:
custom_field_data = pop_custom_fields(params) custom_field_data = pop_custom_fields(params)
for assoc, details in optional_assocs.items(): for assoc, details in optional_assocs.items():
if assoc in params: if assoc in params:
model, field = details model, field = details
query = { field: params.pop(assoc) } query = {field: params.pop(assoc)}
params[assoc] = model.objects.get(**query) params[assoc] = model.objects.get(**query)
vrf, created = VRF.objects.get_or_create(**params) vrf, created = VRF.objects.get_or_create(**params)
if created: if created:
set_custom_fields_values(vrf, custom_field_data) set_custom_fields_values(vrf, custom_field_data)
print("📦 Created VRF", vrf.name) print("📦 Created VRF", vrf.name)

View File

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

View File

@ -2,30 +2,28 @@ import sys
from dcim.models import Site from dcim.models import Site
from ipam.models import VLANGroup from ipam.models import VLANGroup
from startup_script_utils import * from startup_script_utils import load_yaml, pop_custom_fields, set_custom_fields_values
vlan_groups = load_yaml('/opt/netbox/initializers/vlan_groups.yml') vlan_groups = load_yaml("/opt/netbox/initializers/vlan_groups.yml")
if vlan_groups is None: if vlan_groups is None:
sys.exit() sys.exit()
optional_assocs = { optional_assocs = {"site": (Site, "name")}
'site': (Site, 'name')
}
for params in vlan_groups: for params in vlan_groups:
custom_field_data = pop_custom_fields(params) custom_field_data = pop_custom_fields(params)
for assoc, details in optional_assocs.items(): for assoc, details in optional_assocs.items():
if assoc in params: if assoc in params:
model, field = details model, field = details
query = { field: params.pop(assoc) } query = {field: params.pop(assoc)}
params[assoc] = model.objects.get(**query) params[assoc] = model.objects.get(**query)
vlan_group, created = VLANGroup.objects.get_or_create(**params) vlan_group, created = VLANGroup.objects.get_or_create(**params)
if created: if created:
set_custom_fields_values(vlan_group, custom_field_data) set_custom_fields_values(vlan_group, custom_field_data)
print("🏘️ Created VLAN Group", vlan_group.name) print("🏘️ Created VLAN Group", vlan_group.name)

View File

@ -1,36 +1,36 @@
import sys import sys
from dcim.models import Site from dcim.models import Site
from ipam.models import VLAN, VLANGroup, Role from ipam.models import VLAN, Role, VLANGroup
from startup_script_utils import * from startup_script_utils import load_yaml, pop_custom_fields, set_custom_fields_values
from tenancy.models import Tenant, TenantGroup from tenancy.models import Tenant, TenantGroup
vlans = load_yaml('/opt/netbox/initializers/vlans.yml') vlans = load_yaml("/opt/netbox/initializers/vlans.yml")
if vlans is None: if vlans is None:
sys.exit() sys.exit()
optional_assocs = { optional_assocs = {
'site': (Site, 'name'), "site": (Site, "name"),
'tenant': (Tenant, 'name'), "tenant": (Tenant, "name"),
'tenant_group': (TenantGroup, 'name'), "tenant_group": (TenantGroup, "name"),
'group': (VLANGroup, 'name'), "group": (VLANGroup, "name"),
'role': (Role, 'name') "role": (Role, "name"),
} }
for params in vlans: for params in vlans:
custom_field_data = pop_custom_fields(params) custom_field_data = pop_custom_fields(params)
for assoc, details in optional_assocs.items(): for assoc, details in optional_assocs.items():
if assoc in params: if assoc in params:
model, field = details model, field = details
query = { field: params.pop(assoc) } query = {field: params.pop(assoc)}
params[assoc] = model.objects.get(**query) params[assoc] = model.objects.get(**query)
vlan, created = VLAN.objects.get_or_create(**params) vlan, created = VLAN.objects.get_or_create(**params)
if created: if created:
set_custom_fields_values(vlan, custom_field_data) set_custom_fields_values(vlan, custom_field_data)
print("🏠 Created VLAN", vlan.name) print("🏠 Created VLAN", vlan.name)

View File

@ -1,39 +1,39 @@
import sys import sys
from dcim.models import Site from dcim.models import Site
from ipam.models import Prefix, VLAN, Role, VRF from ipam.models import VLAN, VRF, Prefix, Role
from netaddr import IPNetwork from netaddr import IPNetwork
from startup_script_utils import * from startup_script_utils import load_yaml, pop_custom_fields, set_custom_fields_values
from tenancy.models import Tenant, TenantGroup from tenancy.models import Tenant, TenantGroup
prefixes = load_yaml('/opt/netbox/initializers/prefixes.yml') prefixes = load_yaml("/opt/netbox/initializers/prefixes.yml")
if prefixes is None: if prefixes is None:
sys.exit() sys.exit()
optional_assocs = { optional_assocs = {
'site': (Site, 'name'), "site": (Site, "name"),
'tenant': (Tenant, 'name'), "tenant": (Tenant, "name"),
'tenant_group': (TenantGroup, 'name'), "tenant_group": (TenantGroup, "name"),
'vlan': (VLAN, 'name'), "vlan": (VLAN, "name"),
'role': (Role, 'name'), "role": (Role, "name"),
'vrf': (VRF, 'name') "vrf": (VRF, "name"),
} }
for params in prefixes: for params in prefixes:
custom_field_data = pop_custom_fields(params) custom_field_data = pop_custom_fields(params)
params['prefix'] = IPNetwork(params['prefix']) params["prefix"] = IPNetwork(params["prefix"])
for assoc, details in optional_assocs.items(): for assoc, details in optional_assocs.items():
if assoc in params: if assoc in params:
model, field = details model, field = details
query = { field: params.pop(assoc) } query = {field: params.pop(assoc)}
params[assoc] = model.objects.get(**query) params[assoc] = model.objects.get(**query)
prefix, created = Prefix.objects.get_or_create(**params) prefix, created = Prefix.objects.get_or_create(**params)
if created: if created:
set_custom_fields_values(prefix, custom_field_data) set_custom_fields_values(prefix, custom_field_data)
print("📌 Created Prefix", prefix.prefix) print("📌 Created Prefix", prefix.prefix)

View File

@ -1,48 +1,46 @@
import sys import sys
from dcim.models import Platform, DeviceRole from dcim.models import DeviceRole, Platform
from startup_script_utils import * from startup_script_utils import load_yaml, pop_custom_fields, set_custom_fields_values
from tenancy.models import Tenant from tenancy.models import Tenant
from virtualization.models import Cluster, VirtualMachine from virtualization.models import Cluster, VirtualMachine
virtual_machines = load_yaml('/opt/netbox/initializers/virtual_machines.yml') virtual_machines = load_yaml("/opt/netbox/initializers/virtual_machines.yml")
if virtual_machines is None: if virtual_machines is None:
sys.exit() sys.exit()
required_assocs = { required_assocs = {"cluster": (Cluster, "name")}
'cluster': (Cluster, 'name')
}
optional_assocs = { optional_assocs = {
'tenant': (Tenant, 'name'), "tenant": (Tenant, "name"),
'platform': (Platform, 'name'), "platform": (Platform, "name"),
'role': (DeviceRole, 'name') "role": (DeviceRole, "name"),
} }
for params in virtual_machines: for params in virtual_machines:
custom_field_data = pop_custom_fields(params) custom_field_data = pop_custom_fields(params)
# primary ips are handled later in `270_primary_ips.py` # primary ips are handled later in `270_primary_ips.py`
params.pop('primary_ip4', None) params.pop("primary_ip4", None)
params.pop('primary_ip6', None) params.pop("primary_ip6", None)
for assoc, details in required_assocs.items(): for assoc, details in required_assocs.items():
model, field = details model, field = details
query = { field: params.pop(assoc) } query = {field: params.pop(assoc)}
params[assoc] = model.objects.get(**query) params[assoc] = model.objects.get(**query)
for assoc, details in optional_assocs.items(): for assoc, details in optional_assocs.items():
if assoc in params: if assoc in params:
model, field = details model, field = details
query = { field: params.pop(assoc) } query = {field: params.pop(assoc)}
params[assoc] = model.objects.get(**query) params[assoc] = model.objects.get(**query)
virtual_machine, created = VirtualMachine.objects.get_or_create(**params) virtual_machine, created = VirtualMachine.objects.get_or_create(**params)
if created: if created:
set_custom_fields_values(virtual_machine, custom_field_data) set_custom_fields_values(virtual_machine, custom_field_data)
print("🖥️ Created virtual machine", virtual_machine.name) print("🖥️ Created virtual machine", virtual_machine.name)

View File

@ -1,29 +1,27 @@
import sys import sys
from startup_script_utils import * from startup_script_utils import load_yaml, pop_custom_fields, set_custom_fields_values
from virtualization.models import VirtualMachine, VMInterface from virtualization.models import VirtualMachine, VMInterface
interfaces = load_yaml('/opt/netbox/initializers/virtualization_interfaces.yml') interfaces = load_yaml("/opt/netbox/initializers/virtualization_interfaces.yml")
if interfaces is None: if interfaces is None:
sys.exit() sys.exit()
required_assocs = { required_assocs = {"virtual_machine": (VirtualMachine, "name")}
'virtual_machine': (VirtualMachine, 'name')
}
for params in interfaces: for params in interfaces:
custom_field_data = pop_custom_fields(params) custom_field_data = pop_custom_fields(params)
for assoc, details in required_assocs.items(): for assoc, details in required_assocs.items():
model, field = details model, field = details
query = { field: params.pop(assoc) } query = {field: params.pop(assoc)}
params[assoc] = model.objects.get(**query) params[assoc] = model.objects.get(**query)
interface, created = VMInterface.objects.get_or_create(**params) interface, created = VMInterface.objects.get_or_create(**params)
if created: if created:
set_custom_fields_values(interface, custom_field_data) set_custom_fields_values(interface, custom_field_data)
print("🧷 Created interface", interface.name, interface.virtual_machine.name) print("🧷 Created interface", interface.name, interface.virtual_machine.name)

View File

@ -1,29 +1,27 @@
import sys import sys
from dcim.models import Interface, Device from dcim.models import Device, Interface
from startup_script_utils import * from startup_script_utils import load_yaml, pop_custom_fields, set_custom_fields_values
interfaces = load_yaml('/opt/netbox/initializers/dcim_interfaces.yml') interfaces = load_yaml("/opt/netbox/initializers/dcim_interfaces.yml")
if interfaces is None: if interfaces is None:
sys.exit() sys.exit()
required_assocs = { required_assocs = {"device": (Device, "name")}
'device': (Device, 'name')
}
for params in interfaces: for params in interfaces:
custom_field_data = pop_custom_fields(params) custom_field_data = pop_custom_fields(params)
for assoc, details in required_assocs.items(): for assoc, details in required_assocs.items():
model, field = details model, field = details
query = { field: params.pop(assoc) } query = {field: params.pop(assoc)}
params[assoc] = model.objects.get(**query) params[assoc] = model.objects.get(**query)
interface, created = Interface.objects.get_or_create(**params) interface, created = Interface.objects.get_or_create(**params)
if created: if created:
set_custom_fields_values(interface, custom_field_data) set_custom_fields_values(interface, custom_field_data)
print("🧷 Created interface", interface.name, interface.device.name) print("🧷 Created interface", interface.name, interface.device.name)

View File

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

View File

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

View File

@ -1,29 +1,33 @@
import sys
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from extras.models import CustomLink from extras.models import CustomLink
from startup_script_utils import load_yaml from startup_script_utils import load_yaml
import sys
custom_links = load_yaml("/opt/netbox/initializers/custom_links.yml")
custom_links = load_yaml('/opt/netbox/initializers/custom_links.yml')
if custom_links is None: if custom_links is None:
sys.exit() sys.exit()
def get_content_type_id(content_type): def get_content_type_id(content_type):
try: try:
return ContentType.objects.get(model=content_type).id return ContentType.objects.get(model=content_type).id
except ContentType.DoesNotExist: except ContentType.DoesNotExist:
pass pass
for link in custom_links: for link in custom_links:
content_type = link.pop('content_type') content_type = link.pop("content_type")
link['content_type_id'] = get_content_type_id(content_type) link["content_type_id"] = get_content_type_id(content_type)
if link['content_type_id'] is None: if link["content_type_id"] is None:
print("⚠️ Unable to create Custom Link '{0}': The content_type '{1}' is unknown".format(link.name, content_type)) print(
continue "⚠️ Unable to create Custom Link '{0}': The content_type '{1}' is unknown".format(
link.name, content_type
)
)
continue
custom_link, created = CustomLink.objects.get_or_create(**link) custom_link, created = CustomLink.objects.get_or_create(**link)
if created: if created:
print("🔗 Created Custom Link '{0}'".format(custom_link.name)) print("🔗 Created Custom Link '{0}'".format(custom_link.name))

View File

@ -1,18 +1,19 @@
from circuits.models import Provider
from startup_script_utils import *
import sys import sys
providers = load_yaml('/opt/netbox/initializers/providers.yml') from circuits.models import Provider
from startup_script_utils import load_yaml, pop_custom_fields, set_custom_fields_values
providers = load_yaml("/opt/netbox/initializers/providers.yml")
if providers is None: if providers is None:
sys.exit() sys.exit()
for params in providers: for params in providers:
custom_field_data = pop_custom_fields(params) custom_field_data = pop_custom_fields(params)
provider, created = Provider.objects.get_or_create(**params) provider, created = Provider.objects.get_or_create(**params)
if created: if created:
set_custom_fields_values(provider, custom_field_data) set_custom_fields_values(provider, custom_field_data)
print("📡 Created provider", provider.name) print("📡 Created provider", provider.name)

View File

@ -1,18 +1,19 @@
from circuits.models import CircuitType
from startup_script_utils import *
import sys import sys
circuit_types = load_yaml('/opt/netbox/initializers/circuit_types.yml') from circuits.models import CircuitType
from startup_script_utils import load_yaml, pop_custom_fields, set_custom_fields_values
circuit_types = load_yaml("/opt/netbox/initializers/circuit_types.yml")
if circuit_types is None: if circuit_types is None:
sys.exit() sys.exit()
for params in circuit_types: for params in circuit_types:
custom_field_data = pop_custom_fields(params) custom_field_data = pop_custom_fields(params)
circuit_type, created = CircuitType.objects.get_or_create(**params) circuit_type, created = CircuitType.objects.get_or_create(**params)
if created: if created:
set_custom_fields_values(circuit_type, custom_field_data) set_custom_fields_values(circuit_type, custom_field_data)
print("⚡ Created Circuit Type", circuit_type.name) print("⚡ Created Circuit Type", circuit_type.name)

View File

@ -1,34 +1,34 @@
import sys
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from extras.models import Webhook from extras.models import Webhook
from startup_script_utils import load_yaml from startup_script_utils import load_yaml
import sys
webhooks = load_yaml("/opt/netbox/initializers/webhooks.yml")
webhooks = load_yaml('/opt/netbox/initializers/webhooks.yml')
if webhooks is None: if webhooks is None:
sys.exit() sys.exit()
def get_content_type_id(hook_name, content_type): def get_content_type_id(hook_name, content_type):
try: try:
return ContentType.objects.get(model=content_type).id return ContentType.objects.get(model=content_type).id
except ContentType.DoesNotExist as ex: except ContentType.DoesNotExist as ex:
print("⚠️ Webhook '{0}': The object_type '{1}' is unknown.".format(hook_name, content_type)) print("⚠️ Webhook '{0}': The object_type '{1}' is unknown.".format(hook_name, content_type))
raise ex raise ex
for hook in webhooks: for hook in webhooks:
obj_types = hook.pop('object_types') obj_types = hook.pop("object_types")
try: try:
obj_type_ids = [get_content_type_id(hook['name'], obj) for obj in obj_types] obj_type_ids = [get_content_type_id(hook["name"], obj) for obj in obj_types]
except ContentType.DoesNotExist: except ContentType.DoesNotExist:
continue continue
webhook, created = Webhook.objects.get_or_create(**hook) webhook, created = Webhook.objects.get_or_create(**hook)
if created: if created:
webhook.content_types.set(obj_type_ids) webhook.content_types.set(obj_type_ids)
webhook.save() webhook.save()
print("🪝 Created Webhook {0}".format(webhook.name)) print("🪝 Created Webhook {0}".format(webhook.name))

View File

@ -1,41 +1,37 @@
from circuits.models import Circuit, Provider, CircuitType
from tenancy.models import Tenant
from startup_script_utils import *
import sys import sys
circuits = load_yaml('/opt/netbox/initializers/circuits.yml') from circuits.models import Circuit, CircuitType, Provider
from startup_script_utils import load_yaml, pop_custom_fields, set_custom_fields_values
from tenancy.models import Tenant
circuits = load_yaml("/opt/netbox/initializers/circuits.yml")
if circuits is None: if circuits is None:
sys.exit() sys.exit()
required_assocs = { required_assocs = {"provider": (Provider, "name"), "type": (CircuitType, "name")}
'provider': (Provider, 'name'),
'type': (CircuitType, 'name')
}
optional_assocs = { optional_assocs = {"tenant": (Tenant, "name")}
'tenant': (Tenant, 'name')
}
for params in circuits: for params in circuits:
custom_field_data = pop_custom_fields(params) custom_field_data = pop_custom_fields(params)
for assoc, details in required_assocs.items(): for assoc, details in required_assocs.items():
model, field = details model, field = details
query = { field: params.pop(assoc) } query = {field: params.pop(assoc)}
params[assoc] = model.objects.get(**query) params[assoc] = model.objects.get(**query)
for assoc, details in optional_assocs.items(): for assoc, details in optional_assocs.items():
if assoc in params: if assoc in params:
model, field = details model, field = details
query = { field: params.pop(assoc) } query = {field: params.pop(assoc)}
params[assoc] = model.objects.get(**query) params[assoc] = model.objects.get(**query)
circuit, created = Circuit.objects.get_or_create(**params) circuit, created = Circuit.objects.get_or_create(**params)
if created: if created:
set_custom_fields_values(circuit, custom_field_data) set_custom_fields_values(circuit, custom_field_data)
print("⚡ Created Circuit", circuit.cid) print("⚡ Created Circuit", circuit.cid)

View File

@ -1,14 +1,15 @@
from secrets.models import SecretRole
from startup_script_utils import load_yaml
import sys import sys
from secrets.models import SecretRole
secret_roles = load_yaml('/opt/netbox/initializers/secret_roles.yml') from startup_script_utils import load_yaml
secret_roles = load_yaml("/opt/netbox/initializers/secret_roles.yml")
if secret_roles is None: if secret_roles is None:
sys.exit() sys.exit()
for params in secret_roles: for params in secret_roles:
secret_role, created = SecretRole.objects.get_or_create(**params) secret_role, created = SecretRole.objects.get_or_create(**params)
if created: if created:
print("🔑 Created Secret Role", secret_role.name) print("🔑 Created Secret Role", secret_role.name)

View File

@ -1,29 +1,30 @@
from ipam.models import Service
from dcim.models import Device
from virtualization.models import VirtualMachine
from startup_script_utils import load_yaml
import sys import sys
services = load_yaml('/opt/netbox/initializers/services.yml') from dcim.models import Device
from ipam.models import Service
from startup_script_utils import load_yaml
from virtualization.models import VirtualMachine
services = load_yaml("/opt/netbox/initializers/services.yml")
if services is None: if services is None:
sys.exit() sys.exit()
optional_assocs = { optional_assocs = {
'device': (Device, 'name'), "device": (Device, "name"),
'virtual_machine': (VirtualMachine, 'name') "virtual_machine": (VirtualMachine, "name"),
} }
for params in services: for params in services:
for assoc, details in optional_assocs.items(): for assoc, details in optional_assocs.items():
if assoc in params: if assoc in params:
model, field = details model, field = details
query = { field: params.pop(assoc) } query = {field: params.pop(assoc)}
params[assoc] = model.objects.get(**query) params[assoc] = model.objects.get(**query)
service, created = Service.objects.get_or_create(**params) service, created = Service.objects.get_or_create(**params)
if created: if created:
print("🧰 Created Service", service.name) print("🧰 Created Service", service.name)

View File

@ -1,41 +1,36 @@
import sys import sys
from dcim.models import Site, RackGroup, PowerPanel from dcim.models import PowerPanel, RackGroup, Site
from startup_script_utils import * from startup_script_utils import load_yaml, pop_custom_fields, set_custom_fields_values
from tenancy.models import Tenant
power_panels = load_yaml('/opt/netbox/initializers/power_panels.yml') power_panels = load_yaml("/opt/netbox/initializers/power_panels.yml")
if power_panels is None: if power_panels is None:
sys.exit() sys.exit()
required_assocs = { required_assocs = {"site": (Site, "name")}
'site': (Site, 'name')
}
optional_assocs = { optional_assocs = {"rack_group": (RackGroup, "name")}
'rack_group': (RackGroup, 'name')
}
for params in power_panels: for params in power_panels:
custom_field_data = pop_custom_fields(params) custom_field_data = pop_custom_fields(params)
for assoc, details in required_assocs.items(): for assoc, details in required_assocs.items():
model, field = details model, field = details
query = { field: params.pop(assoc) } query = {field: params.pop(assoc)}
params[assoc] = model.objects.get(**query) params[assoc] = model.objects.get(**query)
for assoc, details in optional_assocs.items(): for assoc, details in optional_assocs.items():
if assoc in params: if assoc in params:
model, field = details model, field = details
query = { field: params.pop(assoc) } query = {field: params.pop(assoc)}
params[assoc] = model.objects.get(**query) params[assoc] = model.objects.get(**query)
power_panel, created = PowerPanel.objects.get_or_create(**params) power_panel, created = PowerPanel.objects.get_or_create(**params)
if created: if created:
set_custom_fields_values(power_panel, custom_field_data) set_custom_fields_values(power_panel, custom_field_data)
print("⚡ Created Power Panel", power_panel.site, power_panel.name) print("⚡ Created Power Panel", power_panel.site, power_panel.name)

View File

@ -1,41 +1,36 @@
import sys import sys
from dcim.models import Rack, PowerPanel, PowerFeed from dcim.models import PowerFeed, PowerPanel, Rack
from startup_script_utils import * from startup_script_utils import load_yaml, pop_custom_fields, set_custom_fields_values
from tenancy.models import Tenant
power_feeds = load_yaml('/opt/netbox/initializers/power_feeds.yml') power_feeds = load_yaml("/opt/netbox/initializers/power_feeds.yml")
if power_feeds is None: if power_feeds is None:
sys.exit() sys.exit()
required_assocs = { required_assocs = {"power_panel": (PowerPanel, "name")}
'power_panel': (PowerPanel, 'name')
}
optional_assocs = { optional_assocs = {"rack": (Rack, "name")}
'rack': (Rack, 'name')
}
for params in power_feeds: for params in power_feeds:
custom_field_data = pop_custom_fields(params) custom_field_data = pop_custom_fields(params)
for assoc, details in required_assocs.items(): for assoc, details in required_assocs.items():
model, field = details model, field = details
query = { field: params.pop(assoc) } query = {field: params.pop(assoc)}
params[assoc] = model.objects.get(**query) params[assoc] = model.objects.get(**query)
for assoc, details in optional_assocs.items(): for assoc, details in optional_assocs.items():
if assoc in params: if assoc in params:
model, field = details model, field = details
query = { field: params.pop(assoc) } query = {field: params.pop(assoc)}
params[assoc] = model.objects.get(**query) params[assoc] = model.objects.get(**query)
power_feed, created = PowerFeed.objects.get_or_create(**params) power_feed, created = PowerFeed.objects.get_or_create(**params)
if created: if created:
set_custom_fields_values(power_feed, custom_field_data) set_custom_fields_values(power_feed, custom_field_data)
print("⚡ Created Power Feed", power_feed.name) print("⚡ Created Power Feed", power_feed.name)

View File

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

View File

@ -1,3 +1,3 @@
from .custom_fields import pop_custom_fields, set_custom_fields_values
from .load_yaml import load_yaml from .load_yaml import load_yaml
from .permissions import set_permissions from .permissions import set_permissions
from .custom_fields import set_custom_fields_values, pop_custom_fields

View File

@ -1,15 +1,16 @@
def set_custom_fields_values(entity, custom_field_data): def set_custom_fields_values(entity, custom_field_data):
if not custom_field_data: if not custom_field_data:
return return
entity.custom_field_data = custom_field_data
return entity.save()
entity.custom_field_data = custom_field_data
return entity.save()
def pop_custom_fields(params): def pop_custom_fields(params):
if 'custom_field_data' in params: if "custom_field_data" in params:
return params.pop('custom_field_data') return params.pop("custom_field_data")
elif 'custom_fields' in params: elif "custom_fields" in params:
print("⚠️ Please rename 'custom_fields' to 'custom_field_data'!") print("⚠️ Please rename 'custom_fields' to 'custom_field_data'!")
return params.pop('custom_fields') return params.pop("custom_fields")
return None return None

View File

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

View File

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

View File

@ -28,7 +28,7 @@ if [ -z "${IMAGE}" ]; then
echo "⚠️ No image defined" echo "⚠️ No image defined"
if [ -z "${DEBUG}" ]; then if [ -z "${DEBUG}" ]; then
exit 1; exit 1
else else
echo "⚠️ Would 'exit 1' here, but DEBUG is '${DEBUG}'." echo "⚠️ Would 'exit 1' here, but DEBUG is '${DEBUG}'."
fi fi
@ -49,7 +49,7 @@ test_setup() {
( (
cd initializers cd initializers
for script in *.yml; do for script in *.yml; do
sed -E 's/^# //' "${script}" > "../${INITIALIZERS_DIR}/${script}" sed -E 's/^# //' "${script}" >"../${INITIALIZERS_DIR}/${script}"
done done
) )
} }