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

@ -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

@ -60,8 +60,9 @@ 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}" ] &&
[ "${MINOR_STABLE}" -ge "${MINOR_UNSTABLE}" ]
} || [ "${MAJOR_STABLE}" -gt "${MAJOR_UNSTABLE}" ]; then } || [ "${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'."

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

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(
AUTH_LDAP_USER_SEARCH_BASEDN,
ldap.SCOPE_SUBTREE, ldap.SCOPE_SUBTREE,
"(" + AUTH_LDAP_USER_SEARCH_ATTR + "=%(user)s)") "(" + 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,10 +4,10 @@
# #
# 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):
@ -15,7 +15,7 @@ def _filename(f):
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
@ -28,9 +28,9 @@ def _import(module_name, path, loaded_configurations):
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.")
@ -39,13 +39,13 @@ def read_configurations(config_module, config_dir, main_config):
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(".", "_")
@ -66,9 +66,10 @@ 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):

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,9 +22,10 @@ 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=$(
curl \
--silent \ --silent \
--output /dev/null \ --output /dev/null \
--write-out '%{http_code}' \ --write-out '%{http_code}' \

View File

@ -1,9 +1,10 @@
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):
@ -14,6 +15,7 @@ def __getattr__(name):
pass pass
raise AttributeError raise AttributeError
def __dir__(): def __dir__():
names = [] names = []
for config in _loaded_configurations: for config in _loaded_configurations:

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

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,7 +3,7 @@ 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()
@ -13,11 +13,11 @@ for groupname, group_details in groups.items():
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,8 +3,10 @@ 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 from django.contrib.contenttypes.models import ContentType
module_name, class_name = class_path.rsplit(".", 1) module_name, class_name = class_path.rsplit(".", 1)
@ -12,44 +14,48 @@ def get_class_for_class_path(class_path):
clazz = getattr(module, class_name) clazz = getattr(module, class_name)
return ContentType.objects.get_for_model(clazz) return ContentType.objects.get_for_model(clazz)
customfields = load_yaml('/opt/netbox/initializers/custom_fields.yml')
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}'"
+ " to the new format, as 'weight' is no longer supported!"
)
custom_field.choices.append(choice_detail["value"])
else: else:
custom_field.choices.append(choice_detail) custom_field.choices.append(choice_detail)

View File

@ -1,21 +1,21 @@
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)

View File

@ -1,22 +1,21 @@
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)

View File

@ -1,18 +1,15 @@
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)
@ -20,7 +17,7 @@ for params in sites:
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)

View File

@ -1,8 +1,9 @@
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()

View File

@ -1,36 +1,31 @@
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)

View File

@ -1,21 +1,21 @@
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)

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: if created:
print("🎨 Created rack group", rack_group.name) print("🎨 Created rack group", rack_group.name)

View File

@ -1,22 +1,20 @@
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:
@ -24,14 +22,14 @@ for params in racks:
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)

View File

@ -1,22 +1,22 @@
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)

View File

@ -1,14 +1,15 @@
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:
@ -16,7 +17,7 @@ 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)

View File

@ -1,8 +1,9 @@
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()

View File

@ -1,16 +1,14 @@
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)
@ -18,7 +16,7 @@ for params in tenants:
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)

View File

@ -1,8 +1,9 @@
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()

View File

@ -1,8 +1,9 @@
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()

View File

@ -1,23 +1,21 @@
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:
@ -25,14 +23,14 @@ for params in clusters:
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)

View File

@ -1,23 +1,21 @@
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:
@ -25,14 +23,14 @@ for params in clusters:
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)

View File

@ -1,45 +1,45 @@
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)

View File

@ -1,45 +1,45 @@
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)

View File

@ -1,8 +1,9 @@
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()

View File

@ -1,38 +1,36 @@
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)

View File

@ -1,8 +1,9 @@
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()

View File

@ -1,17 +1,15 @@
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)
@ -19,7 +17,7 @@ for params in route_targets:
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)

View File

@ -1,17 +1,15 @@
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)
@ -19,7 +17,7 @@ for params in vrfs:
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)

View File

@ -1,8 +1,9 @@
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()

View File

@ -2,16 +2,14 @@ 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)
@ -19,7 +17,7 @@ for params in vlan_groups:
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)

View File

@ -1,21 +1,21 @@
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:
@ -24,7 +24,7 @@ for params in vlans:
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)

View File

@ -1,34 +1,34 @@
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)

View File

@ -1,42 +1,40 @@
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)

View File

@ -1,23 +1,21 @@
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)

View File

@ -1,23 +1,21 @@
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)

View File

@ -5,30 +5,32 @@ 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() sys.exit()
optional_assocs = { optional_assocs = {
'tenant': (Tenant, 'name'), "tenant": (Tenant, "name"),
'vrf': (VRF, 'name'), "vrf": (VRF, "name"),
'interface': (None, None) "interface": (None, None),
} }
vm_interface_ct = ContentType.objects.filter(Q(app_label='virtualization', model='vminterface')).first() vm_interface_ct = ContentType.objects.filter(
interface_ct = ContentType.objects.filter(Q(app_label='dcim', model='interface')).first() Q(app_label="virtualization", model="vminterface")
).first()
interface_ct = ContentType.objects.filter(Q(app_label="dcim", model="interface")).first()
for params in ip_addresses: for params in ip_addresses:
custom_field_data = pop_custom_fields(params) custom_field_data = pop_custom_fields(params)
vm = params.pop('virtual_machine', None) vm = params.pop("virtual_machine", None)
device = params.pop('device', None) device = params.pop("device", None)
params['address'] = IPNetwork(params['address']) params["address"] = IPNetwork(params["address"])
if vm and device: if vm and device:
print("IP Address can only specify one of the following: virtual_machine or device.") print("IP Address can only specify one of the following: virtual_machine or device.")
@ -37,19 +39,19 @@ for params in ip_addresses:
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
if assoc == 'interface': if assoc == "interface":
if vm: if vm:
vm_id = VirtualMachine.objects.get(name=vm).id vm_id = VirtualMachine.objects.get(name=vm).id
query = { 'name': params.pop(assoc), "virtual_machine_id": vm_id } query = {"name": params.pop(assoc), "virtual_machine_id": vm_id}
params['assigned_object_type'] = vm_interface_ct params["assigned_object_type"] = vm_interface_ct
params['assigned_object_id'] = VMInterface.objects.get(**query).id params["assigned_object_id"] = VMInterface.objects.get(**query).id
elif device: elif device:
dev_id = Device.objects.get(name=device).id dev_id = Device.objects.get(name=device).id
query = { 'name': params.pop(assoc), "device_id": dev_id } query = {"name": params.pop(assoc), "device_id": dev_id}
params['assigned_object_type'] = interface_ct params["assigned_object_type"] = interface_ct
params['assigned_object_id'] = Interface.objects.get(**query).id params["assigned_object_id"] = Interface.objects.get(**query).id
else: else:
query = { field: params.pop(assoc) } query = {field: params.pop(assoc)}
params[assoc] = model.objects.get(**query) params[assoc] = model.objects.get(**query)
ip_address, created = IPAddress.objects.get_or_create(**params) ip_address, created = IPAddress.objects.get_or_create(**params)

View File

@ -1,19 +1,21 @@
import sys
from dcim.models import Device from dcim.models import Device
from ipam.models import IPAddress from ipam.models import IPAddress
from virtualization.models import VirtualMachine
from startup_script_utils import load_yaml from startup_script_utils import load_yaml
import sys 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)
@ -21,19 +23,20 @@ def link_primary_ip(assets, asset_model):
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:

View File

@ -1,10 +1,10 @@
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()
@ -18,10 +18,14 @@ def get_content_type_id(content_type):
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(
"⚠️ Unable to create Custom Link '{0}': The content_type '{1}' is unknown".format(
link.name, content_type
)
)
continue continue
custom_link, created = CustomLink.objects.get_or_create(**link) custom_link, created = CustomLink.objects.get_or_create(**link)

View File

@ -1,8 +1,9 @@
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()

View File

@ -1,8 +1,9 @@
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()

View File

@ -1,10 +1,10 @@
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()
@ -19,10 +19,10 @@ def get_content_type_id(hook_name, content_type):
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

View File

@ -1,35 +1,31 @@
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)

View File

@ -1,8 +1,9 @@
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()

View File

@ -1,17 +1,18 @@
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:
@ -19,7 +20,7 @@ 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)

View File

@ -1,35 +1,30 @@
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)

View File

@ -1,35 +1,30 @@
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)

View File

@ -2,22 +2,24 @@
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}")

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

@ -5,11 +5,12 @@ def set_custom_fields_values(entity, custom_field_data):
entity.custom_field_data = custom_field_data entity.custom_field_data = custom_field_data
return entity.save() 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,4 +1,5 @@
from pathlib import Path from pathlib import Path
from ruamel.yaml import YAML from ruamel.yaml import YAML

View File

@ -9,7 +9,11 @@ def set_permissions(subject, 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(
" ⚿ Granting",
permissions.count(),
"permissions matching '" + permission_filter + "'",
)
else: else:
permissions = Permission.objects.filter(codename=permission_filter) permissions = Permission.objects.filter(codename=permission_filter)
print(" ⚿ Granting permission", permission_filter) print(" ⚿ Granting permission", permission_filter)

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
) )
} }