From 88edcde8d6c190cc7278798f99a386d3efc9f022 Mon Sep 17 00:00:00 2001
From: wkoot <3715211+wkoot@users.noreply.github.com>
Date: Wed, 19 Apr 2023 10:14:32 +0200
Subject: [PATCH] Unify api serializers (#16)
---
.env | 2 +-
.github/workflows/docker-image.yml | 23 ++++-
.gitignore | 2 +
MANIFEST.in | 5 +-
ci/Dockerfile-CI | 4 +
ci/configuration/extra.py | 7 ++
ci/configuration/ldap/extra.py | 28 ------
ci/configuration/ldap/ldap_config.py | 90 -------------------
...ose.override.yml => docker-compose.ci.yml} | 4 +
ci/docker-compose.yml | 2 -
ci/reports/.gitkeep | 0
ci/requirements_ci.txt | 2 +
netbox_slm/__init__.py | 9 +-
netbox_slm/api/serializers.py | 10 +--
netbox_slm/api/urls.py | 2 +-
netbox_slm/api/views.py | 6 +-
netbox_slm/filtersets.py | 8 +-
netbox_slm/forms.py | 11 +--
netbox_slm/models.py | 4 +-
netbox_slm/navigation.py | 1 -
netbox_slm/tables.py | 4 +-
netbox_slm/tests/test_models.py | 36 ++++++++
netbox_slm/tests/test_smoke.py | 16 ----
netbox_slm/urls.py | 2 +-
netbox_slm/views.py | 8 +-
setup.cfg | 14 ++-
setup.py | 4 +-
sonar-project.properties | 13 +++
start-netbox.sh | 2 +-
29 files changed, 127 insertions(+), 192 deletions(-)
delete mode 100644 ci/configuration/ldap/extra.py
delete mode 100644 ci/configuration/ldap/ldap_config.py
rename ci/{docker-compose.override.yml => docker-compose.ci.yml} (76%)
create mode 100644 ci/reports/.gitkeep
create mode 100644 ci/requirements_ci.txt
create mode 100644 netbox_slm/tests/test_models.py
delete mode 100644 netbox_slm/tests/test_smoke.py
create mode 100644 sonar-project.properties
diff --git a/.env b/.env
index 6f67894..56a3cc3 100644
--- a/.env
+++ b/.env
@@ -1,3 +1,3 @@
COMPOSE_PATH_SEPARATOR=:
-COMPOSE_FILE=ci/docker-compose.yml:ci/docker-compose.override.yml
+COMPOSE_FILE=ci/docker-compose.yml:ci/docker-compose.ci.yml
COMPOSE_PROJECT_NAME=netbox-docker
diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml
index c215f3d..74bb16d 100644
--- a/.github/workflows/docker-image.yml
+++ b/.github/workflows/docker-image.yml
@@ -1,6 +1,11 @@
name: Docker Image CI
-on: [push, pull_request]
+on:
+ push:
+ branches:
+ - master
+ pull_request:
+ types: [opened, synchronize, reopened]
jobs:
build:
@@ -15,5 +20,17 @@ jobs:
# clearcache is provided by Django extras, which is not loaded if netbox-slm cannot be loaded
run: docker compose run netbox sh -c "/opt/netbox/venv/bin/python manage.py clearcache"
- - name: Run Django tests for netbox_slm
- run: docker compose run netbox sh -c "/opt/netbox/venv/bin/python manage.py test netbox_slm"
+ - name: Run Django tests with coverage for netbox_slm
+ run: |
+ chmod go+w ci/reports
+ docker compose run netbox sh -c " \
+ /opt/netbox/venv/bin/coverage run --source='netbox_slm' manage.py test netbox_slm && \
+ /opt/netbox/venv/bin/coverage report --fail-under=0 && \
+ /opt/netbox/venv/bin/coverage xml -o /ci/reports/coverage.xml"
+
+ - name: Sonarcloud scan
+ if: env.SONAR_TOKEN != null
+ uses: sonarsource/sonarcloud-github-action@master
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
diff --git a/.gitignore b/.gitignore
index bdab604..a5534c1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,4 +6,6 @@
**/.vscode
**/dist
**/netbox_slm.egg-info
+ci/docker-compose.override.yml
+ci/reports
out/production
diff --git a/MANIFEST.in b/MANIFEST.in
index 813087f..fd64489 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -1,3 +1,4 @@
include ../LICENSE
-include ../README.rst
-recursive-include netbox_slm/templates *
\ No newline at end of file
+include ../README.md
+include ../SECURITY.md
+recursive-include netbox_slm/templates *
diff --git a/ci/Dockerfile-CI b/ci/Dockerfile-CI
index 6ca4687..822fc40 100644
--- a/ci/Dockerfile-CI
+++ b/ci/Dockerfile-CI
@@ -1,3 +1,7 @@
FROM netboxcommunity/netbox:v3.4.7
+RUN mkdir /ci && chmod go+w /ci
+COPY ../ci/requirements_ci.txt /ci/
+RUN pip install -r /ci/requirements_ci.txt
+
COPY ../netbox_slm /opt/netbox/netbox/netbox_slm
diff --git a/ci/configuration/extra.py b/ci/configuration/extra.py
index 740aeb3..c721991 100644
--- a/ci/configuration/extra.py
+++ b/ci/configuration/extra.py
@@ -2,3 +2,10 @@ PLUGINS = ['netbox_slm']
DEBUG = True
SECRET_KEY = 'dummy'
DEVELOPER = True
+PLUGINS_CONFIG = {
+ 'netbox_slm': dict(
+ TEST_RUNNER='xmlrunner.extra.djangotestrunner.XMLTestRunner',
+ TEST_OUTPUT_DIR='/ci/reports/',
+ TEST_OUTPUT_FILE_NAME='junit.xml',
+ )
+}
diff --git a/ci/configuration/ldap/extra.py b/ci/configuration/ldap/extra.py
deleted file mode 100644
index 4505197..0000000
--- a/ci/configuration/ldap/extra.py
+++ /dev/null
@@ -1,28 +0,0 @@
-####
-## This file contains extra configuration options that can't be configured
-## directly through environment variables.
-## All vairables set here overwrite any existing found in ldap_config.py
-####
-
-# # This Python script inherits all the imports from ldap_config.py
-# from django_auth_ldap.config import LDAPGroupQuery # Imported since not in ldap_config.py
-
-# # Sets a base requirement of membetship to netbox-user-ro, netbox-user-rw, or netbox-user-admin.
-# AUTH_LDAP_REQUIRE_GROUP = (
-# LDAPGroupQuery("cn=netbox-user-ro,ou=groups,dc=example,dc=com")
-# | LDAPGroupQuery("cn=netbox-user-rw,ou=groups,dc=example,dc=com")
-# | LDAPGroupQuery("cn=netbox-user-admin,ou=groups,dc=example,dc=com")
-# )
-
-# # Sets LDAP Flag groups variables with example.
-# AUTH_LDAP_USER_FLAGS_BY_GROUP = {
-# "is_staff": (
-# LDAPGroupQuery("cn=netbox-user-ro,ou=groups,dc=example,dc=com")
-# | LDAPGroupQuery("cn=netbox-user-rw,ou=groups,dc=example,dc=com")
-# | LDAPGroupQuery("cn=netbox-user-admin,ou=groups,dc=example,dc=com")
-# ),
-# "is_superuser": "cn=netbox-user-admin,ou=groups,dc=example,dc=com",
-# }
-
-# # Sets LDAP Mirror groups variables with example groups
-# AUTH_LDAP_MIRROR_GROUPS = ["netbox-user-ro", "netbox-user-rw", "netbox-user-admin"]
diff --git a/ci/configuration/ldap/ldap_config.py b/ci/configuration/ldap/ldap_config.py
deleted file mode 100644
index 3071b45..0000000
--- a/ci/configuration/ldap/ldap_config.py
+++ /dev/null
@@ -1,90 +0,0 @@
-from importlib import import_module
-from os import environ
-
-import ldap
-from django_auth_ldap.config import LDAPSearch
-
-
-# Read secret from file
-def _read_secret(secret_name, default=None):
- try:
- f = open('/run/secrets/' + secret_name, 'r', encoding='utf-8')
- except EnvironmentError:
- return default
- else:
- with f:
- return f.readline().strip()
-
-# Import and return the group type based on string name
-def _import_group_type(group_type_name):
- mod = import_module('django_auth_ldap.config')
- try:
- return getattr(mod, group_type_name)()
- except:
- return None
-
-# Server URI
-AUTH_LDAP_SERVER_URI = environ.get('AUTH_LDAP_SERVER_URI', '')
-
-# The following may be needed if you are binding to Active Directory.
-AUTH_LDAP_CONNECTION_OPTIONS = {
- ldap.OPT_REFERRALS: 0
-}
-
-# Set the DN and password for the NetBox service account.
-AUTH_LDAP_BIND_DN = environ.get('AUTH_LDAP_BIND_DN', '')
-AUTH_LDAP_BIND_PASSWORD = _read_secret('auth_ldap_bind_password', environ.get('AUTH_LDAP_BIND_PASSWORD', ''))
-
-# Set a string template that describes any user’s distinguished name based on the username.
-AUTH_LDAP_USER_DN_TEMPLATE = environ.get('AUTH_LDAP_USER_DN_TEMPLATE', None)
-
-# Enable STARTTLS for ldap authentication.
-AUTH_LDAP_START_TLS = environ.get('AUTH_LDAP_START_TLS', 'False').lower() == 'true'
-
-# Include this setting if you want to ignore certificate errors. This might be needed to accept a self-signed cert.
-# Note that this is a NetBox-specific setting which sets:
-# ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER)
-LDAP_IGNORE_CERT_ERRORS = environ.get('LDAP_IGNORE_CERT_ERRORS', 'False').lower() == 'true'
-
-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 = LDAPSearch(
- AUTH_LDAP_USER_SEARCH_BASEDN,
- ldap.SCOPE_SUBTREE,
- "(" + AUTH_LDAP_USER_SEARCH_ATTR + "=%(user)s)"
-)
-
-# This search ought to return all groups to which the user belongs. django_auth_ldap uses this to determine group
-# heirarchy.
-AUTH_LDAP_GROUP_SEARCH_BASEDN = environ.get('AUTH_LDAP_GROUP_SEARCH_BASEDN', '')
-AUTH_LDAP_GROUP_SEARCH_CLASS = environ.get('AUTH_LDAP_GROUP_SEARCH_CLASS', 'group')
-AUTH_LDAP_GROUP_SEARCH = LDAPSearch(AUTH_LDAP_GROUP_SEARCH_BASEDN, ldap.SCOPE_SUBTREE,
- "(objectClass=" + AUTH_LDAP_GROUP_SEARCH_CLASS + ")")
-AUTH_LDAP_GROUP_TYPE = _import_group_type(environ.get('AUTH_LDAP_GROUP_TYPE', 'GroupOfNamesType'))
-
-# Define a group required to login.
-AUTH_LDAP_REQUIRE_GROUP = environ.get('AUTH_LDAP_REQUIRE_GROUP_DN')
-
-# Define special user types using groups. Exercise great caution when assigning superuser status.
-AUTH_LDAP_USER_FLAGS_BY_GROUP = {}
-
-if AUTH_LDAP_REQUIRE_GROUP is not None:
- AUTH_LDAP_USER_FLAGS_BY_GROUP = {
- "is_active": environ.get('AUTH_LDAP_REQUIRE_GROUP_DN', ''),
- "is_staff": environ.get('AUTH_LDAP_IS_ADMIN_DN', ''),
- "is_superuser": environ.get('AUTH_LDAP_IS_SUPERUSER_DN', '')
- }
-
-# For more granular permissions, we can map LDAP groups to Django groups.
-AUTH_LDAP_FIND_GROUP_PERMS = environ.get('AUTH_LDAP_FIND_GROUP_PERMS', 'True').lower() == 'true'
-AUTH_LDAP_MIRROR_GROUPS = environ.get('AUTH_LDAP_MIRROR_GROUPS', '').lower() == 'true'
-
-# Cache groups for one hour to reduce LDAP traffic
-AUTH_LDAP_CACHE_TIMEOUT = int(environ.get('AUTH_LDAP_CACHE_TIMEOUT', 3600))
-
-# Populate the Django user from the LDAP directory.
-AUTH_LDAP_USER_ATTR_MAP = {
- "first_name": environ.get('AUTH_LDAP_ATTR_FIRSTNAME', 'givenName'),
- "last_name": environ.get('AUTH_LDAP_ATTR_LASTNAME', 'sn'),
- "email": environ.get('AUTH_LDAP_ATTR_MAIL', 'mail')
-}
diff --git a/ci/docker-compose.override.yml b/ci/docker-compose.ci.yml
similarity index 76%
rename from ci/docker-compose.override.yml
rename to ci/docker-compose.ci.yml
index 5838746..0939273 100644
--- a/ci/docker-compose.override.yml
+++ b/ci/docker-compose.ci.yml
@@ -7,6 +7,10 @@ services:
context: ..
dockerfile: ci/Dockerfile-CI
image: netbox:slm
+ environment:
+ - COVERAGE_FILE=/ci/.coverage
+ volumes:
+ - ./reports:/ci/reports
netbox-worker:
image: netbox:slm
netbox-housekeeping:
diff --git a/ci/docker-compose.yml b/ci/docker-compose.yml
index e862fae..1b5997d 100644
--- a/ci/docker-compose.yml
+++ b/ci/docker-compose.yml
@@ -11,8 +11,6 @@ services:
user: 'unit:root'
volumes:
- ./configuration:/etc/netbox/config:z,ro
-# - ./reports:/etc/netbox/reports:z,ro
-# - ./scripts:/etc/netbox/scripts:z,ro
- netbox-media-files:/opt/netbox/netbox/media:z
netbox-worker:
<<: *netbox
diff --git a/ci/reports/.gitkeep b/ci/reports/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/ci/requirements_ci.txt b/ci/requirements_ci.txt
new file mode 100644
index 0000000..eca0d7a
--- /dev/null
+++ b/ci/requirements_ci.txt
@@ -0,0 +1,2 @@
+coverage==7.2.2
+unittest-xml-reporting==3.2.0
diff --git a/netbox_slm/__init__.py b/netbox_slm/__init__.py
index 67a513c..82f0b04 100644
--- a/netbox_slm/__init__.py
+++ b/netbox_slm/__init__.py
@@ -4,14 +4,15 @@ from extras.plugins import PluginConfig
class SLMConfig(PluginConfig):
name = 'netbox_slm'
verbose_name = 'Software Lifecycle Management'
- description = 'Software Lifecycle Management'
- version = '1.2'
- author = 'Hedde van der Heide'
- author_email = 'hedde.vanderheide@ictu.nl'
+ description = 'Software Lifecycle Management Netbox Plugin.'
+ version = '1.3'
+ author = 'ICTU'
+ author_email = 'open-source-projects@ictu.nl'
base_url = 'slm'
required_settings = []
default_settings = {
'version_info': False
}
+
config = SLMConfig
diff --git a/netbox_slm/api/serializers.py b/netbox_slm/api/serializers.py
index 520663a..c0fe19e 100644
--- a/netbox_slm/api/serializers.py
+++ b/netbox_slm/api/serializers.py
@@ -1,9 +1,7 @@
from rest_framework import serializers
from netbox.api.serializers import NetBoxModelSerializer
-from netbox_slm.models import (
- SoftwareProduct, SoftwareProductVersion, SoftwareProductInstallation,
-)
+from netbox_slm.models import SoftwareProduct, SoftwareProductVersion, SoftwareProductInstallation
class SoftwareProductSerializer(NetBoxModelSerializer):
@@ -19,7 +17,7 @@ class SoftwareProductSerializer(NetBoxModelSerializer):
]
def get_display(self, obj):
- return f"{obj.manufacturer.name} - {obj.name}"
+ return f"{obj.manufacturer} - {obj}"
class SoftwareProductVersionSerializer(NetBoxModelSerializer):
@@ -35,7 +33,7 @@ class SoftwareProductVersionSerializer(NetBoxModelSerializer):
]
def get_display(self, obj):
- return obj.name
+ return f"{obj}"
class SoftwareProductInstallationSerializer(NetBoxModelSerializer):
@@ -52,4 +50,4 @@ class SoftwareProductInstallationSerializer(NetBoxModelSerializer):
]
def get_display(self, obj):
- return obj
+ return f"{obj}"
diff --git a/netbox_slm/api/urls.py b/netbox_slm/api/urls.py
index 421eb61..aaa1d43 100644
--- a/netbox_slm/api/urls.py
+++ b/netbox_slm/api/urls.py
@@ -12,4 +12,4 @@ router.APIRootView = NetboxSLMRootView
router.register("softwareproducts", SoftwareProductViewSet)
router.register("softwareproductversions", SoftwareProductVersionViewSet)
router.register("softwareproductinstallations", SoftwareProductInstallationViewSet)
-urlpatterns = router.urls
\ No newline at end of file
+urlpatterns = router.urls
diff --git a/netbox_slm/api/views.py b/netbox_slm/api/views.py
index 021c22a..88b13b6 100644
--- a/netbox_slm/api/views.py
+++ b/netbox_slm/api/views.py
@@ -1,15 +1,13 @@
-from netbox.api.viewsets import NetBoxModelViewSet
from rest_framework.routers import APIRootView
+from netbox.api.viewsets import NetBoxModelViewSet
from netbox_slm.api.serializers import (
SoftwareProductSerializer, SoftwareProductVersionSerializer, SoftwareProductInstallationSerializer,
)
from netbox_slm.filtersets import (
SoftwareProductFilterSet, SoftwareProductVersionFilterSet, SoftwareProductInstallationFilterSet,
)
-from netbox_slm.models import (
- SoftwareProduct, SoftwareProductVersion, SoftwareProductInstallation,
-)
+from netbox_slm.models import SoftwareProduct, SoftwareProductVersion, SoftwareProductInstallation
class NetboxSLMRootView(APIRootView):
diff --git a/netbox_slm/filtersets.py b/netbox_slm/filtersets.py
index 93bace7..99778a8 100644
--- a/netbox_slm/filtersets.py
+++ b/netbox_slm/filtersets.py
@@ -1,11 +1,12 @@
from django.db.models import Q
from netbox.filtersets import NetBoxModelFilterSet
-from netbox_slm.models import *
+from netbox_slm.models import SoftwareProduct, SoftwareProductVersion, SoftwareProductInstallation
class SoftwareProductFilterSet(NetBoxModelFilterSet):
"""Filter capabilities for SoftwareProduct instances."""
+
class Meta:
model = SoftwareProduct
fields = tuple()
@@ -14,13 +15,13 @@ class SoftwareProductFilterSet(NetBoxModelFilterSet):
"""Perform the filtered search."""
if not value.strip():
return queryset
- qs_filter = Q(name__icontains=value) | \
- Q(manufacturer__name__icontains=value)
+ qs_filter = Q(name__icontains=value) | Q(manufacturer__name__icontains=value)
return queryset.filter(qs_filter)
class SoftwareProductVersionFilterSet(NetBoxModelFilterSet):
"""Filter capabilities for SoftwareProductVersion instances."""
+
class Meta:
model = SoftwareProductVersion
fields = (
@@ -39,6 +40,7 @@ class SoftwareProductVersionFilterSet(NetBoxModelFilterSet):
class SoftwareProductInstallationFilterSet(NetBoxModelFilterSet):
"""Filter capabilities for SoftwareProductInstallation instances."""
+
class Meta:
model = SoftwareProductInstallation
fields = tuple()
diff --git a/netbox_slm/forms.py b/netbox_slm/forms.py
index e7cea70..e03f4c3 100644
--- a/netbox_slm/forms.py
+++ b/netbox_slm/forms.py
@@ -3,16 +3,9 @@ from django.urls import reverse_lazy
from django.utils.translation import gettext as _
from dcim.models import Manufacturer, Device
-from netbox.forms import (
- NetBoxModelForm,
- NetBoxModelCSVForm,
- NetBoxModelBulkEditForm,
- NetBoxModelFilterSetForm,
-)
+from netbox.forms import NetBoxModelForm, NetBoxModelCSVForm, NetBoxModelBulkEditForm, NetBoxModelFilterSetForm
from netbox_slm.models import SoftwareProduct, SoftwareProductVersion, SoftwareProductInstallation
-from utilities.forms import (
- DynamicModelChoiceField, APISelect, TagFilterField, ChoiceField
-)
+from utilities.forms import DynamicModelChoiceField, APISelect, TagFilterField
from virtualization.models import VirtualMachine
diff --git a/netbox_slm/models.py b/netbox_slm/models.py
index bf6545f..d2beac9 100644
--- a/netbox_slm/models.py
+++ b/netbox_slm/models.py
@@ -9,7 +9,7 @@ from utilities.querysets import RestrictedQuerySet
class SoftwareProduct(NetBoxModel):
name = models.CharField(max_length=128)
description = models.CharField(max_length=255, null=True, blank=True)
-
+
manufacturer = models.ForeignKey(
to='dcim.Manufacturer',
on_delete=models.PROTECT,
@@ -89,4 +89,4 @@ class SoftwareProductInstallation(NetBoxModel):
return self.device or self.virtualmachine
def render_type(self):
- return f"{'device' if self.device else 'virtualmachine'}"
+ return 'device' if self.device else 'virtualmachine'
diff --git a/netbox_slm/navigation.py b/netbox_slm/navigation.py
index 71c25de..d34579b 100644
--- a/netbox_slm/navigation.py
+++ b/netbox_slm/navigation.py
@@ -1,7 +1,6 @@
from extras.plugins import PluginMenuButton, PluginMenuItem
from utilities.choices import ButtonColorChoices
-
menu_items = (
PluginMenuItem(
link='plugins:netbox_slm:softwareproduct_list',
diff --git a/netbox_slm/tables.py b/netbox_slm/tables.py
index 3accc26..bec0967 100644
--- a/netbox_slm/tables.py
+++ b/netbox_slm/tables.py
@@ -1,9 +1,9 @@
import django_tables2 as tables
-
from django.db.models import Count
from django_tables2.utils import Accessor
+
+from netbox.tables import NetBoxTable, ToggleColumn, columns
from netbox_slm.models import SoftwareProduct, SoftwareProductVersion, SoftwareProductInstallation
-from netbox.tables import NetBoxTable, ChoiceFieldColumn, ToggleColumn, columns
class SoftwareProductTable(NetBoxTable):
diff --git a/netbox_slm/tests/test_models.py b/netbox_slm/tests/test_models.py
new file mode 100644
index 0000000..25062a1
--- /dev/null
+++ b/netbox_slm/tests/test_models.py
@@ -0,0 +1,36 @@
+from django.test import TestCase
+
+from netbox_slm.models import SoftwareProduct, SoftwareProductVersion, SoftwareProductInstallation
+
+
+class ModelTestCase(TestCase):
+ def setUp(self):
+ self.p_name = "test product"
+ self.v_name = "test version"
+
+ self.software_product = SoftwareProduct.objects.create(name=self.p_name)
+ self.software_product_version = SoftwareProductVersion.objects.create(
+ name=self.v_name, software_product=self.software_product
+ )
+ self.software_product_installation = SoftwareProductInstallation.objects.create(
+ software_product=self.software_product, version=self.software_product_version
+ )
+
+ def test_model_name(self):
+ self.assertEqual(self.p_name, str(self.software_product))
+ self.assertEqual(self.v_name, str(self.software_product_version))
+ self.assertTrue(str(self.software_product_installation).isnumeric()) # should be PK
+
+ def test_absolute_url(self):
+ self.assertEqual("/plugins/slm/software-products/1/", self.software_product.get_absolute_url())
+ self.assertEqual("/plugins/slm/versions/1/", self.software_product_version.get_absolute_url())
+ self.assertEqual("/plugins/slm/installations/1/", self.software_product_installation.get_absolute_url())
+
+ def test_get_installation_count(self):
+ installation_ss = '1'
+ self.assertEqual(installation_ss.format(self.p_name), self.software_product.get_installation_count())
+ self.assertEqual(installation_ss.format(self.v_name), self.software_product_version.get_installation_count())
+
+ def test_product_installation_methods(self):
+ self.assertEqual("virtualmachine", self.software_product_installation.render_type())
+ self.assertIsNone(self.software_product_installation.get_platform())
diff --git a/netbox_slm/tests/test_smoke.py b/netbox_slm/tests/test_smoke.py
deleted file mode 100644
index 0a08181..0000000
--- a/netbox_slm/tests/test_smoke.py
+++ /dev/null
@@ -1,16 +0,0 @@
-from django.test import TestCase
-
-from netbox_slm.models import SoftwareProduct, SoftwareProductVersion, SoftwareProductInstallation
-
-
-class ModelTestCase(TestCase):
- def test_smoke(self):
- software_product = SoftwareProduct.objects.create(name="test product")
- software_product_version = SoftwareProductVersion.objects.create(
- name="test version", software_product=software_product
- )
- software_product_installation = SoftwareProductInstallation.objects.create(
- software_product=software_product, version=software_product_version
- )
-
- self.assertEqual('virtualmachine', software_product_installation.render_type())
diff --git a/netbox_slm/urls.py b/netbox_slm/urls.py
index 7e3e2d9..d951389 100644
--- a/netbox_slm/urls.py
+++ b/netbox_slm/urls.py
@@ -1,6 +1,6 @@
from django.urls import path
-from netbox.views.generic import ObjectChangeLogView
+from netbox.views.generic import ObjectChangeLogView
from netbox_slm import views
from netbox_slm.models import SoftwareProduct, SoftwareProductVersion, SoftwareProductInstallation
diff --git a/netbox_slm/views.py b/netbox_slm/views.py
index 898e540..e549a57 100644
--- a/netbox_slm/views.py
+++ b/netbox_slm/views.py
@@ -1,10 +1,6 @@
from netbox.views import generic
-from netbox_slm import filtersets
-from netbox_slm import forms
-from netbox_slm import tables
-from netbox_slm.models import (
- SoftwareProduct, SoftwareProductVersion, SoftwareProductInstallation
-)
+from netbox_slm import filtersets, forms, tables
+from netbox_slm.models import SoftwareProduct, SoftwareProductVersion, SoftwareProductInstallation
class SoftwareProductListView(generic.ObjectListView):
diff --git a/setup.cfg b/setup.cfg
index 36e87d0..33ccb12 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,11 +1,9 @@
[metadata]
name = netbox-slm
-version = 1.2
+version = 1.3
description = Software Lifecycle Management Netbox Plugin.
-# long_description = file: README.rst
-# long_description_content_type='text/x-rst'
-author = Hedde van der Heide
-author_email = hedde.vanderheide@ictu.nl
+author = ICTU
+author_email = open-source-projects@ictu.nl
license = Apache 2.0
classifiers =
Environment :: Web Environment
@@ -16,13 +14,13 @@ classifiers =
Programming Language :: Python
Programming Language :: Python :: 3
Programming Language :: Python :: 3 :: Only
- Programming Language :: Python :: 3.7
- Programming Language :: Python :: 3.8
Programming Language :: Python :: 3.9
+ Programming Language :: Python :: 3.10
+ Programming Language :: Python :: 3.11
Topic :: Internet :: WWW/HTTP
Topic :: Internet :: WWW/HTTP :: Dynamic Content
[options]
include_package_data = true
packages = find:
-python_requires = >=3.7
+python_requires = >=3.9
diff --git a/setup.py b/setup.py
index 02997c3..6068493 100644
--- a/setup.py
+++ b/setup.py
@@ -1,3 +1,3 @@
-from setuptools import setup, Extension
+from setuptools import setup
-setup()
\ No newline at end of file
+setup()
diff --git a/sonar-project.properties b/sonar-project.properties
new file mode 100644
index 0000000..fe9e86d
--- /dev/null
+++ b/sonar-project.properties
@@ -0,0 +1,13 @@
+# Project metadata
+sonar.organization=ictu
+sonar.projectKey=ICTU_netbox_slm
+sonar.projectName=netbox-slm
+sonar.projectVersion=1.3
+
+# Path is relative to the sonar-project.properties file
+sonar.sources=netbox_slm
+sonar.python.version=3.9
+
+# Unit tests
+sonar.python.xunit.reportPath=ci/reports/junit.xml
+sonar.python.coverage.reportPaths=ci/reports/coverage.xml
diff --git a/start-netbox.sh b/start-netbox.sh
index 96758e3..749e0f9 100755
--- a/start-netbox.sh
+++ b/start-netbox.sh
@@ -1,7 +1,7 @@
git clone -b release https://github.com/netbox-community/netbox-docker.git
cd netbox-docker
tee docker-compose.override.yml <