diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index 3293aff..608e6e0 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -19,7 +19,7 @@ fetch-depth: 0 - uses: actions/setup-python@v2 - name: Lint Code Base - uses: github/super-linter@v3 + uses: github/super-linter@v4 env: DEFAULT_BRANCH: develop GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/Dockerfile b/Dockerfile index 280a9c6..c636a04 100644 --- a/Dockerfile +++ b/Dockerfile @@ -11,7 +11,7 @@ jpeg-dev \ libevent-dev \ libffi-dev \ - libressl-dev \ + openssl-dev \ libxslt-dev \ musl-dev \ openldap-dev \ @@ -45,12 +45,11 @@ libevent \ libffi \ libjpeg-turbo \ - libressl \ + openssl \ libxslt \ postgresql-libs \ python3 \ py3-pip \ - ttf-ubuntu-font-family \ unit \ unit-python3 @@ -75,6 +74,8 @@ # to g+w so that pictures can be uploaded to netbox. RUN mkdir -p static /opt/unit/state/ /opt/unit/tmp/ \ && chmod -R g+w media /opt/unit/ \ + && cd /opt/netbox/ && /opt/netbox/venv/bin/python -m mkdocs build \ + --config-file /opt/netbox/mkdocs.yml --site-dir /opt/netbox/netbox/project-static/docs/ \ && SECRET_KEY="dummy" /opt/netbox/venv/bin/python /opt/netbox/netbox/manage.py collectstatic --no-input ENTRYPOINT [ "/opt/netbox/docker-entrypoint.sh" ] diff --git a/VERSION b/VERSION index 26aaba0..f0bb29e 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.2.0 +1.3.0 diff --git a/build.sh b/build.sh index 82084bf..e980411 100755 --- a/build.sh +++ b/build.sh @@ -49,7 +49,7 @@ echo " DOCKERFILE The name of Dockerfile to use." echo " Default: Dockerfile" echo " DOCKER_FROM The base image to use." - echo " Default: 'alpine:3.13'" + echo " Default: 'alpine:3.14'" echo " DOCKER_TARGET A specific target to build." echo " It's currently not possible to pass multiple targets." echo " Default: main ldap" @@ -125,7 +125,7 @@ ( $DRY cd "${NETBOX_PATH}" - + # shellcheck disable=SC2030 if [ -n "${HTTP_PROXY}" ]; then git config http.proxy "${HTTP_PROXY}" fi @@ -157,7 +157,7 @@ # Determining the value for DOCKER_FROM ### if [ -z "$DOCKER_FROM" ]; then - DOCKER_FROM="alpine:3.13" + DOCKER_FROM="alpine:3.14" fi ### @@ -345,6 +345,7 @@ if [ -n "${DOCKER_FROM}" ]; then DOCKER_BUILD_ARGS+=(--build-arg "FROM=${DOCKER_FROM}") fi + # shellcheck disable=SC2031 if [ -n "${HTTP_PROXY}" ]; then DOCKER_BUILD_ARGS+=(--build-arg "http_proxy=${HTTP_PROXY}") DOCKER_BUILD_ARGS+=(--build-arg "https_proxy=${HTTPS_PROXY}") diff --git a/configuration/configuration.py b/configuration/configuration.py index 727f7b3..87435cf 100644 --- a/configuration/configuration.py +++ b/configuration/configuration.py @@ -48,6 +48,8 @@ # Database connection SSLMODE 'CONN_MAX_AGE': int(environ.get('DB_CONN_MAX_AGE', '300')), # Max database connection age + 'DISABLE_SERVER_SIDE_CURSORS': environ.get('DB_DISABLE_SERVER_SIDE_CURSORS', 'False').lower() == 'true', + # Disable the use of server-side cursors transaction pooling } # Redis database settings. Redis is used for caching and for queuing background tasks such as webhook events. A separate @@ -106,9 +108,6 @@ # BASE_PATH = 'netbox/' BASE_PATH = environ.get('BASE_PATH', '') -# Cache timeout in seconds. Set to 0 to dissable caching. Defaults to 900 (15 minutes) -CACHE_TIMEOUT = int(environ.get('CACHE_TIMEOUT', 900)) - # Maximum number of days to retain logged changes. Set to 0 to retain changes indefinitely. (Default: 90) CHANGELOG_RETENTION = int(environ.get('CHANGELOG_RETENTION', 90)) @@ -210,9 +209,6 @@ REMOTE_AUTH_AUTO_CREATE_USER = environ.get('REMOTE_AUTH_AUTO_CREATE_USER', 'True').lower() == 'true' REMOTE_AUTH_DEFAULT_GROUPS = list(filter(None, environ.get('REMOTE_AUTH_DEFAULT_GROUPS', '').split(' '))) -# This determines how often the GitHub API is called to check the latest release of NetBox. Must be at least 1 hour. -RELEASE_CHECK_TIMEOUT = int(environ.get('RELEASE_CHECK_TIMEOUT', 24 * 3600)) - # This repository is used to check whether there is a new release of NetBox available. Set to None to disable the # version check or use the URL below to check for release in the official NetBox repository. # https://api.github.com/repos/netbox-community/netbox/releases diff --git a/docker-compose.test.yml b/docker-compose.test.yml index 8233bf6..df681d2 100644 --- a/docker-compose.test.yml +++ b/docker-compose.test.yml @@ -20,7 +20,7 @@ ports: - 8080 postgres: - image: postgres:12-alpine + image: postgres:13-alpine env_file: env/postgres.env redis: image: redis:6-alpine diff --git a/docker-compose.yml b/docker-compose.yml index 7bec177..e38aa0c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,7 +1,7 @@ version: '3.4' services: netbox: &netbox - image: netboxcommunity/netbox:${VERSION-latest} + image: netboxcommunity/netbox:${VERSION-v3.0} depends_on: - postgres - redis @@ -29,7 +29,7 @@ # postgres postgres: - image: postgres:12-alpine + image: postgres:13-alpine env_file: env/postgres.env volumes: - netbox-postgres-data:/var/lib/postgresql/data diff --git a/docker/docker-entrypoint.sh b/docker/docker-entrypoint.sh index c39453d..1610d8f 100755 --- a/docker/docker-entrypoint.sh +++ b/docker/docker-entrypoint.sh @@ -15,7 +15,7 @@ DB_WAIT_TIMEOUT=${DB_WAIT_TIMEOUT-3} MAX_DB_WAIT_TIME=${MAX_DB_WAIT_TIME-30} CUR_DB_WAIT_TIME=0 -while ! ./manage.py migrate 2>&1 && [ "${CUR_DB_WAIT_TIME}" -lt "${MAX_DB_WAIT_TIME}" ]; do +while ! ./manage.py showmigrations >/dev/null 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)" sleep "${DB_WAIT_TIMEOUT}" CUR_DB_WAIT_TIME=$((CUR_DB_WAIT_TIME + DB_WAIT_TIMEOUT)) @@ -24,6 +24,17 @@ echo "❌ Waited ${MAX_DB_WAIT_TIME}s or more for the DB to become ready." exit 1 fi +# Check if update is needed +if ! ./manage.py migrate --check >/dev/null 2>&1; then + echo "⚙️ Applying database migrations" + ./manage.py migrate --no-input + echo "⚙️ Running trace_paths" + ./manage.py trace_paths --no-input + echo "⚙️ Removing stale content types" + ./manage.py remove_stale_contenttypes --no-input + echo "⚙️ Removing expired user sessions" + ./manage.py clearsessions +fi # Create Superuser if required if [ "$SKIP_SUPERUSER" == "true" ]; then diff --git a/initializers/secret_roles.yml b/initializers/secret_roles.yml deleted file mode 100644 index 239906a..0000000 --- a/initializers/secret_roles.yml +++ /dev/null @@ -1,4 +0,0 @@ -# - name: Super Secret Passwords -# slug: super-secret -# - name: SNMP Communities -# slug: snmp diff --git a/initializers/sites.yml b/initializers/sites.yml index 0015f4e..7ace3aa 100644 --- a/initializers/sites.yml +++ b/initializers/sites.yml @@ -20,6 +20,7 @@ # status: active # facility: Amsterdam 3 # asn: 67890 +# tenant: tenant1 # custom_field_data: # text_field: Description for AMS3 # - name: SING 1 @@ -28,5 +29,6 @@ # status: active # facility: Singapore 1 # asn: 09876 +# tenant: tenant2 # custom_field_data: # text_field: Description for SING1 diff --git a/renovate.json b/renovate.json index b98598c..ac1b258 100644 --- a/renovate.json +++ b/renovate.json @@ -1,6 +1,7 @@ { "extends": [ - "config:base" + "config:base", + ":disableDependencyDashboard" ], "enabled": true, "labels": ["maintenance"], diff --git a/requirements-container.txt b/requirements-container.txt index 450c322..cc48128 100644 --- a/requirements-container.txt +++ b/requirements-container.txt @@ -1,4 +1,4 @@ -napalm==3.2.0 -ruamel.yaml==0.17.4 -django-auth-ldap==2.4.0 +napalm==3.3.1 +ruamel.yaml==0.17.16 +django-auth-ldap==3.0.0 django-storages[azure,boto3,dropbox,google,libcloud,sftp]==1.11.1 diff --git a/startup_scripts/020_tenant_groups.py b/startup_scripts/020_tenant_groups.py new file mode 100644 index 0000000..65cf155 --- /dev/null +++ b/startup_scripts/020_tenant_groups.py @@ -0,0 +1,15 @@ +import sys + +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: + sys.exit() + +for params in tenant_groups: + tenant_group, created = TenantGroup.objects.get_or_create(**params) + + if created: + print("🔳 Created Tenant Group", tenant_group.name) diff --git a/startup_scripts/030_tenants.py b/startup_scripts/030_tenants.py new file mode 100644 index 0000000..7b1a629 --- /dev/null +++ b/startup_scripts/030_tenants.py @@ -0,0 +1,28 @@ +import sys + +from startup_script_utils import load_yaml, pop_custom_fields, set_custom_fields_values +from tenancy.models import Tenant, TenantGroup + +tenants = load_yaml("/opt/netbox/initializers/tenants.yml") + +if tenants is None: + sys.exit() + +optional_assocs = {"group": (TenantGroup, "name")} + +for params in tenants: + custom_field_data = pop_custom_fields(params) + + for assoc, details in optional_assocs.items(): + if assoc in params: + model, field = details + query = {field: params.pop(assoc)} + + params[assoc] = model.objects.get(**query) + + tenant, created = Tenant.objects.get_or_create(**params) + + if created: + set_custom_fields_values(tenant, custom_field_data) + + print("👩‍💻 Created Tenant", tenant.name) diff --git a/startup_scripts/110_tenant_groups.py b/startup_scripts/110_tenant_groups.py deleted file mode 100644 index 65cf155..0000000 --- a/startup_scripts/110_tenant_groups.py +++ /dev/null @@ -1,15 +0,0 @@ -import sys - -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: - sys.exit() - -for params in tenant_groups: - tenant_group, created = TenantGroup.objects.get_or_create(**params) - - if created: - print("🔳 Created Tenant Group", tenant_group.name) diff --git a/startup_scripts/120_tenants.py b/startup_scripts/120_tenants.py deleted file mode 100644 index 7b1a629..0000000 --- a/startup_scripts/120_tenants.py +++ /dev/null @@ -1,28 +0,0 @@ -import sys - -from startup_script_utils import load_yaml, pop_custom_fields, set_custom_fields_values -from tenancy.models import Tenant, TenantGroup - -tenants = load_yaml("/opt/netbox/initializers/tenants.yml") - -if tenants is None: - sys.exit() - -optional_assocs = {"group": (TenantGroup, "name")} - -for params in tenants: - custom_field_data = pop_custom_fields(params) - - for assoc, details in optional_assocs.items(): - if assoc in params: - model, field = details - query = {field: params.pop(assoc)} - - params[assoc] = model.objects.get(**query) - - tenant, created = Tenant.objects.get_or_create(**params) - - if created: - set_custom_fields_values(tenant, custom_field_data) - - print("👩‍💻 Created Tenant", tenant.name) diff --git a/startup_scripts/310_secret_roles.py b/startup_scripts/310_secret_roles.py deleted file mode 100644 index 02dcd88..0000000 --- a/startup_scripts/310_secret_roles.py +++ /dev/null @@ -1,15 +0,0 @@ -import sys -from secrets.models import SecretRole - -from startup_script_utils import load_yaml - -secret_roles = load_yaml("/opt/netbox/initializers/secret_roles.yml") - -if secret_roles is None: - sys.exit() - -for params in secret_roles: - secret_role, created = SecretRole.objects.get_or_create(**params) - - if created: - print("🔑 Created Secret Role", secret_role.name)