Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
19fc473286 | ||
|
|
f4188b957f | ||
|
|
51736942e7 | ||
|
|
bf63046edb | ||
|
|
72274e59b5 | ||
|
|
ae06bea12d | ||
|
|
6937a0ecca | ||
|
|
e7eb5b46e4 | ||
|
|
154c0de9f4 | ||
|
|
c84aa3650b | ||
|
|
fb29bc4258 | ||
|
|
7e59a5644b | ||
|
|
f1dbedcfba | ||
|
|
bbb00d667d | ||
|
|
743759f0e6 | ||
|
|
3ed18c5767 | ||
|
|
e926f01141 | ||
|
|
bc0b77f962 | ||
|
|
cec3d50313 | ||
|
|
d70f8afc41 | ||
|
|
0122275ee1 | ||
|
|
267cb8db63 |
@@ -0,0 +1,13 @@
|
||||
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.
|
||||
@@ -6,6 +6,7 @@ name = "pypi"
|
||||
[packages]
|
||||
|
||||
[dev-packages]
|
||||
twine = "3.7.1"
|
||||
|
||||
[requires]
|
||||
python_version = "3.9"
|
||||
|
||||
Generated
+192
@@ -0,0 +1,192 @@
|
||||
{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "f3cebe84c169ba6773cfcfae65b47e5076fa331e445f47a6ec4d13306942deb4"
|
||||
},
|
||||
"pipfile-spec": 6,
|
||||
"requires": {
|
||||
"python_version": "3.9"
|
||||
},
|
||||
"sources": [
|
||||
{
|
||||
"name": "pypi",
|
||||
"url": "https://pypi.org/simple",
|
||||
"verify_ssl": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"default": {},
|
||||
"develop": {
|
||||
"bleach": {
|
||||
"hashes": [
|
||||
"sha256:0900d8b37eba61a802ee40ac0061f8c2b5dee29c1927dd1d233e075ebf5a71da",
|
||||
"sha256:4d2651ab93271d1129ac9cbc679f524565cc8a1b791909c4a51eac4446a15994"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==4.1.0"
|
||||
},
|
||||
"certifi": {
|
||||
"hashes": [
|
||||
"sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872",
|
||||
"sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569"
|
||||
],
|
||||
"version": "==2021.10.8"
|
||||
},
|
||||
"charset-normalizer": {
|
||||
"hashes": [
|
||||
"sha256:876d180e9d7432c5d1dfd4c5d26b72f099d503e8fcc0feb7532c9289be60fcbd",
|
||||
"sha256:cb957888737fc0bbcd78e3df769addb41fd1ff8cf950dc9e7ad7793f1bf44455"
|
||||
],
|
||||
"markers": "python_version >= '3'",
|
||||
"version": "==2.0.10"
|
||||
},
|
||||
"colorama": {
|
||||
"hashes": [
|
||||
"sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b",
|
||||
"sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||
"version": "==0.4.4"
|
||||
},
|
||||
"docutils": {
|
||||
"hashes": [
|
||||
"sha256:23010f129180089fbcd3bc08cfefccb3b890b0050e1ca00c867036e9d161b98c",
|
||||
"sha256:679987caf361a7539d76e584cbeddc311e3aee937877c87346f31debc63e9d06"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||
"version": "==0.18.1"
|
||||
},
|
||||
"idna": {
|
||||
"hashes": [
|
||||
"sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff",
|
||||
"sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"
|
||||
],
|
||||
"markers": "python_version >= '3'",
|
||||
"version": "==3.3"
|
||||
},
|
||||
"importlib-metadata": {
|
||||
"hashes": [
|
||||
"sha256:92a8b58ce734b2a4494878e0ecf7d79ccd7a128b5fc6014c401e0b61f006f0f6",
|
||||
"sha256:b7cf7d3fef75f1e4c80a96ca660efbd51473d7e8f39b5ab9210febc7809012a4"
|
||||
],
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==4.10.0"
|
||||
},
|
||||
"keyring": {
|
||||
"hashes": [
|
||||
"sha256:9012508e141a80bd1c0b6778d5c610dd9f8c464d75ac6774248500503f972fb9",
|
||||
"sha256:b0d28928ac3ec8e42ef4cc227822647a19f1d544f21f96457965dc01cf555261"
|
||||
],
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==23.5.0"
|
||||
},
|
||||
"packaging": {
|
||||
"hashes": [
|
||||
"sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb",
|
||||
"sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==21.3"
|
||||
},
|
||||
"pkginfo": {
|
||||
"hashes": [
|
||||
"sha256:542e0d0b6750e2e21c20179803e40ab50598d8066d51097a0e382cba9eb02bff",
|
||||
"sha256:c24c487c6a7f72c66e816ab1796b96ac6c3d14d49338293d2141664330b55ffc"
|
||||
],
|
||||
"version": "==1.8.2"
|
||||
},
|
||||
"pygments": {
|
||||
"hashes": [
|
||||
"sha256:59b895e326f0fb0d733fd28c6839bd18ad0687ba20efc26d4277fd1d30b971f4",
|
||||
"sha256:9135c1af61eec0f650cd1ea1ed8ce298e54d56bcd8cc2ef46edd7702c171337c"
|
||||
],
|
||||
"markers": "python_version >= '3.5'",
|
||||
"version": "==2.11.1"
|
||||
},
|
||||
"pyparsing": {
|
||||
"hashes": [
|
||||
"sha256:04ff808a5b90911829c55c4e26f75fa5ca8a2f5f36aa3a51f68e27033341d3e4",
|
||||
"sha256:d9bdec0013ef1eb5a84ab39a3b3868911598afa494f5faa038647101504e2b81"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==3.0.6"
|
||||
},
|
||||
"readme-renderer": {
|
||||
"hashes": [
|
||||
"sha256:a50a0f2123a4c1145ac6f420e1a348aafefcc9211c846e3d51df05fe3d865b7d",
|
||||
"sha256:b512beafa6798260c7d5af3e1b1f097e58bfcd9a575da7c4ddd5e037490a5b85"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==32.0"
|
||||
},
|
||||
"requests": {
|
||||
"hashes": [
|
||||
"sha256:8e5643905bf20a308e25e4c1dd379117c09000bf8a82ebccc462cfb1b34a16b5",
|
||||
"sha256:f71a09d7feba4a6b64ffd8e9d9bc60f9bf7d7e19fd0e04362acb1cfc2e3d98df"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'",
|
||||
"version": "==2.27.0"
|
||||
},
|
||||
"requests-toolbelt": {
|
||||
"hashes": [
|
||||
"sha256:380606e1d10dc85c3bd47bf5a6095f815ec007be7a8b69c878507068df059e6f",
|
||||
"sha256:968089d4584ad4ad7c171454f0a5c6dac23971e9472521ea3b6d49d610aa6fc0"
|
||||
],
|
||||
"version": "==0.9.1"
|
||||
},
|
||||
"rfc3986": {
|
||||
"hashes": [
|
||||
"sha256:270aaf10d87d0d4e095063c65bf3ddbc6ee3d0b226328ce21e036f946e421835",
|
||||
"sha256:a86d6e1f5b1dc238b218b012df0aa79409667bb209e58da56d0b94704e712a97"
|
||||
],
|
||||
"version": "==1.5.0"
|
||||
},
|
||||
"six": {
|
||||
"hashes": [
|
||||
"sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926",
|
||||
"sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'",
|
||||
"version": "==1.16.0"
|
||||
},
|
||||
"tqdm": {
|
||||
"hashes": [
|
||||
"sha256:8dd278a422499cd6b727e6ae4061c40b48fce8b76d1ccbf5d34fca9b7f925b0c",
|
||||
"sha256:d359de7217506c9851b7869f3708d8ee53ed70a1b8edbba4dbcb47442592920d"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==4.62.3"
|
||||
},
|
||||
"twine": {
|
||||
"hashes": [
|
||||
"sha256:28460a3db6b4532bde6a5db6755cf2dce6c5020bada8a641bb2c5c7a9b1f35b8",
|
||||
"sha256:8c120845fc05270f9ee3e9d7ebbed29ea840e41f48cd059e04733f7e1d401345"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==3.7.1"
|
||||
},
|
||||
"urllib3": {
|
||||
"hashes": [
|
||||
"sha256:4987c65554f7a2dbf30c18fd48778ef124af6fab771a377103da0585e2336ece",
|
||||
"sha256:c4fdf4019605b6e5423637e01bc9fe4daef873709a7973e195ceba0a62bbc844"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'",
|
||||
"version": "==1.26.7"
|
||||
},
|
||||
"webencodings": {
|
||||
"hashes": [
|
||||
"sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78",
|
||||
"sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923"
|
||||
],
|
||||
"version": "==0.5.1"
|
||||
},
|
||||
"zipp": {
|
||||
"hashes": [
|
||||
"sha256:9f50f446828eb9d45b267433fd3e9da8d801f614129124863f9c51ebceafb87d",
|
||||
"sha256:b47250dd24f92b7dd6a0a8fc5244da14608f3ca90a5efcd37a3b1642fac9a375"
|
||||
],
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==3.7.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,153 +0,0 @@
|
||||
## Software Lifecycle Management
|
||||
|
||||
### _Netbox Plugin for lifecycle management of software components, including versions and installations_
|
||||
|
||||
---
|
||||
|
||||
### Installation Guide
|
||||
|
||||
Depending on running in Docker (see the netbox-docker repository) add netbox_slm to the plugin_requirements.txt (requires a valid pypi version)
|
||||
|
||||
```
|
||||
netbox-slm==0.1
|
||||
```
|
||||
|
||||
Change the configuration.py to include the plugin:
|
||||
|
||||
```
|
||||
PLUGINS = [
|
||||
'netbox_slm',
|
||||
]
|
||||
```
|
||||
|
||||
### Releasing Guide
|
||||
|
||||
_TODO_
|
||||
|
||||
### Developer Guide (local installation)
|
||||
|
||||
_Follow the steps below on your local system to run netbox and the netbox_slm plugin in developer mode_
|
||||
|
||||
### 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.
|
||||
|
||||
### Gotcha's
|
||||
|
||||
_Netbox's exception handler seems to supress initial Exceptions, obfuscating missing imports or other Django related issues by re-raising an opague error, e.g. netbox_slm plugin namespace doesnotexist. It's recommended to often check the runtime server or patch Netbox's global exception handler._
|
||||
|
||||
### Steps
|
||||
|
||||
```
|
||||
from your projects directory clone the netbox repository
|
||||
|
||||
$ git clone https://github.com/netbox-community/netbox
|
||||
$ cd netbox
|
||||
$ git checkout f5356b8 (to pin 3.0.9)
|
||||
|
||||
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 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
|
||||
```
|
||||
|
||||
Go back to the netbox configuration.py file and update the postgres and 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:
|
||||
# https://docs.djangoproject.com/en/stable/ref/settings/#databases
|
||||
DATABASE = {
|
||||
'NAME': 'netbox', # Database name
|
||||
'USER': 'netbox', # PostgreSQL username
|
||||
'PASSWORD': 'J5brHrAXFLQSif0K', # PostgreSQL password
|
||||
'HOST': 'localhost', # Database server
|
||||
'PORT': '', # Database port (leave blank for default)
|
||||
'CONN_MAX_AGE': 300, # Max database connection age
|
||||
}
|
||||
|
||||
# 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': 'localhost',
|
||||
'PORT': 6379,
|
||||
# Comment out `HOST` and `PORT` lines and uncomment the following if using Redis Sentinel
|
||||
# 'SENTINELS': [('mysentinel.redis.example.com', 6379)],
|
||||
# 'SENTINEL_SERVICE': 'netbox',
|
||||
'PASSWORD': 'H733Kdjndks81',
|
||||
'DATABASE': 0,
|
||||
'SSL': False,
|
||||
# Set this to True to skip TLS certificate verification
|
||||
# This can expose the connection to attacks, be careful
|
||||
# 'INSECURE_SKIP_TLS_VERIFY': False,
|
||||
},
|
||||
'caching': {
|
||||
'HOST': 'localhost',
|
||||
'PORT': 6379,
|
||||
# Comment out `HOST` and `PORT` lines and uncomment the following if using Redis Sentinel
|
||||
# 'SENTINELS': [('mysentinel.redis.example.com', 6379)],
|
||||
# 'SENTINEL_SERVICE': 'netbox',
|
||||
'PASSWORD': 'H733Kdjndks81',
|
||||
'DATABASE': 1,
|
||||
'SSL': False,
|
||||
# Set this to True to skip TLS certificate verification
|
||||
# This can expose the connection to attacks, be careful
|
||||
# 'INSECURE_SKIP_TLS_VERIFY': False,
|
||||
}
|
||||
}
|
||||
|
||||
<<collapsed>>
|
||||
```
|
||||
|
||||
Now you can run commands from the netbox repository like this;
|
||||
|
||||
```
|
||||
$ cd netbox/netbox
|
||||
$ export PYTHONPATH=../../netbox-slm/src/
|
||||
$ 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 version of the netbox UI. Port 8000 is taken by the docker ran variant.
|
||||
+223
@@ -0,0 +1,223 @@
|
||||
Software Lifecycle Management
|
||||
-----------------------------
|
||||
|
||||
*Netbox Plugin for lifecycle management of software components, including versions and installations*
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
--------------
|
||||
|
||||
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``.
|
||||
|
||||
Next, follow these instructions (based on the generic `Netbox plugin
|
||||
instructions <https://github.com/netbox-community/netbox-docker/wiki/Using-Netbox-Plugins>`__)
|
||||
to install the Netbox SLM plugin:
|
||||
|
||||
1. Add ``netbox_slm`` to the ``PLUGINS`` list in
|
||||
``configuration/configuration.py``.
|
||||
2. Create a ``plugin_requirements.txt`` with ``netbox-slm==0.93`` as
|
||||
contents.
|
||||
3. Create a ``Dockerfile-SLM`` with contents:
|
||||
|
||||
.. code:: dockerfile
|
||||
|
||||
FROM netboxcommunity/netbox:v3.0.9 # The Netbox SLM plugin currently only works with v3.0.9 of Netbox due to backwards incompatible changes in newer version of Netbox
|
||||
|
||||
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:
|
||||
ports:
|
||||
- 8000:8080
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile-SLM
|
||||
image: netbox:slm
|
||||
netbox-worker:
|
||||
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
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
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.
|
||||
|
||||
n.b. Currently the plugin is configured to use a personal pypi account,
|
||||
this should be changed.
|
||||
|
||||
Developer Guide (local installation)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
*Follow the steps below on your local system to run netbox and the
|
||||
netbox_slm plugin in developer mode*
|
||||
|
||||
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.
|
||||
|
||||
Gotcha’s
|
||||
~~~~~~~~
|
||||
|
||||
*Netbox’s exception handler seems to supress initial Exceptions,
|
||||
obfuscating missing imports or other Django related issues by re-raising
|
||||
an opague error, e.g. netbox_slm plugin namespace doesnotexist. It’s
|
||||
recommended to often check the runtime server or patch Netbox’s global
|
||||
exception handler.*
|
||||
|
||||
Steps
|
||||
~~~~~
|
||||
|
||||
::
|
||||
|
||||
from your projects directory clone the netbox repository
|
||||
|
||||
$ git clone https://github.com/netbox-community/netbox
|
||||
$ cd netbox
|
||||
$ git checkout f5356b8 (to pin 3.0.9)
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
Go back to the netbox configuration.py file and update the postgres and
|
||||
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:
|
||||
# https://docs.djangoproject.com/en/stable/ref/settings/#databases
|
||||
DATABASE = {
|
||||
'NAME': 'netbox', # Database name
|
||||
'USER': 'netbox', # PostgreSQL username
|
||||
'PASSWORD': 'J5brHrAXFLQSif0K', # PostgreSQL password
|
||||
'HOST': 'localhost', # Database server
|
||||
'PORT': '', # Database port (leave blank for default)
|
||||
'CONN_MAX_AGE': 300, # Max database connection age
|
||||
}
|
||||
|
||||
# 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': 'localhost',
|
||||
'PORT': 6379,
|
||||
# Comment out `HOST` and `PORT` lines and uncomment the following if using Redis Sentinel
|
||||
# 'SENTINELS': [('mysentinel.redis.example.com', 6379)],
|
||||
# 'SENTINEL_SERVICE': 'netbox',
|
||||
'PASSWORD': 'H733Kdjndks81',
|
||||
'DATABASE': 0,
|
||||
'SSL': False,
|
||||
# Set this to True to skip TLS certificate verification
|
||||
# This can expose the connection to attacks, be careful
|
||||
# 'INSECURE_SKIP_TLS_VERIFY': False,
|
||||
},
|
||||
'caching': {
|
||||
'HOST': 'localhost',
|
||||
'PORT': 6379,
|
||||
# Comment out `HOST` and `PORT` lines and uncomment the following if using Redis Sentinel
|
||||
# 'SENTINELS': [('mysentinel.redis.example.com', 6379)],
|
||||
# 'SENTINEL_SERVICE': 'netbox',
|
||||
'PASSWORD': 'H733Kdjndks81',
|
||||
'DATABASE': 1,
|
||||
'SSL': False,
|
||||
# Set this to True to skip TLS certificate verification
|
||||
# This can expose the connection to attacks, be careful
|
||||
# 'INSECURE_SKIP_TLS_VERIFY': False,
|
||||
}
|
||||
}
|
||||
|
||||
<<collapsed>>
|
||||
|
||||
Now you can run commands from the netbox repository like this;
|
||||
|
||||
::
|
||||
|
||||
$ cd netbox/netbox
|
||||
$ export PYTHONPATH=../../netbox-slm/src/
|
||||
$ 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
|
||||
version of the netbox UI. Port 8000 is taken by the docker ran variant.
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
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.
|
||||
@@ -0,0 +1,3 @@
|
||||
include ../LICENSE
|
||||
include ../README.rst
|
||||
recursive-include netbox_slm/templates *
|
||||
+223
@@ -0,0 +1,223 @@
|
||||
Software Lifecycle Management
|
||||
-----------------------------
|
||||
|
||||
*Netbox Plugin for lifecycle management of software components, including versions and installations*
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
--------------
|
||||
|
||||
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``.
|
||||
|
||||
Next, follow these instructions (based on the generic `Netbox plugin
|
||||
instructions <https://github.com/netbox-community/netbox-docker/wiki/Using-Netbox-Plugins>`__)
|
||||
to install the Netbox SLM plugin:
|
||||
|
||||
1. Add ``netbox_slm`` to the ``PLUGINS`` list in
|
||||
``configuration/configuration.py``.
|
||||
2. Create a ``plugin_requirements.txt`` with ``netbox-slm==0.93`` as
|
||||
contents.
|
||||
3. Create a ``Dockerfile-SLM`` with contents:
|
||||
|
||||
.. code:: dockerfile
|
||||
|
||||
FROM netboxcommunity/netbox:v3.0.9 # The Netbox SLM plugin currently only works with v3.0.9 of Netbox due to backwards incompatible changes in newer version of Netbox
|
||||
|
||||
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:
|
||||
ports:
|
||||
- 8000:8080
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile-SLM
|
||||
image: netbox:slm
|
||||
netbox-worker:
|
||||
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
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
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 and setup.cfg
|
||||
$ 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.
|
||||
|
||||
n.b. Currently the plugin is configured to use a personal pypi account,
|
||||
this should be changed.
|
||||
|
||||
Developer Guide (local installation)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
*Follow the steps below on your local system to run netbox and the
|
||||
netbox_slm plugin in developer mode*
|
||||
|
||||
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.
|
||||
|
||||
Gotcha’s
|
||||
~~~~~~~~
|
||||
|
||||
*Netbox’s exception handler seems to supress initial Exceptions,
|
||||
obfuscating missing imports or other Django related issues by re-raising
|
||||
an opague error, e.g. netbox_slm plugin namespace doesnotexist. It’s
|
||||
recommended to often check the runtime server or patch Netbox’s global
|
||||
exception handler.*
|
||||
|
||||
Steps
|
||||
~~~~~
|
||||
|
||||
::
|
||||
|
||||
from your projects directory clone the netbox repository
|
||||
|
||||
$ git clone https://github.com/netbox-community/netbox
|
||||
$ cd netbox
|
||||
$ git checkout f5356b8 (to pin 3.0.9)
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
Go back to the netbox configuration.py file and update the postgres and
|
||||
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:
|
||||
# https://docs.djangoproject.com/en/stable/ref/settings/#databases
|
||||
DATABASE = {
|
||||
'NAME': 'netbox', # Database name
|
||||
'USER': 'netbox', # PostgreSQL username
|
||||
'PASSWORD': 'J5brHrAXFLQSif0K', # PostgreSQL password
|
||||
'HOST': 'localhost', # Database server
|
||||
'PORT': '', # Database port (leave blank for default)
|
||||
'CONN_MAX_AGE': 300, # Max database connection age
|
||||
}
|
||||
|
||||
# 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': 'localhost',
|
||||
'PORT': 6379,
|
||||
# Comment out `HOST` and `PORT` lines and uncomment the following if using Redis Sentinel
|
||||
# 'SENTINELS': [('mysentinel.redis.example.com', 6379)],
|
||||
# 'SENTINEL_SERVICE': 'netbox',
|
||||
'PASSWORD': 'H733Kdjndks81',
|
||||
'DATABASE': 0,
|
||||
'SSL': False,
|
||||
# Set this to True to skip TLS certificate verification
|
||||
# This can expose the connection to attacks, be careful
|
||||
# 'INSECURE_SKIP_TLS_VERIFY': False,
|
||||
},
|
||||
'caching': {
|
||||
'HOST': 'localhost',
|
||||
'PORT': 6379,
|
||||
# Comment out `HOST` and `PORT` lines and uncomment the following if using Redis Sentinel
|
||||
# 'SENTINELS': [('mysentinel.redis.example.com', 6379)],
|
||||
# 'SENTINEL_SERVICE': 'netbox',
|
||||
'PASSWORD': 'H733Kdjndks81',
|
||||
'DATABASE': 1,
|
||||
'SSL': False,
|
||||
# Set this to True to skip TLS certificate verification
|
||||
# This can expose the connection to attacks, be careful
|
||||
# 'INSECURE_SKIP_TLS_VERIFY': False,
|
||||
}
|
||||
}
|
||||
|
||||
<<collapsed>>
|
||||
|
||||
Now you can run commands from the netbox repository like this;
|
||||
|
||||
::
|
||||
|
||||
$ cd netbox/netbox
|
||||
$ export PYTHONPATH=../../netbox-slm/src/
|
||||
$ 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
|
||||
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.1'
|
||||
version = '0.94'
|
||||
author = 'Hedde van der Heide'
|
||||
author_email = 'hedde.vanderheide@ictu.nl'
|
||||
base_url = 'slm'
|
||||
|
||||
@@ -21,7 +21,7 @@ class SoftwareProductSerializer(PrimaryModelSerializer):
|
||||
]
|
||||
|
||||
def get_display(self, obj):
|
||||
return obj.name
|
||||
return f"{obj.manufacturer.name} - {obj.name}"
|
||||
|
||||
|
||||
class SoftwareProductVersionSerializer(PrimaryModelSerializer):
|
||||
|
||||
@@ -74,7 +74,6 @@ class SoftwareProductVersionForm(BootstrapMixin, CustomFieldModelForm):
|
||||
|
||||
software_product = DynamicModelChoiceField(
|
||||
queryset=SoftwareProduct.objects.all(),
|
||||
required=False,
|
||||
widget=APISelect(
|
||||
attrs={"data-url": reverse_lazy("plugins-api:netbox_slm-api:softwareproduct-list")}
|
||||
),
|
||||
@@ -171,9 +170,10 @@ class SoftwareProductInstallationForm(BootstrapMixin, CustomFieldModelForm):
|
||||
model = SoftwareProductInstallation
|
||||
fields = ("device", "virtualmachine", "software_product", "version",) # "tags")
|
||||
|
||||
# def clean(self):
|
||||
# import pdb;pdb.set_trace()
|
||||
# return super(SoftwareProductInstallationForm, self).clean()
|
||||
def clean(self):
|
||||
if not any([self.cleaned_data['device'], self.cleaned_data['virtualmachine']]):
|
||||
raise forms.ValidationError(_("Installation requires atleast one virtualmachine or device destination."))
|
||||
return super(SoftwareProductInstallationForm, self).clean()
|
||||
|
||||
|
||||
class SoftwareProductInstallationFilterForm(BootstrapMixin, CustomFieldModelFilterForm):
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
# Generated by Django 3.2.9 on 2022-01-24 08:05
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('dcim', '0133_port_colors'),
|
||||
('netbox_slm', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='softwareproduct',
|
||||
name='manufacturer',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='software_products', to='dcim.manufacturer'),
|
||||
),
|
||||
]
|
||||
@@ -17,7 +17,8 @@ class SoftwareProduct(PrimaryModel):
|
||||
manufacturer = models.ForeignKey(
|
||||
to='dcim.Manufacturer',
|
||||
on_delete=models.PROTECT,
|
||||
related_name='software_products'
|
||||
related_name='software_products',
|
||||
null=True, blank=True
|
||||
)
|
||||
|
||||
objects = RestrictedQuerySet.as_manager()
|
||||
@@ -95,3 +96,9 @@ class SoftwareProductInstallation(PrimaryModel):
|
||||
|
||||
def get_absolute_url(self):
|
||||
return reverse("plugins:netbox_slm:softwareproductinstallation", kwargs={"pk": self.pk})
|
||||
|
||||
def get_platform(self):
|
||||
return self.device or self.virtualmachine
|
||||
|
||||
def render_type(self):
|
||||
return f"{'device' if self.device else 'virtualmachine'}"
|
||||
|
||||
@@ -37,6 +37,12 @@ class SoftwareProductTable(BaseTable):
|
||||
"installations",
|
||||
# "tags",
|
||||
)
|
||||
sequence = (
|
||||
"manufacturer",
|
||||
"name",
|
||||
"description",
|
||||
"installations",
|
||||
)
|
||||
|
||||
|
||||
class SoftwareProductVersionTable(BaseTable):
|
||||
@@ -76,6 +82,12 @@ class SoftwareProductVersionTable(BaseTable):
|
||||
"installations",
|
||||
# "tags",
|
||||
)
|
||||
sequence = (
|
||||
"manufacturer",
|
||||
"software_product",
|
||||
"name",
|
||||
"installations",
|
||||
)
|
||||
|
||||
|
||||
class SoftwareProductInstallationTable(BaseTable):
|
||||
@@ -91,6 +103,11 @@ class SoftwareProductInstallationTable(BaseTable):
|
||||
accessor=Accessor('virtualmachine'),
|
||||
linkify=True
|
||||
)
|
||||
platform = tables.Column(
|
||||
accessor='get_platform',
|
||||
linkify=True
|
||||
)
|
||||
type = tables.Column(accessor='render_type')
|
||||
software_product = tables.Column(
|
||||
accessor=Accessor('software_product'),
|
||||
linkify=True
|
||||
@@ -109,17 +126,20 @@ class SoftwareProductInstallationTable(BaseTable):
|
||||
fields = (
|
||||
"pk",
|
||||
"name",
|
||||
"device",
|
||||
"virtualmachine",
|
||||
"platform",
|
||||
"type",
|
||||
"software_product",
|
||||
"version",
|
||||
# "tags",
|
||||
)
|
||||
default_columns = (
|
||||
"pk",
|
||||
"device",
|
||||
"virtualmachine",
|
||||
"platform",
|
||||
"type",
|
||||
"software_product",
|
||||
"version",
|
||||
# "tags",
|
||||
)
|
||||
|
||||
def render_software_product(self, value, **kwargs):
|
||||
return f"{kwargs['record'].software_product.manufacturer.name} - {value}"
|
||||
|
||||
@@ -25,11 +25,7 @@
|
||||
<tr>
|
||||
<th scope="row">Installations</th>
|
||||
<td>
|
||||
<!-- {% for version in object.softwareproduct_versions.all %}-->
|
||||
<!-- <a href="{% url 'plugins:netbox_slm:softwareproductversion' pk=version.pk %}">-->
|
||||
<!-- <span class="badge" style="color: #ffffff; background-color: #9e9e9e">{{ version }}</span>-->
|
||||
<!-- </a>-->
|
||||
<!-- {% endfor %}-->
|
||||
{{ object.get_installation_count }}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
@@ -78,9 +78,9 @@ class SoftwareProductVersionView(generic.ObjectView):
|
||||
|
||||
queryset = SoftwareProductVersion.objects.all()
|
||||
|
||||
# def get_extra_context(self, request, instance):
|
||||
# records = instance.record_set.all()
|
||||
# return {"records": records}
|
||||
def get_extra_context(self, request, instance):
|
||||
installation_count = instance.get_installation_count()
|
||||
return {"installations": installation_count}
|
||||
|
||||
|
||||
class SoftwareProductVersionEditView(generic.ObjectEditView):
|
||||
@@ -127,7 +127,7 @@ class SoftwareProductInstallationListView(generic.ObjectListView):
|
||||
class SoftwareProductInstallationView(generic.ObjectView):
|
||||
"""Display SoftwareProductInstallation details"""
|
||||
|
||||
queryset = SoftwareProductVersion.objects.all()
|
||||
queryset = SoftwareProductInstallation.objects.all()
|
||||
|
||||
# def get_extra_context(self, request, instance):
|
||||
# records = instance.record_set.all()
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
[metadata]
|
||||
name = netbox-slm
|
||||
version = 0.94
|
||||
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
|
||||
license = Apache 2.0
|
||||
classifiers =
|
||||
Environment :: Web Environment
|
||||
Framework :: Django
|
||||
Intended Audience :: Developers
|
||||
License :: OSI Approved :: Apache Software License
|
||||
Operating System :: OS Independent
|
||||
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
|
||||
Topic :: Internet :: WWW/HTTP
|
||||
Topic :: Internet :: WWW/HTTP :: Dynamic Content
|
||||
|
||||
[options]
|
||||
include_package_data = true
|
||||
packages = find:
|
||||
python_requires = >=3.7
|
||||
+2
-13
@@ -1,14 +1,3 @@
|
||||
from setuptools import find_packages, setup
|
||||
from setuptools import setup, Extension
|
||||
|
||||
setup(
|
||||
name='netbox-slm',
|
||||
version='0.9',
|
||||
description='Software Lifecycle Management Netbox Plugin',
|
||||
url='https://github.com/ICTU/netbox_slm',
|
||||
author='Hedde van der Heide',
|
||||
license='Apache 2.0',
|
||||
install_requires=[],
|
||||
packages=find_packages(),
|
||||
include_package_data=True,
|
||||
zip_safe=False,
|
||||
)
|
||||
setup()
|
||||
Reference in New Issue
Block a user