Compare commits
14 Commits
Author | SHA1 | Date | |
---|---|---|---|
1fa07c6dc1 | |||
c866bfff16 | |||
44cdb73cc4 | |||
20a86f0e98 | |||
1f9ea8db53 | |||
db7daee86e | |||
0bae952410 | |||
34cd2cc577 | |||
e55580e3ae | |||
aab28d03ba | |||
eb09bf5364 | |||
e46a7d2f7f | |||
03eb153da4 | |||
7675e8fc03 |
26
.github/issue_template.md
vendored
26
.github/issue_template.md
vendored
@ -9,6 +9,12 @@ Before raising an issue here, answer the following questions for yourself, pleas
|
||||
(Otherwise ask on the Netbox mailing list, please: https://groups.google.com/d/forum/netbox-discuss)
|
||||
* Have you looked through the issues already resolved?
|
||||
|
||||
Please try this means to get help before opening an issue here:
|
||||
|
||||
* On the networktocode Slack in the #netbox-docker channel: http://slack.networktocode.com/
|
||||
* On the networktocode Slack in the #netbox channel: http://slack.networktocode.com/
|
||||
* On the Netbox mailing list: https://groups.google.com/d/forum/netbox-discuss
|
||||
|
||||
-->
|
||||
|
||||
## Current Behavior
|
||||
@ -30,17 +36,19 @@ The output of `git rev-parse HEAD`: `XXXXX`
|
||||
The command you used to start the project: `XXXXX`
|
||||
|
||||
The output of `docker-compose logs netbox`:
|
||||
<!-- if your log is very long, create a Gist instead: https://gist.github.com -->
|
||||
|
||||
```
|
||||
LOG LOG LOG
|
||||
```
|
||||
|
||||
<!--
|
||||
If you have get any 5xx http error, else delete this section.
|
||||
If your log is very long, create a Gist instead: https://gist.github.com
|
||||
If your log is very long, create a Gist instead (and post the link to it): https://gist.github.com
|
||||
-->
|
||||
|
||||
```
|
||||
LOG LOG LOG
|
||||
```
|
||||
|
||||
The output of `docker-compose logs nginx`:
|
||||
<!--
|
||||
Only if you have gotten a 5xx http error, else delete this section.
|
||||
If your log is very long, create a Gist instead (and post the link to it): https://gist.github.com
|
||||
-->
|
||||
The output of `docker-compose logs nginx`:
|
||||
|
||||
```
|
||||
LOG LOG LOG
|
||||
|
15
README.md
15
README.md
@ -131,6 +131,18 @@ However, if you don't need this functionality, leave these blank.
|
||||
[napalm-doc]: http://napalm.readthedocs.io/en/latest/index.html
|
||||
[netbox-napalm-doc]: https://netbox.readthedocs.io/en/latest/configuration/optional-settings/#napalm_username
|
||||
|
||||
### Customizable Reporting
|
||||
|
||||
NetBox includes [customized reporting][netbox-reports-doc] that allows the user to write Python code and determine the validity of the data within NetBox.
|
||||
The `REPORTS_ROOT` variable is setup as a mapped directory within this Docker container to `/reports/` and includes the example directly from the documentation for `devices.py`.
|
||||
However, it has been renamed to `devices.py.example` which prevents NetBox from recognizing it as a valid report.
|
||||
This was done to avoid unnessary issues from being opened when the default does not work for someone's expectations.
|
||||
|
||||
To re-enable this default report, simply rename `devices.py.example` to `devices.py` and browse within the WebUI to `/extras/reports/`.
|
||||
You can also dynamically add any other report to this same directory and NetBox will be able to see it without restarting the container.
|
||||
|
||||
[netbox-reports-doc]: https://netbox.readthedocs.io/en/stable/additional-features/reports/
|
||||
|
||||
### Custom Initialization Code (e.g. Automatically Setting Up Custom Fields)
|
||||
|
||||
When using `docker-compose`, all the python scripts present in `/opt/netbox/startup_scripts` will automatically be executed after the application boots in the context of `./manage.py`.
|
||||
@ -368,6 +380,9 @@ Compare the version with the list below to check whether a breaking change was i
|
||||
|
||||
The following is a list of breaking changes of the `netbox-docker` project:
|
||||
|
||||
* 0.7.0: The value of the `MAX_PAGE_SIZE` environment variable was changed to `1000`, which is the default of Netbox.
|
||||
* 0.6.0: The naming of the default startup_scripts were changed.
|
||||
If you overwrite them, you may need to adjust these scripts.
|
||||
* 0.5.0: Alpine was updated to 3.8, `*.env` moved to `/env` folder
|
||||
* 0.4.0: In order to use Netbox webhooks you need to add Redis and a netbox-worker to your docker-compose.yml.
|
||||
* 0.3.0: Field `filterable: <boolean` was replaced with field `filter_logic: loose/exact/disabled`. It will default to `CF_FILTER_LOOSE=loose` when not defined.
|
||||
|
@ -15,10 +15,10 @@ services:
|
||||
- ./startup_scripts:/opt/netbox/startup_scripts:ro
|
||||
- ./initializers:/opt/netbox/initializers:ro
|
||||
- ./configuration:/etc/netbox/config:ro
|
||||
- ./reports:/etc/netbox/reports:ro
|
||||
- netbox-nginx-config:/etc/netbox-nginx/
|
||||
- netbox-static-files:/opt/netbox/netbox/static
|
||||
- netbox-media-files:/opt/netbox/netbox/media
|
||||
- netbox-report-files:/etc/netbox/reports:ro
|
||||
netbox-worker:
|
||||
<<: *netbox
|
||||
depends_on:
|
||||
|
2
env/netbox.env
vendored
2
env/netbox.env
vendored
@ -12,7 +12,7 @@ MEDIA_ROOT=/opt/netbox/netbox/media
|
||||
NAPALM_USERNAME=
|
||||
NAPALM_PASSWORD=
|
||||
NAPALM_TIMEOUT=10
|
||||
MAX_PAGE_SIZE=0
|
||||
MAX_PAGE_SIZE=1000
|
||||
REDIS_HOST=redis
|
||||
REDIS_PASSWORD=H733Kdjndks81
|
||||
SECRET_KEY=r8OwDznj!!dci#P9ghmRfdu1Ysxm0AiPeDCQhKE+N_rClfWNj
|
||||
|
46
reports/devices.py.example
Normal file
46
reports/devices.py.example
Normal file
@ -0,0 +1,46 @@
|
||||
from dcim.constants import CONNECTION_STATUS_PLANNED, DEVICE_STATUS_ACTIVE
|
||||
from dcim.models import ConsolePort, Device, PowerPort
|
||||
from extras.reports import Report
|
||||
|
||||
|
||||
class DeviceConnectionsReport(Report):
|
||||
description = "Validate the minimum physical connections for each device"
|
||||
|
||||
def test_console_connection(self):
|
||||
|
||||
# Check that every console port for every active device has a connection defined.
|
||||
for console_port in ConsolePort.objects.select_related('device').filter(device__status=DEVICE_STATUS_ACTIVE):
|
||||
if console_port.connected_endpoint is None:
|
||||
self.log_failure(
|
||||
console_port.device,
|
||||
"No console connection defined for {}".format(console_port.name)
|
||||
)
|
||||
elif console_port.connection_status == CONNECTION_STATUS_PLANNED:
|
||||
self.log_warning(
|
||||
console_port.device,
|
||||
"Console connection for {} marked as planned".format(console_port.name)
|
||||
)
|
||||
else:
|
||||
self.log_success(console_port.device)
|
||||
|
||||
def test_power_connections(self):
|
||||
|
||||
# Check that every active device has at least two connected power supplies.
|
||||
for device in Device.objects.filter(status=DEVICE_STATUS_ACTIVE):
|
||||
connected_ports = 0
|
||||
for power_port in PowerPort.objects.filter(device=device):
|
||||
if power_port.connected_endpoint is not None:
|
||||
connected_ports += 1
|
||||
if power_port.connection_status == CONNECTION_STATUS_PLANNED:
|
||||
self.log_warning(
|
||||
device,
|
||||
"Power connection for {} marked as planned".format(power_port.name)
|
||||
)
|
||||
if connected_ports < 2:
|
||||
self.log_failure(
|
||||
device,
|
||||
"{} connected power supplies found (2 needed)".format(connected_ports)
|
||||
)
|
||||
else:
|
||||
self.log_success(device)
|
||||
|
@ -2,8 +2,14 @@ from django.contrib.auth.models import Permission, Group, User
|
||||
from users.models import Token
|
||||
|
||||
from ruamel.yaml import YAML
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
with open('/opt/netbox/initializers/users.yml', 'r') as stream:
|
||||
file = Path('/opt/netbox/initializers/users.yml')
|
||||
if not file.is_file():
|
||||
sys.exit()
|
||||
|
||||
with file.open('r') as stream:
|
||||
yaml=YAML(typ='safe')
|
||||
users = yaml.load(stream)
|
||||
|
||||
|
@ -1,7 +1,13 @@
|
||||
from django.contrib.auth.models import Permission, Group, User
|
||||
from ruamel.yaml import YAML
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
with open('/opt/netbox/initializers/groups.yml', 'r') as stream:
|
||||
file = Path('/opt/netbox/initializers/groups.yml')
|
||||
if not file.is_file():
|
||||
sys.exit()
|
||||
|
||||
with file.open('r') as stream:
|
||||
yaml=YAML(typ='safe')
|
||||
groups = yaml.load(stream)
|
||||
|
||||
|
@ -2,6 +2,8 @@ from extras.constants import CF_TYPE_TEXT, CF_TYPE_INTEGER, CF_TYPE_BOOLEAN, CF_
|
||||
from extras.models import CustomField, CustomFieldChoice
|
||||
|
||||
from ruamel.yaml import YAML
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
text_to_fields = {
|
||||
'boolean': CF_TYPE_BOOLEAN,
|
||||
@ -21,7 +23,11 @@ def get_class_for_class_path(class_path):
|
||||
clazz = getattr(module, class_name)
|
||||
return ContentType.objects.get_for_model(clazz)
|
||||
|
||||
with open('/opt/netbox/initializers/custom_fields.yml', 'r') as stream:
|
||||
file = Path('/opt/netbox/initializers/custom_fields.yml')
|
||||
if not file.is_file():
|
||||
sys.exit()
|
||||
|
||||
with file.open('r') as stream:
|
||||
yaml = YAML(typ='safe')
|
||||
customfields = yaml.load(stream)
|
||||
|
||||
|
@ -1,7 +1,13 @@
|
||||
from dcim.models import Region
|
||||
from ruamel.yaml import YAML
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
with open('/opt/netbox/initializers/regions.yml', 'r') as stream:
|
||||
file = Path('/opt/netbox/initializers/regions.yml')
|
||||
if not file.is_file():
|
||||
sys.exit()
|
||||
|
||||
with file.open('r') as stream:
|
||||
yaml=YAML(typ='safe')
|
||||
regions = yaml.load(stream)
|
||||
|
||||
|
@ -2,8 +2,14 @@ from dcim.models import Region, Site
|
||||
from extras.models import CustomField, CustomFieldValue
|
||||
from tenancy.models import Tenant
|
||||
from ruamel.yaml import YAML
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
with open('/opt/netbox/initializers/sites.yml', 'r') as stream:
|
||||
file = Path('/opt/netbox/initializers/sites.yml')
|
||||
if not file.is_file():
|
||||
sys.exit()
|
||||
|
||||
with file.open('r') as stream:
|
||||
yaml = YAML(typ='safe')
|
||||
sites = yaml.load(stream)
|
||||
|
||||
|
@ -1,7 +1,13 @@
|
||||
from dcim.models import Manufacturer
|
||||
from ruamel.yaml import YAML
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
with open('/opt/netbox/initializers/manufacturers.yml', 'r') as stream:
|
||||
file = Path('/opt/netbox/initializers/manufacturers.yml')
|
||||
if not file.is_file():
|
||||
sys.exit()
|
||||
|
||||
with file.open('r') as stream:
|
||||
yaml = YAML(typ='safe')
|
||||
manufacturers = yaml.load(stream)
|
||||
|
||||
|
@ -2,8 +2,14 @@ from dcim.models import DeviceType, Manufacturer, Region
|
||||
from tenancy.models import Tenant
|
||||
from extras.models import CustomField, CustomFieldValue
|
||||
from ruamel.yaml import YAML
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
with open('/opt/netbox/initializers/device_types.yml', 'r') as stream:
|
||||
file = Path('/opt/netbox/initializers/device_types.yml')
|
||||
if not file.is_file():
|
||||
sys.exit()
|
||||
|
||||
with file.open('r') as stream:
|
||||
yaml = YAML(typ='safe')
|
||||
device_types = yaml.load(stream)
|
||||
|
||||
@ -48,4 +54,3 @@ with open('/opt/netbox/initializers/device_types.yml', 'r') as stream:
|
||||
device_type.custom_field_values.add(custom_field_value)
|
||||
|
||||
print("🔡 Created device type", device_type.manufacturer, device_type.model)
|
||||
|
||||
|
@ -2,7 +2,14 @@ from dcim.models import RackRole
|
||||
from ruamel.yaml import YAML
|
||||
from utilities.forms import COLOR_CHOICES
|
||||
|
||||
with open('/opt/netbox/initializers/rack_roles.yml', 'r') as stream:
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
file = Path('/opt/netbox/initializers/rack_roles.yml')
|
||||
if not file.is_file():
|
||||
sys.exit()
|
||||
|
||||
with file.open('r') as stream:
|
||||
yaml=YAML(typ='safe')
|
||||
rack_roles = yaml.load(stream)
|
||||
|
||||
|
@ -3,8 +3,14 @@ from tenancy.models import Tenant
|
||||
from extras.models import CustomField, CustomFieldValue
|
||||
from dcim.constants import RACK_TYPE_CHOICES, RACK_WIDTH_CHOICES
|
||||
from ruamel.yaml import YAML
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
with open('/opt/netbox/initializers/racks.yml', 'r') as stream:
|
||||
file = Path('/opt/netbox/initializers/racks.yml')
|
||||
if not file.is_file():
|
||||
sys.exit()
|
||||
|
||||
with file.open('r') as stream:
|
||||
yaml = YAML(typ='safe')
|
||||
racks = yaml.load(stream)
|
||||
|
||||
|
@ -2,7 +2,14 @@ from dcim.models import DeviceRole
|
||||
from ruamel.yaml import YAML
|
||||
from utilities.forms import COLOR_CHOICES
|
||||
|
||||
with open('/opt/netbox/initializers/device_roles.yml', 'r') as stream:
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
file = Path('/opt/netbox/initializers/device_roles.yml')
|
||||
if not file.is_file():
|
||||
sys.exit()
|
||||
|
||||
with file.open('r') as stream:
|
||||
yaml=YAML(typ='safe')
|
||||
device_roles = yaml.load(stream)
|
||||
|
||||
|
@ -1,7 +1,14 @@
|
||||
from dcim.models import Manufacturer, Platform
|
||||
from ruamel.yaml import YAML
|
||||
|
||||
with open('/opt/netbox/initializers/platforms.yml', 'r') as stream:
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
file = Path('/opt/netbox/initializers/platforms.yml')
|
||||
if not file.is_file():
|
||||
sys.exit()
|
||||
|
||||
with file.open('r') as stream:
|
||||
yaml = YAML(typ='safe')
|
||||
platforms = yaml.load(stream)
|
||||
|
||||
|
@ -6,7 +6,14 @@ from tenancy.models import Tenant
|
||||
from extras.models import CustomField, CustomFieldValue
|
||||
from ruamel.yaml import YAML
|
||||
|
||||
with open('/opt/netbox/initializers/devices.yml', 'r') as stream:
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
file = Path('/opt/netbox/initializers/devices.yml')
|
||||
if not file.is_file():
|
||||
sys.exit()
|
||||
|
||||
with file.open('r') as stream:
|
||||
yaml = YAML(typ='safe')
|
||||
devices = yaml.load(stream)
|
||||
|
||||
|
Reference in New Issue
Block a user