Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a53486ca23 | ||
|
|
4bc418a5d0 | ||
|
|
e952111a53 | ||
|
|
e73cb5fa1a | ||
|
|
56552bdd02 | ||
|
|
f914e78812 | ||
|
|
c9a7b2315e | ||
|
|
a8c9fc5fbe | ||
|
|
a1f6e3dc92 | ||
|
|
4f8053c0f6 | ||
|
|
3b3a6d63d4 | ||
|
|
ce283dea52 | ||
|
|
f3579cce63 | ||
|
|
3bb711ea84 | ||
|
|
9d76bb421d |
+49
-42
@@ -1,45 +1,47 @@
|
||||
Software Lifecycle Management
|
||||
-----------------------------
|
||||
<h1 align="center">NetBox SLM</h1>
|
||||
|
||||
*Netbox Plugin for lifecycle management of software components, including versions and installations*
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
<p align="center"><i>Netbox SLM is a plugin for lifecycle management of software components, including versions and installations.</i></p>
|
||||
|
||||
--------------
|
||||
<div align="center">
|
||||
<a href="https://pypi.org/project/netbox_slm/"><img src="https://img.shields.io/pypi/v/netbox_slm" alt="PyPi"/></a>
|
||||
<a href="https://github.com/ICTU/netbox_slm/stargazers"><img src="https://img.shields.io/github/stars/ICTU/netbox_slm" alt="Stars Badge"/></a>
|
||||
<a href="https://github.com/ICTU/netbox_slm/network/members"><img src="https://img.shields.io/github/forks/ICTU/netbox_slm" alt="Forks Badge"/></a>
|
||||
<a href="https://github.com/ICTU/netbox_slm/pulls"><img src="https://img.shields.io/github/issues-pr/ICTU/netbox_slm" alt="Pull Requests Badge"/></a>
|
||||
<a href="https://github.com/ICTU/netbox_slm/issues"><img src="https://img.shields.io/github/issues/ICTU/netbox_slm" alt="Issues Badge"/></a>
|
||||
<a href="https://github.com/ICTU/netbox_slm/graphs/contributors"><img alt="GitHub contributors" src="https://img.shields.io/github/contributors/ICTU/netbox_slm?color=2b9348"></a>
|
||||
<a href="https://github.com/ICTU/netbox_slm/blob/master/LICENSE"><img src="https://img.shields.io/github/license/ICTU/netbox_slm?color=2b9348" alt="License Badge"/></a>
|
||||
</div>
|
||||
|
||||
|
||||
## Known Issues
|
||||
|
||||
Known Issues
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
- WARNING: This plugin is only tested with Netbox 3.2 at this time.
|
||||
- CSV/Bulk imports for SoftwareProduct, Version and Installation are currently broken (WIP)
|
||||
|
||||
Installation Guide
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
## Installation Guide
|
||||
|
||||
When using the Docker version of Netbox, first follow the `netbox-docker
|
||||
quickstart <https://github.com/netbox-community/netbox-docker#quickstart>`__
|
||||
instructions to clone the netbox-docker repo and set up the
|
||||
``docker-compose.override.yml``.
|
||||
When using the Docker version of Netbox, first follow the netbox-docker [quickstart](https://github.com/netbox-community/netbox-docker#quickstart) instructions to clone the netbox-docker repo and set up the ``docker-compose.override.yml``.
|
||||
|
||||
Next, follow these instructions (based on the `Netbox docker variant
|
||||
instructions <https://github.com/netbox-community/netbox-docker/wiki/Configuration#custom-configuration-files>`__)
|
||||
Next, follow these instructions (based on the Netbox docker variant
|
||||
[instructions](https://github.com/netbox-community/netbox-docker/wiki/Configuration#custom-configuration-files))
|
||||
to install the Netbox SLM plugin:
|
||||
|
||||
1. Add ``netbox_slm`` to the ``PLUGINS`` list in
|
||||
``configuration/extra.py``.
|
||||
2. Create a ``plugin_requirements.txt`` with ``netbox-slm==0.99`` as
|
||||
2. Create a ``plugin_requirements.txt`` with ``netbox-slm==1.2`` as
|
||||
contents.
|
||||
3. Create a ``Dockerfile-SLM`` with contents:
|
||||
|
||||
.. code:: dockerfile
|
||||
|
||||
```
|
||||
FROM netboxcommunity/netbox:v3.2.X
|
||||
|
||||
COPY ./plugin_requirements.txt /
|
||||
RUN /opt/netbox/venv/bin/pip install --no-warn-script-location -r /plugin_requirements.txt
|
||||
```
|
||||
|
||||
4. Create a ``docker-compose.override.yml`` with contents:
|
||||
|
||||
.. code:: yaml
|
||||
|
||||
```
|
||||
version: '3.4'
|
||||
services:
|
||||
netbox:
|
||||
@@ -53,24 +55,24 @@ to install the Netbox SLM plugin:
|
||||
image: netbox:slm
|
||||
netbox-housekeeping:
|
||||
image: netbox:slm
|
||||
```
|
||||
|
||||
Now, build the image: ``docker compose build --no-cache``
|
||||
|
||||
And finally, run Netbox with the SLM plugin: ``docker compose up``
|
||||
|
||||
Releasing Guide
|
||||
~~~~~~~~~~~~~~~
|
||||
## Releasing Guide
|
||||
|
||||
To draft a release;
|
||||
|
||||
update the setup.py file to reflect the new version, then from the *src*
|
||||
directory run
|
||||
|
||||
::
|
||||
|
||||
```
|
||||
# make sure to update the version in netbox_slm/__init__.py
|
||||
$ python setup.py sdist
|
||||
$ twine upload dist/*
|
||||
```
|
||||
|
||||
On Github.com create a similar tag and version. These steps could be
|
||||
automated with a github workflow.
|
||||
@@ -78,55 +80,56 @@ automated with a github workflow.
|
||||
n.b. Currently the plugin is configured to use a personal pypi account,
|
||||
this should be changed.
|
||||
|
||||
Developer Guide (local installation)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
## Developer Guide (local installation)
|
||||
|
||||
*Follow the steps below on your local system to run netbox and the
|
||||
netbox_slm plugin in developer mode*
|
||||
|
||||
Setup
|
||||
~~~~~
|
||||
### Setup
|
||||
|
||||
The goal below is to run all Netbox components in Docker and run a local
|
||||
Netbox Django copy with auto-reload to develop the plugin pointing to
|
||||
the Dockerized postgres and redis instances, basically ignoring the
|
||||
netbox docker runtime server.
|
||||
|
||||
Steps
|
||||
~~~~~
|
||||
|
||||
::
|
||||
### Steps
|
||||
|
||||
from your projects directory clone the netbox repository
|
||||
|
||||
```
|
||||
$ git clone https://github.com/netbox-community/netbox
|
||||
$ cd netbox
|
||||
```
|
||||
|
||||
install the virtual environment
|
||||
|
||||
```
|
||||
$ pipenv shell
|
||||
$ pipenv install
|
||||
```
|
||||
|
||||
create and edit netbox/configuration.py (based on the template file) add these lines at the end of the file;
|
||||
|
||||
```
|
||||
DEBUG = True
|
||||
SECRET_KEY = 'dummy'
|
||||
DEVELOPER = True
|
||||
PLUGINS = [
|
||||
'netbox_slm',
|
||||
]
|
||||
```
|
||||
|
||||
The Netbox installation above will be used to run Django management
|
||||
commands like runserver, makemigrations and migrate, which will be
|
||||
explained in the next steps below;
|
||||
|
||||
::
|
||||
|
||||
from your projects directory clone the netbox-slm repository
|
||||
|
||||
```
|
||||
$ git clone https://github.com/ICTU/netbox_slm
|
||||
$ cd netbox_slm
|
||||
$ ./start-netbox.sh
|
||||
```
|
||||
|
||||
This will start Netbox locally (requires Docker) and forward the redis
|
||||
and postgres ports to the localhost (make sure there’s no processes
|
||||
@@ -134,20 +137,24 @@ using these ports or change the dockerfiles accordingly)
|
||||
|
||||
Note, you can also start and stop netbox by hand:
|
||||
|
||||
::
|
||||
|
||||
```
|
||||
$ cd netbox-docker
|
||||
$ docker-compose up -d
|
||||
```
|
||||
|
||||
or stop the stack with
|
||||
|
||||
```
|
||||
$ docker-compose down
|
||||
```
|
||||
|
||||
# to start fresh:
|
||||
|
||||
```
|
||||
$ docker-compose down
|
||||
$ docker volume rm netbox-docker_netbox-postgres-data # et cetera
|
||||
$ docker-compose up -d --force-recreate
|
||||
```
|
||||
|
||||
this will require you to re-run the migrate commando's for netbox-slm, see further down below
|
||||
|
||||
@@ -156,8 +163,7 @@ redis connection strings (username, password) to the ones the netbox
|
||||
docker backend is using, for example (using default user and passwords
|
||||
from the netbox docker example):
|
||||
|
||||
::
|
||||
|
||||
```
|
||||
<<collapsed>>
|
||||
|
||||
# PostgreSQL database configuration. See the Django documentation for a complete list of available parameters:
|
||||
@@ -204,15 +210,16 @@ from the netbox docker example):
|
||||
}
|
||||
|
||||
<<collapsed>>
|
||||
```
|
||||
|
||||
Now you can run commands from the netbox repository like this;
|
||||
|
||||
::
|
||||
|
||||
```
|
||||
$ cd netbox/netbox
|
||||
$ export PYTHONPATH=../../netbox-slm/src/
|
||||
$ export PYTHONPATH=../../netbox_slm/netbox_slm/ # or with the pipenv activated run `python3 setup.py develop` from the netbox_slm directory
|
||||
$ python3 manage.py migrate netbox_slm
|
||||
$ python3 manage.py runserver 8001
|
||||
```
|
||||
|
||||
Visit http://127.0.0.1:8001 in the browesr to see the auto reloading
|
||||
Visit http://127.0.0.1:8001 in the browser to see the auto reloading
|
||||
version of the netbox UI. Port 8000 is taken by the docker ran variant.
|
||||
@@ -5,7 +5,7 @@ class SLMConfig(PluginConfig):
|
||||
name = 'netbox_slm'
|
||||
verbose_name = 'Software Lifecycle Management'
|
||||
description = 'Software Lifecycle Management'
|
||||
version = '0.99'
|
||||
version = '1.2'
|
||||
author = 'Hedde van der Heide'
|
||||
author_email = 'hedde.vanderheide@ictu.nl'
|
||||
base_url = 'slm'
|
||||
@@ -0,0 +1,53 @@
|
||||
from django.db.models import Q
|
||||
|
||||
from netbox.filtersets import NetBoxModelFilterSet
|
||||
from netbox_slm.models import *
|
||||
|
||||
|
||||
class SoftwareProductFilterSet(NetBoxModelFilterSet):
|
||||
"""Filter capabilities for SoftwareProduct instances."""
|
||||
class Meta:
|
||||
model = SoftwareProduct
|
||||
fields = tuple()
|
||||
|
||||
def search(self, queryset, name, value):
|
||||
"""Perform the filtered search."""
|
||||
if not value.strip():
|
||||
return queryset
|
||||
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 = (
|
||||
"software_product",
|
||||
)
|
||||
|
||||
def search(self, queryset, name, value):
|
||||
"""Perform the filtered search."""
|
||||
if not value.strip():
|
||||
return queryset
|
||||
qs_filter = Q(name__icontains=value) | \
|
||||
Q(software_product__name__icontains=value) | \
|
||||
Q(software_product__manufacturer__name__icontains=value)
|
||||
return queryset.filter(qs_filter)
|
||||
|
||||
|
||||
class SoftwareProductInstallationFilterSet(NetBoxModelFilterSet):
|
||||
"""Filter capabilities for SoftwareProductInstallation instances."""
|
||||
class Meta:
|
||||
model = SoftwareProductInstallation
|
||||
fields = tuple()
|
||||
|
||||
def search(self, queryset, name, value):
|
||||
"""Perform the filtered search."""
|
||||
if not value.strip():
|
||||
return queryset
|
||||
qs_filter = Q(software_product__name__icontains=value) | \
|
||||
Q(software_product__manufacturer__name__icontains=value) | \
|
||||
Q(version__name__icontains=value)
|
||||
return queryset.filter(qs_filter)
|
||||
@@ -1,5 +1,4 @@
|
||||
from django import forms
|
||||
from django.db.models import Q
|
||||
from django.urls import reverse_lazy
|
||||
from django.utils.translation import gettext as _
|
||||
|
||||
@@ -12,7 +11,7 @@ from netbox.forms import (
|
||||
)
|
||||
from netbox_slm.models import SoftwareProduct, SoftwareProductVersion, SoftwareProductInstallation
|
||||
from utilities.forms import (
|
||||
DynamicModelChoiceField, APISelect, TagFilterField
|
||||
DynamicModelChoiceField, APISelect, TagFilterField, ChoiceField
|
||||
)
|
||||
from virtualization.models import VirtualMachine
|
||||
|
||||
@@ -22,7 +21,7 @@ class SoftwareProductForm(NetBoxModelForm):
|
||||
|
||||
manufacturer = DynamicModelChoiceField(
|
||||
queryset=Manufacturer.objects.all(),
|
||||
required=False,
|
||||
required=True,
|
||||
)
|
||||
|
||||
class Meta:
|
||||
@@ -38,14 +37,6 @@ class SoftwareProductFilterForm(NetBoxModelFilterSetForm):
|
||||
|
||||
tag = TagFilterField(model)
|
||||
|
||||
def search(self, queryset, name, value):
|
||||
"""Perform the filtered search."""
|
||||
if not value.strip():
|
||||
return queryset
|
||||
qs_filter = Q(name__icontains=value) | \
|
||||
Q(manufacturer__name__icontains=value)
|
||||
return queryset.filter(qs_filter)
|
||||
|
||||
|
||||
class SoftwareProductCSVForm(NetBoxModelCSVForm):
|
||||
class Meta:
|
||||
@@ -88,15 +79,6 @@ class SoftwareProductVersionFilterForm(NetBoxModelFilterSetForm):
|
||||
|
||||
tag = TagFilterField(model)
|
||||
|
||||
def search(self, queryset, name, value):
|
||||
"""Perform the filtered search."""
|
||||
if not value.strip():
|
||||
return queryset
|
||||
qs_filter = Q(name__icontains=value) | \
|
||||
Q(software_product__name__icontains=value) | \
|
||||
Q(software_product__manufacturer__name__icontains=value)
|
||||
return queryset.filter(qs_filter)
|
||||
|
||||
|
||||
class SoftwareProductVersionCSVForm(NetBoxModelCSVForm):
|
||||
class Meta:
|
||||
@@ -165,20 +147,11 @@ class SoftwareProductInstallationForm(NetBoxModelForm):
|
||||
class SoftwareProductInstallationFilterForm(NetBoxModelFilterSetForm):
|
||||
model = SoftwareProductInstallation
|
||||
fieldsets = (
|
||||
(None, ('q', 'tag')),
|
||||
(None, ('q', 'tag',)),
|
||||
)
|
||||
|
||||
tag = TagFilterField(model)
|
||||
|
||||
def search(self, queryset, name, value):
|
||||
"""Perform the filtered search."""
|
||||
if not value.strip():
|
||||
return queryset
|
||||
qs_filter = Q(software_product__name__icontains=value) | \
|
||||
Q(software_product__manufacturer__name__icontains=value) | \
|
||||
Q(version__name__icontains=value)
|
||||
return queryset.filter(qs_filter)
|
||||
|
||||
|
||||
class SoftwareProductInstallationCSVForm(NetBoxModelCSVForm):
|
||||
class Meta:
|
||||
@@ -1,6 +1,6 @@
|
||||
[metadata]
|
||||
name = netbox-slm
|
||||
version = 0.99
|
||||
version = 1.2
|
||||
description = Software Lifecycle Management Netbox Plugin.
|
||||
# long_description = file: README.rst
|
||||
# long_description_content_type='text/x-rst'
|
||||
-13
@@ -1,13 +0,0 @@
|
||||
Copyright 2022 ICTU
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
@@ -1,14 +0,0 @@
|
||||
from django.contrib import admin
|
||||
from netbox_slm.models import SoftwareProduct, SoftwareProductVersion
|
||||
|
||||
|
||||
class SoftwareProductVersionInline(admin.TabularInline):
|
||||
model = SoftwareProductVersion
|
||||
fields = ('name',)
|
||||
extra = 0
|
||||
|
||||
|
||||
@admin.register(SoftwareProduct)
|
||||
class SoftwareProductAdmin(admin.ModelAdmin):
|
||||
list_display = ('name',)
|
||||
inlines = (SoftwareProductVersionInline,)
|
||||
@@ -1,23 +0,0 @@
|
||||
from netbox.filtersets import NetBoxModelFilterSet
|
||||
from netbox_slm.models import *
|
||||
|
||||
|
||||
class SoftwareProductFilterSet(NetBoxModelFilterSet):
|
||||
"""Filter capabilities for SoftwareProduct instances."""
|
||||
class Meta:
|
||||
model = SoftwareProduct
|
||||
fields = tuple()
|
||||
|
||||
|
||||
class SoftwareProductVersionFilterSet(NetBoxModelFilterSet):
|
||||
"""Filter capabilities for SoftwareProductVersion instances."""
|
||||
class Meta:
|
||||
model = SoftwareProductVersion
|
||||
fields = tuple()
|
||||
|
||||
|
||||
class SoftwareProductInstallationFilterSet(NetBoxModelFilterSet):
|
||||
"""Filter capabilities for SoftwareProductInstallation instances."""
|
||||
class Meta:
|
||||
model = SoftwareProductInstallation
|
||||
fields = tuple()
|
||||
Reference in New Issue
Block a user