mirror of
https://github.com/lucaspalomodevelop/netbox-acls.git
synced 2026-03-12 23:27:23 +00:00
Added testing framework (#121)
* added api test case for access list * initial testing framework
This commit is contained in:
parent
9611816fe8
commit
e43b5e41f1
3
.github/linters/.flake8
vendored
3
.github/linters/.flake8
vendored
@ -1,3 +0,0 @@
|
|||||||
[flake8]
|
|
||||||
max-line-length = 160
|
|
||||||
extend-ignore = E203
|
|
||||||
8
.github/linters/.isort.cfg
vendored
8
.github/linters/.isort.cfg
vendored
@ -1,8 +0,0 @@
|
|||||||
[settings]
|
|
||||||
profile = black
|
|
||||||
|
|
||||||
; vertical hanging indent mode also used in black configuration
|
|
||||||
multi_line_output = 3
|
|
||||||
|
|
||||||
; necessary because black expect the trailing comma
|
|
||||||
include_trailing_comma = true
|
|
||||||
3
.github/linters/.jscpd.json
vendored
3
.github/linters/.jscpd.json
vendored
@ -1,3 +0,0 @@
|
|||||||
{
|
|
||||||
"threshold": 10
|
|
||||||
}
|
|
||||||
46
.github/workflows/ci.yml
vendored
Normal file
46
.github/workflows/ci.yml
vendored
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
name: CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
# This ensures that previous jobs for the workflow are canceled when the ref is
|
||||||
|
# updated.
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
run-lint:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
# Full git history is needed to get a proper list of changed files within `super-linter`
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Lint Code Base
|
||||||
|
uses: github/super-linter/slim@v4
|
||||||
|
env:
|
||||||
|
DEFAULT_BRANCH: dev
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
SUPPRESS_POSSUM: true
|
||||||
|
LINTER_RULES_PATH: /
|
||||||
|
VALIDATE_ALL_CODEBASE: false
|
||||||
|
VALIDATE_DOCKERFILE: false
|
||||||
|
VALIDATE_JSCPD: true
|
||||||
|
FILTER_REGEX_EXCLUDE: (.*/)?(configuration/.*)
|
||||||
|
|
||||||
|
test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
name: Runs plugin tests
|
||||||
|
needs: run-lint
|
||||||
|
steps:
|
||||||
|
- id: git-checkout
|
||||||
|
name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- id: docker-test
|
||||||
|
name: Test the image
|
||||||
|
run: ./test.sh snapshot
|
||||||
30
.github/workflows/super-linter.yml
vendored
30
.github/workflows/super-linter.yml
vendored
@ -1,30 +0,0 @@
|
|||||||
---
|
|
||||||
# This workflow executes several linters on changed files based on languages used in your code base whenever
|
|
||||||
# you push a code or open a pull request.
|
|
||||||
#
|
|
||||||
# You can adjust the behavior by modifying this file.
|
|
||||||
# For more information, see:
|
|
||||||
# https://github.com/github/super-linter
|
|
||||||
name: Lint Code Base
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: ["dev"]
|
|
||||||
pull_request:
|
|
||||||
branches: ["dev"]
|
|
||||||
jobs:
|
|
||||||
run-lint:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout code
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
with:
|
|
||||||
# Full git history is needed to get a proper list of changed files within `super-linter`
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: Lint Code Base
|
|
||||||
uses: github/super-linter/slim@v4
|
|
||||||
env:
|
|
||||||
VALIDATE_ALL_CODEBASE: false
|
|
||||||
DEFAULT_BRANCH: "dev"
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
4
.jscpd.json
Normal file
4
.jscpd.json
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"threshold": 10,
|
||||||
|
"ignore": ["**/tests/**"]
|
||||||
|
}
|
||||||
@ -9,6 +9,8 @@ repos:
|
|||||||
- id: debug-statements
|
- id: debug-statements
|
||||||
- id: end-of-file-fixer
|
- id: end-of-file-fixer
|
||||||
- id: name-tests-test
|
- id: name-tests-test
|
||||||
|
args:
|
||||||
|
- "--django"
|
||||||
- id: requirements-txt-fixer
|
- id: requirements-txt-fixer
|
||||||
- id: trailing-whitespace
|
- id: trailing-whitespace
|
||||||
- repo: https://github.com/PyCQA/isort
|
- repo: https://github.com/PyCQA/isort
|
||||||
|
|||||||
9
Dockerfile
Normal file
9
Dockerfile
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
ARG NETBOX_VARIANT=v3.4
|
||||||
|
|
||||||
|
FROM netboxcommunity/netbox:${NETBOX_VARIANT}
|
||||||
|
|
||||||
|
RUN mkdir -pv /plugins/netbox-acls
|
||||||
|
COPY . /plugins/netbox-acls
|
||||||
|
|
||||||
|
RUN /opt/netbox/venv/bin/python3 /plugins/netbox-acls/setup.py develop
|
||||||
|
RUN cp -rf /plugins/netbox-acls/netbox_acls/ /opt/netbox/venv/lib/python3.10/site-packages/netbox_acls
|
||||||
@ -1,4 +1,3 @@
|
|||||||
include README.md
|
include README.md
|
||||||
include LICENSE
|
include LICENSE
|
||||||
recursive-include netbox_acls/templates *
|
recursive-include netbox_acls/templates *
|
||||||
recursive-include netbox_acls/static *
|
|
||||||
|
|||||||
99
configuration/configuration.py
Normal file
99
configuration/configuration.py
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
####
|
||||||
|
## We recommend to not edit this file.
|
||||||
|
## Create separate files to overwrite the settings.
|
||||||
|
## See `extra.py` as an example.
|
||||||
|
####
|
||||||
|
|
||||||
|
from os import environ
|
||||||
|
from os.path import abspath, dirname
|
||||||
|
|
||||||
|
# For reference see https://netbox.readthedocs.io/en/stable/configuration/
|
||||||
|
# Based on https://github.com/netbox-community/netbox/blob/master/netbox/netbox/configuration.example.py
|
||||||
|
|
||||||
|
# Read secret from file
|
||||||
|
def _read_secret(secret_name, default=None):
|
||||||
|
try:
|
||||||
|
f = open("/run/secrets/" + secret_name, encoding="utf-8")
|
||||||
|
except OSError:
|
||||||
|
return default
|
||||||
|
else:
|
||||||
|
with f:
|
||||||
|
return f.readline().strip()
|
||||||
|
|
||||||
|
|
||||||
|
_BASE_DIR = dirname(dirname(abspath(__file__)))
|
||||||
|
|
||||||
|
#########################
|
||||||
|
# #
|
||||||
|
# Required settings #
|
||||||
|
# #
|
||||||
|
#########################
|
||||||
|
|
||||||
|
# This is a list of valid fully-qualified domain names (FQDNs) for the NetBox server. NetBox will not permit write
|
||||||
|
# access to the server via any other hostnames. The first FQDN in the list will be treated as the preferred name.
|
||||||
|
#
|
||||||
|
# Example: ALLOWED_HOSTS = ['netbox.example.com', 'netbox.internal.local']
|
||||||
|
ALLOWED_HOSTS = environ.get("ALLOWED_HOSTS", "*").split(" ")
|
||||||
|
|
||||||
|
# PostgreSQL database configuration. See the Django documentation for a complete list of available parameters:
|
||||||
|
# https://docs.djangoproject.com/en/stable/ref/settings/#databases
|
||||||
|
DATABASE = {
|
||||||
|
"NAME": environ.get("DB_NAME", "netbox"), # Database name
|
||||||
|
"USER": environ.get("DB_USER", ""), # PostgreSQL username
|
||||||
|
"PASSWORD": _read_secret("db_password", environ.get("DB_PASSWORD", "")),
|
||||||
|
# PostgreSQL password
|
||||||
|
"HOST": environ.get("DB_HOST", "localhost"), # Database server
|
||||||
|
"PORT": environ.get("DB_PORT", ""), # Database port (leave blank for default)
|
||||||
|
"OPTIONS": {"sslmode": environ.get("DB_SSLMODE", "prefer")},
|
||||||
|
# Database connection SSLMODE
|
||||||
|
"CONN_MAX_AGE": int(environ.get("DB_CONN_MAX_AGE", "300")),
|
||||||
|
# Max database connection age
|
||||||
|
"DISABLE_SERVER_SIDE_CURSORS": environ.get(
|
||||||
|
"DB_DISABLE_SERVER_SIDE_CURSORS",
|
||||||
|
"False",
|
||||||
|
).lower()
|
||||||
|
== "true",
|
||||||
|
# Disable the use of server-side cursors transaction pooling
|
||||||
|
}
|
||||||
|
|
||||||
|
# Redis database settings. Redis is used for caching and for queuing background tasks such as webhook events. A separate
|
||||||
|
# configuration exists for each. Full connection details are required in both sections, and it is strongly recommended
|
||||||
|
# to use two separate database IDs.
|
||||||
|
REDIS = {
|
||||||
|
"tasks": {
|
||||||
|
"HOST": environ.get("REDIS_HOST", "localhost"),
|
||||||
|
"PORT": int(environ.get("REDIS_PORT", 6379)),
|
||||||
|
"PASSWORD": _read_secret("redis_password", environ.get("REDIS_PASSWORD", "")),
|
||||||
|
"DATABASE": int(environ.get("REDIS_DATABASE", 0)),
|
||||||
|
"SSL": environ.get("REDIS_SSL", "False").lower() == "true",
|
||||||
|
"INSECURE_SKIP_TLS_VERIFY": environ.get(
|
||||||
|
"REDIS_INSECURE_SKIP_TLS_VERIFY",
|
||||||
|
"False",
|
||||||
|
).lower()
|
||||||
|
== "true",
|
||||||
|
},
|
||||||
|
"caching": {
|
||||||
|
"HOST": environ.get("REDIS_CACHE_HOST", environ.get("REDIS_HOST", "localhost")),
|
||||||
|
"PORT": int(environ.get("REDIS_CACHE_PORT", environ.get("REDIS_PORT", 6379))),
|
||||||
|
"PASSWORD": _read_secret(
|
||||||
|
"redis_cache_password",
|
||||||
|
environ.get("REDIS_CACHE_PASSWORD", environ.get("REDIS_PASSWORD", "")),
|
||||||
|
),
|
||||||
|
"DATABASE": int(environ.get("REDIS_CACHE_DATABASE", 1)),
|
||||||
|
"SSL": environ.get("REDIS_CACHE_SSL", environ.get("REDIS_SSL", "False")).lower()
|
||||||
|
== "true",
|
||||||
|
"INSECURE_SKIP_TLS_VERIFY": environ.get(
|
||||||
|
"REDIS_CACHE_INSECURE_SKIP_TLS_VERIFY",
|
||||||
|
environ.get("REDIS_INSECURE_SKIP_TLS_VERIFY", "False"),
|
||||||
|
).lower()
|
||||||
|
== "true",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
# This key is used for secure generation of random numbers and strings. It must never be exposed outside of this file.
|
||||||
|
# For optimal security, SECRET_KEY should be at least 50 characters in length and contain a mix of letters, numbers, and
|
||||||
|
# symbols. NetBox will not run without this defined. For more information, see
|
||||||
|
# https://docs.djangoproject.com/en/stable/ref/settings/#std:setting-SECRET_KEY
|
||||||
|
SECRET_KEY = _read_secret("secret_key", environ.get("SECRET_KEY", ""))
|
||||||
|
|
||||||
|
DEVELOPER = True
|
||||||
11
configuration/logging.py
Normal file
11
configuration/logging.py
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
# Remove first comment(#) on each line to implement this working logging example.
|
||||||
|
# Add LOGLEVEL environment variable to netbox if you use this example & want a different log level.
|
||||||
|
from os import environ
|
||||||
|
|
||||||
|
# Set LOGLEVEL in netbox.env or docker-compose.overide.yml to override a logging level of INFO.
|
||||||
|
LOGLEVEL = environ.get("LOGLEVEL", "INFO")
|
||||||
|
|
||||||
|
LOGGING = {
|
||||||
|
"version": 1,
|
||||||
|
"disable_existing_loggers": True,
|
||||||
|
}
|
||||||
13
configuration/plugins.py
Normal file
13
configuration/plugins.py
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
# Add your plugins and plugin settings here.
|
||||||
|
# Of course uncomment this file out.
|
||||||
|
|
||||||
|
# To learn how to build images with your required plugins
|
||||||
|
# See https://github.com/netbox-community/netbox-docker/wiki/Using-Netbox-Plugins
|
||||||
|
|
||||||
|
PLUGINS = [
|
||||||
|
"netbox_acls",
|
||||||
|
]
|
||||||
|
|
||||||
|
PLUGINS_CONFIG = { # type: ignore
|
||||||
|
"netbox_acls": {},
|
||||||
|
}
|
||||||
29
docker-compose.yml
Normal file
29
docker-compose.yml
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
version: '3.4'
|
||||||
|
|
||||||
|
services:
|
||||||
|
netbox:
|
||||||
|
build:
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
context: .
|
||||||
|
args:
|
||||||
|
NETBOX_VARIANT: ${NETBOX_VARIANT}
|
||||||
|
depends_on:
|
||||||
|
- postgres
|
||||||
|
- redis
|
||||||
|
env_file: env/netbox.env
|
||||||
|
volumes:
|
||||||
|
- ./configuration:/etc/netbox/config:z,ro
|
||||||
|
|
||||||
|
# postgres
|
||||||
|
postgres:
|
||||||
|
image: postgres:14-alpine
|
||||||
|
env_file: env/postgres.env
|
||||||
|
|
||||||
|
# redis
|
||||||
|
redis:
|
||||||
|
image: redis:6-alpine
|
||||||
|
command:
|
||||||
|
- sh
|
||||||
|
- -c # this is to evaluate the $REDIS_PASSWORD from the env
|
||||||
|
- redis-server --appendonly yes --requirepass $$REDIS_PASSWORD ## $$ because of docker-compose
|
||||||
|
env_file: env/redis.env
|
||||||
23
env/netbox.env
vendored
Normal file
23
env/netbox.env
vendored
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
ALLOWED_HOSTS=*
|
||||||
|
CORS_ORIGIN_ALLOW_ALL=true
|
||||||
|
DB_HOST=postgres
|
||||||
|
DB_NAME=netbox
|
||||||
|
DB_PASSWORD=J5brHrAXFLQSif0K
|
||||||
|
DB_USER=netbox
|
||||||
|
DEBUG=true
|
||||||
|
ENFORCE_GLOBAL_UNIQUE=true
|
||||||
|
LOGIN_REQUIRED=false
|
||||||
|
GRAPHQL_ENABLED=true
|
||||||
|
MAX_PAGE_SIZE=1000
|
||||||
|
MEDIA_ROOT=/opt/netbox/netbox/media
|
||||||
|
REDIS_DATABASE=0
|
||||||
|
REDIS_HOST=redis
|
||||||
|
REDIS_INSECURE_SKIP_TLS_VERIFY=false
|
||||||
|
REDIS_PASSWORD=H733Kdjndks81
|
||||||
|
SECRET_KEY=r8OwDznj!!dciP9ghmRfdu1Ysxm0AiPeDCQhKE+N_rClfWNj
|
||||||
|
SUPERUSER_API_TOKEN=0123456789abcdef0123456789abcdef01234567
|
||||||
|
SUPERUSER_EMAIL=admin@example.com
|
||||||
|
SUPERUSER_NAME=admin
|
||||||
|
SUPERUSER_PASSWORD=admin
|
||||||
|
STARTUP_SCRIPTS=false
|
||||||
|
WEBHOOKS_ENABLED=true
|
||||||
3
env/postgres.env
vendored
Normal file
3
env/postgres.env
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
POSTGRES_DB=netbox
|
||||||
|
POSTGRES_PASSWORD=J5brHrAXFLQSif0K
|
||||||
|
POSTGRES_USER=netbox
|
||||||
1
env/redis.env
vendored
Normal file
1
env/redis.env
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
REDIS_PASSWORD=H733Kdjndks81
|
||||||
@ -15,28 +15,36 @@ class Migration(migrations.Migration):
|
|||||||
model_name="accesslist",
|
model_name="accesslist",
|
||||||
name="custom_field_data",
|
name="custom_field_data",
|
||||||
field=models.JSONField(
|
field=models.JSONField(
|
||||||
blank=True, default=dict, encoder=utilities.json.CustomFieldJSONEncoder
|
blank=True,
|
||||||
|
default=dict,
|
||||||
|
encoder=utilities.json.CustomFieldJSONEncoder,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name="aclextendedrule",
|
model_name="aclextendedrule",
|
||||||
name="custom_field_data",
|
name="custom_field_data",
|
||||||
field=models.JSONField(
|
field=models.JSONField(
|
||||||
blank=True, default=dict, encoder=utilities.json.CustomFieldJSONEncoder
|
blank=True,
|
||||||
|
default=dict,
|
||||||
|
encoder=utilities.json.CustomFieldJSONEncoder,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name="aclinterfaceassignment",
|
model_name="aclinterfaceassignment",
|
||||||
name="custom_field_data",
|
name="custom_field_data",
|
||||||
field=models.JSONField(
|
field=models.JSONField(
|
||||||
blank=True, default=dict, encoder=utilities.json.CustomFieldJSONEncoder
|
blank=True,
|
||||||
|
default=dict,
|
||||||
|
encoder=utilities.json.CustomFieldJSONEncoder,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name="aclstandardrule",
|
model_name="aclstandardrule",
|
||||||
name="custom_field_data",
|
name="custom_field_data",
|
||||||
field=models.JSONField(
|
field=models.JSONField(
|
||||||
blank=True, default=dict, encoder=utilities.json.CustomFieldJSONEncoder
|
blank=True,
|
||||||
|
default=dict,
|
||||||
|
encoder=utilities.json.CustomFieldJSONEncoder,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|||||||
0
netbox_acls/tests/__init__.py
Normal file
0
netbox_acls/tests/__init__.py
Normal file
100
netbox_acls/tests/test_api.py
Normal file
100
netbox_acls/tests/test_api.py
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
from dcim.models import Device, DeviceRole, DeviceType, Interface, Manufacturer, Site
|
||||||
|
from django.contrib.contenttypes.models import ContentType
|
||||||
|
from django.urls import reverse
|
||||||
|
from netbox_acls.choices import *
|
||||||
|
from netbox_acls.models import *
|
||||||
|
from rest_framework import status
|
||||||
|
from utilities.testing import APITestCase, APIViewTestCases
|
||||||
|
|
||||||
|
|
||||||
|
class AppTest(APITestCase):
|
||||||
|
def test_root(self):
|
||||||
|
url = reverse("plugins-api:netbox_acls-api:api-root")
|
||||||
|
response = self.client.get(f"{url}?format=api", **self.header)
|
||||||
|
|
||||||
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
|
|
||||||
|
|
||||||
|
class ACLTestCase(
|
||||||
|
APIViewTestCases.GetObjectViewTestCase,
|
||||||
|
APIViewTestCases.ListObjectsViewTestCase,
|
||||||
|
APIViewTestCases.CreateObjectViewTestCase,
|
||||||
|
APIViewTestCases.UpdateObjectViewTestCase,
|
||||||
|
APIViewTestCases.DeleteObjectViewTestCase,
|
||||||
|
):
|
||||||
|
"""Test the AccessList Test"""
|
||||||
|
|
||||||
|
model = AccessList
|
||||||
|
view_namespace = "plugins-api:netbox_acls"
|
||||||
|
brief_fields = ["display", "id", "name", "url"]
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setUpTestData(cls):
|
||||||
|
site = Site.objects.create(name="Site 1", slug="site-1")
|
||||||
|
manufacturer = Manufacturer.objects.create(
|
||||||
|
name="Manufacturer 1",
|
||||||
|
slug="manufacturer-1",
|
||||||
|
)
|
||||||
|
devicetype = DeviceType.objects.create(
|
||||||
|
manufacturer=manufacturer,
|
||||||
|
model="Device Type 1",
|
||||||
|
)
|
||||||
|
devicerole = DeviceRole.objects.create(
|
||||||
|
name="Device Role 1",
|
||||||
|
slug="device-role-1",
|
||||||
|
)
|
||||||
|
device = Device.objects.create(
|
||||||
|
name="Device 1",
|
||||||
|
site=site,
|
||||||
|
device_type=devicetype,
|
||||||
|
device_role=devicerole,
|
||||||
|
)
|
||||||
|
|
||||||
|
access_lists = (
|
||||||
|
AccessList(
|
||||||
|
name="testacl1",
|
||||||
|
assigned_object_type=ContentType.objects.get_for_model(Device),
|
||||||
|
assigned_object_id=device.id,
|
||||||
|
type=ACLTypeChoices.TYPE_STANDARD,
|
||||||
|
default_action=ACLActionChoices.ACTION_DENY,
|
||||||
|
),
|
||||||
|
AccessList(
|
||||||
|
name="testacl2",
|
||||||
|
assigned_object_type=ContentType.objects.get_for_model(Device),
|
||||||
|
assigned_object_id=device.id,
|
||||||
|
type=ACLTypeChoices.TYPE_STANDARD,
|
||||||
|
default_action=ACLActionChoices.ACTION_DENY,
|
||||||
|
),
|
||||||
|
AccessList(
|
||||||
|
name="testacl3",
|
||||||
|
assigned_object_type=ContentType.objects.get_for_model(Device),
|
||||||
|
assigned_object_id=device.id,
|
||||||
|
type=ACLTypeChoices.TYPE_STANDARD,
|
||||||
|
default_action=ACLActionChoices.ACTION_DENY,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
AccessList.objects.bulk_create(access_lists)
|
||||||
|
|
||||||
|
cls.create_data = [
|
||||||
|
{
|
||||||
|
"name": "testacl4",
|
||||||
|
"assigned_object_type": "dcim.device",
|
||||||
|
"assigned_object_id": device.id,
|
||||||
|
"type": ACLTypeChoices.TYPE_STANDARD,
|
||||||
|
"default_action": ACLActionChoices.ACTION_DENY,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "testacl5",
|
||||||
|
"assigned_object_type": "dcim.device",
|
||||||
|
"assigned_object_id": device.id,
|
||||||
|
"type": ACLTypeChoices.TYPE_EXTENDED,
|
||||||
|
"default_action": ACLActionChoices.ACTION_DENY,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "testacl6",
|
||||||
|
"assigned_object_type": "dcim.device",
|
||||||
|
"assigned_object_id": device.id,
|
||||||
|
"type": ACLTypeChoices.TYPE_STANDARD,
|
||||||
|
"default_action": ACLActionChoices.ACTION_DENY,
|
||||||
|
},
|
||||||
|
]
|
||||||
@ -5,7 +5,7 @@ Map Views to URLs.
|
|||||||
from django.urls import include, path
|
from django.urls import include, path
|
||||||
from utilities.urls import get_model_urls
|
from utilities.urls import get_model_urls
|
||||||
|
|
||||||
from . import models, views
|
from . import views
|
||||||
|
|
||||||
urlpatterns = (
|
urlpatterns = (
|
||||||
# Access Lists
|
# Access Lists
|
||||||
|
|||||||
5
setup.py
5
setup.py
@ -3,12 +3,13 @@ import os.path
|
|||||||
|
|
||||||
from setuptools import find_packages, setup
|
from setuptools import find_packages, setup
|
||||||
|
|
||||||
with open("README.md", encoding="utf-8") as fh:
|
here = os.path.abspath(os.path.dirname(__file__))
|
||||||
|
|
||||||
|
with open(os.path.join(here, "README.md"), encoding="utf-8") as fh:
|
||||||
long_description = fh.read()
|
long_description = fh.read()
|
||||||
|
|
||||||
|
|
||||||
def read(rel_path):
|
def read(rel_path):
|
||||||
here = os.path.abspath(os.path.dirname(__file__))
|
|
||||||
with codecs.open(os.path.join(here, rel_path), "r") as fp:
|
with codecs.open(os.path.join(here, rel_path), "r") as fp:
|
||||||
return fp.read()
|
return fp.read()
|
||||||
|
|
||||||
|
|||||||
38
test.sh
Executable file
38
test.sh
Executable file
@ -0,0 +1,38 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Runs the NetBox plugin unit tests
|
||||||
|
# Usage:
|
||||||
|
# ./test.sh latest
|
||||||
|
# ./test.sh v2.9.7
|
||||||
|
# ./test.sh develop-2.10
|
||||||
|
|
||||||
|
# exit when a command exits with an exit code != 0
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# NETBOX_VARIANT is used by `Dockerfile` to determine the tag
|
||||||
|
NETBOX_VARIANT="${1-latest}"
|
||||||
|
|
||||||
|
# The docker compose command to use
|
||||||
|
doco="docker compose --file docker-compose.yml"
|
||||||
|
|
||||||
|
test_netbox_unit_tests() {
|
||||||
|
echo "⏱ Running NetBox Unit Tests"
|
||||||
|
$doco run --rm netbox python manage.py makemigrations netbox_acls --check
|
||||||
|
$doco run --rm netbox python manage.py test netbox_acls
|
||||||
|
}
|
||||||
|
|
||||||
|
test_cleanup() {
|
||||||
|
echo "💣 Cleaning Up"
|
||||||
|
$doco down -v
|
||||||
|
$doco rm -fsv
|
||||||
|
docker image rm docker.io/library/netbox-acls-netbox || echo ''
|
||||||
|
}
|
||||||
|
|
||||||
|
export NETBOX_VARIANT=${NETBOX_VARIANT}
|
||||||
|
|
||||||
|
echo "🐳🐳🐳 Start testing '${NETBOX_VARIANT}'"
|
||||||
|
|
||||||
|
# Make sure the cleanup script is executed
|
||||||
|
trap test_cleanup EXIT ERR
|
||||||
|
test_netbox_unit_tests
|
||||||
|
|
||||||
|
echo "🐳🐳🐳 Done testing '${NETBOX_VARIANT}'"
|
||||||
Loading…
x
Reference in New Issue
Block a user