Compare commits

...

413 Commits

Author SHA1 Message Date
9c66cc4c32 Merge pull request #606 from netbox-community/develop
Version 1.4.1
2021-10-14 07:45:50 +02:00
68401caf1c Merge pull request #608 from netbox-community/renovate/django-storages-1.x
Update dependency django-storages to v1.12.1
2021-10-11 22:39:39 +02:00
4f466bb5a1 Update dependency django-storages to v1.12.1 2021-10-11 19:24:42 +00:00
daaea77144 Merge pull request #589 from tobiasge/user-unit
Fix #586: Use user name instead of userid
2021-10-06 17:25:47 +02:00
faa1cb52dd Preparation for 1.4.1 2021-10-06 17:03:48 +02:00
57ac14f295 Merge pull request #605 from netbox-community/renovate/google-crc32c-1.x
Update dependency google-crc32c to v1.3.0
2021-10-06 13:58:47 +02:00
d0f4820baa Update dependency google-crc32c to v1.3.0 2021-10-06 00:32:00 +00:00
b0261e8cc6 Merge pull request #603 from cimnine/GroupBuildOutput
Group the build output in GitHub Action
2021-10-05 11:33:03 +02:00
30a7aa0e9c Group the build output in GitHub Action 2021-10-05 11:08:16 +02:00
5f0b7467d1 Merge pull request #602 from cimnine/FixEdge
Implicit openssl-dev dependency resolution (fixes alpine:edge)
2021-10-05 10:55:55 +02:00
24363b653f Remove openssl-dev from Dockerfile
It is pulled by postgresql-dev anyway
In the upcoming alpine, openssl v3 will be
the default, but postgresql-dev will still
require openssl v1.x.
This creates a conflict, which can be resolved
if postgresql-dev can choose the openssl version
it depends on.
2021-10-05 09:47:55 +02:00
21a3048b96 Merge pull request #601 from cimnine/IssueForms
Use issue template form instead of text template
2021-10-05 09:26:48 +02:00
5679ab435f Use user name instead of userid
Nginx unit needs the user and group parameter as names.
2021-09-24 08:16:07 +02:00
c9b3edd0f1 Merge pull request #587 from netbox-community/renovate/google-crc32c-1.x
Update dependency google-crc32c to v1.2.0
2021-09-21 08:22:15 +02:00
31e6e42a30 Update dependency google-crc32c to v1.2.0 2021-09-20 20:43:14 +00:00
1a868c6847 Merge pull request #583 from cimnine/NBDoVersionTag
Add project version to Docker tag
2021-09-20 13:35:24 +02:00
a9d6f1fefe Use issue template form instead of template 2021-09-17 20:10:15 +02:00
dbfcd5b58c Add project version to Docker tag 2021-09-17 19:02:18 +02:00
6a52a48b71 Merge pull request #582 from netbox-community/develop
Version 1.4.0
2021-09-17 11:35:56 +02:00
e31492a9b4 Merge branch 'release' into develop 2021-09-17 11:08:31 +02:00
f2dbc4f717 Preparation for 1.4.0 2021-09-17 10:56:50 +02:00
1d040ad64d Merge pull request #546 from tobiasge/drop-privileges
Drops privileges to user 101 and group 0
2021-09-17 10:53:08 +02:00
8703749292 Merge pull request #571 from tobiasge/house
Added container for Netbox housekeeping command
2021-09-17 10:52:28 +02:00
d432a84c42 Merge pull request #565 from mk-fg/develop
Print last line of django db connection error while waiting for db to start
2021-09-17 10:50:31 +02:00
c00492cad0 Merge pull request #579 from tobiasge/check-remote
Check if remote branch exists before checkout
2021-09-13 23:42:47 +02:00
c4d545a256 Improved check
Co-authored-by: Christian Mäder <cimnine@users.noreply.github.com>
2021-09-13 22:50:06 +02:00
d0c429c8a1 Check if remote branch exists before checkout 2021-09-13 09:27:28 +02:00
a8b6883183 Changed entrypoint to "tini". 2021-09-13 08:51:23 +02:00
5590b32c93 Merge pull request #576 from netbox-community/renovate/google-crc32c-1.x
Update dependency google-crc32c to v1.1.5
2021-09-08 08:47:17 +02:00
97e7022121 Update dependency google-crc32c to v1.1.5 2021-09-07 22:27:44 +00:00
2926d1a11d Quote variable
Co-authored-by: Christian Mäder <cimnine@users.noreply.github.com>
2021-09-07 09:47:38 +02:00
58debafa8a Added container for Netbox housekeeping command
Adds an additional container in which the new "housekeeping" command from
Netbox v3.0.0 is run.
2021-09-03 12:48:30 +02:00
e021390568 Merge pull request #568 from netbox-community/develop
Version 1.3.1
2021-09-03 10:57:05 +02:00
389e68f6ba Merge branch 'release' into develop 2021-09-03 10:34:55 +02:00
7eeb2ea7e6 Prepare version 1.3.1 2021-09-03 10:21:43 +02:00
954bddeb64 Merge pull request #570 from cimnine/FixCRC32
Build and install libcrc32c
2021-09-03 10:16:13 +02:00
9255afd060 Improves google-cloud-storage performance
And also fixes the build by providing a 'alpine version'
of the google/crc32c library, which google-crc32c and
google-cloud-storage and ultimately django-storages[google]
depend on.
2021-09-03 09:15:41 +02:00
a0a32b930e Fixed port issue with latest docker version. (#538)
Co-authored-by: Tobias Genannt <t.genannt@scanplus.de>
2021-09-03 08:03:27 +02:00
fc4b78f74a Print last line of django db connection error while waiting for db to start
Fixes #562
2021-09-02 20:22:03 +05:00
9e063a6e6f Merge pull request #560 from tobiasge/google-crc32c
Workaround for build error in google-crc32c 1.1.3
2021-08-31 16:29:40 +02:00
54823b41e1 Workaround for build error in google-crc32c 1.1.3 2021-08-31 16:04:48 +02:00
6c5434ee20 Merge pull request #557 from netbox-community/develop
Version 1.3.0: Compatibility with Netbox v3
2021-08-30 21:29:25 +02:00
8e0c795791 Prepare version 1.3.0 2021-08-30 21:07:01 +02:00
1fd8d105e6 Merge pull request #543 from tobiasge/prepare-3.0.0
Prepare for Netbox v3.0.0
2021-08-30 18:05:54 +02:00
fe4df4f70a Merge pull request #556 from netbox-community/disableDependencyDashboard 2021-08-30 12:54:31 +02:00
650e62f44f Disable Renovate's "Dependency Dashboard" 2021-08-30 12:31:36 +02:00
f8451b0c0a Merge pull request #555 from netbox-community/renovate/ruamel.yaml-0.x
Update dependency ruamel.yaml to v0.17.16
2021-08-29 15:51:02 +02:00
3af075e039 Update dependency ruamel.yaml to v0.17.16 2021-08-29 13:05:16 +00:00
26d45b1e85 Merge pull request #554 from netbox-community/renovate/ruamel.yaml-0.x
Update dependency ruamel.yaml to v0.17.14
2021-08-26 15:07:24 +02:00
9b6c476bf9 Update dependency ruamel.yaml to v0.17.14 2021-08-25 20:34:39 +00:00
c5a1557800 Removed deprecated settings 2021-08-21 18:22:24 +02:00
9d476fa9af Build documentation files in the image 2021-08-21 18:22:24 +02:00
9142aaf78e django-cacheops has been removed from Netbox 3.0.0 2021-08-21 18:22:24 +02:00
b258b6578c Merge pull request #552 from netbox-community/renovate/ruamel.yaml-0.x 2021-08-21 18:03:42 +02:00
289540f576 Update dependency ruamel.yaml to v0.17.13 2021-08-21 14:53:54 +00:00
26a3f5fcc0 Merge pull request #551 from netbox-community/renovate/ruamel.yaml-0.x
Update dependency ruamel.yaml to v0.17.11
2021-08-19 11:27:59 +02:00
18ea220102 Update dependency ruamel.yaml to v0.17.11 2021-08-19 06:45:17 +00:00
03a1793208 Drops privileges to user 101 and group 0
When the container is started as root the default was to drop privileges to "unit:unit". This caused some problems with temporary files. Now the privileges are drop to "101:0".
When the container is started as a normal user unit prints a warning that changing the user and group is not possible. This warning is safe to ignore.
2021-07-30 21:42:05 +02:00
3c01985e20 Merge pull request #542 from netbox-community/renovate/django-auth-ldap-3.x
Update dependency django-auth-ldap to v3
2021-07-30 11:16:28 +02:00
275d2673b4 Update dependency django-auth-ldap to v3 2021-07-19 07:56:47 +00:00
746aa9b4a6 Merge pull request #534 from tobiasge/alpine-update
Alpine update to 3.14
2021-07-08 10:41:22 +02:00
c13bec47b8 Merge pull request #537 from insidieux/disable-server-side-cursors-option
Disable server side cursors option
2021-07-07 09:51:05 +02:00
9953d11fd8 Merge pull request #536 from netbox-community/renovate/ruamel.yaml-0.x
Update dependency ruamel.yaml to v0.17.10
2021-07-07 09:47:56 +02:00
b2ee468871 Alpine update to 3.14 2021-07-07 09:44:21 +02:00
dd41d09b43 Add possibility to disable server side cursors 2021-06-24 18:21:08 +03:00
abfa6c989f Update dependency ruamel.yaml to v0.17.10 2021-06-24 09:38:10 +00:00
bb3d964b89 Merge pull request #533 from netbox-community/renovate/napalm-3.x
Update dependency napalm to v3.3.1
2021-06-23 21:47:32 +02:00
6bbc7a3a84 Update dependency napalm to v3.3.1 2021-06-18 12:29:27 +00:00
17b1a5022d Merge pull request #531 from netbox-community/renovate/ruamel.yaml-0.x
Update dependency ruamel.yaml to v0.17.9
2021-06-10 17:19:06 +02:00
e38d646e8e Update dependency ruamel.yaml to v0.17.9 2021-06-10 06:57:09 +00:00
bb298e7a01 Merge pull request #530 from netbox-community/renovate/ruamel.yaml-0.x 2021-06-09 20:01:41 +02:00
98840382b9 Update dependency ruamel.yaml to v0.17.8 2021-06-09 13:53:48 +00:00
b8ff0a1d43 Merge pull request #524 from jlemesh/fix/initialize_tenants_before_sites
Initialize tenants before sites
2021-06-03 11:29:53 +02:00
15b097bd3e Add second tenant with group to site 2021-06-01 14:22:08 +03:00
e0b34b8c67 Merge pull request #527 from netbox-community/renovate/ruamel.yaml-0.x
Update dependency ruamel.yaml to v0.17.7
2021-06-01 09:45:02 +02:00
3aad44d68c Update dependency ruamel.yaml to v0.17.7 2021-05-31 15:28:52 +00:00
6658d069fb Merge pull request #520 from cimnine/PinNetboxMinor 2021-05-31 11:26:51 +02:00
52f097d4a2 Merge pull request #525 from netbox-community/renovate/ruamel.yaml-0.x 2021-05-31 11:25:56 +02:00
f4e9ebcfb5 Update dependency ruamel.yaml to v0.17.6 2021-05-31 08:58:27 +00:00
057728b774 Allow sites to be initialized with tenants 2021-05-28 11:26:34 +03:00
5b618851c0 Pin the NetBox Docker version in the docker-compose.yml file 2021-05-26 19:05:37 +02:00
9f531ce0f7 Merge pull request #518 from netbox-community/renovate/github-super-linter-4.x 2021-05-26 16:46:24 +02:00
dd732d7bc2 Update github/super-linter action to v4 2021-05-25 20:35:56 +00:00
05bb40adb1 Merge pull request #511 from netbox-community/renovate/napalm-3.x
Update dependency napalm to v3.3.0
2021-05-19 09:02:18 +02:00
240326ef37 Update dependency napalm to v3.3.0 2021-05-18 13:30:10 +00:00
c49fa313ed Merge pull request #514 from tobiasge/ttf-ubuntu
Remove 'ttf-ubuntu-font-family' from image
2021-05-18 14:23:32 +02:00
ff6bd95fce Merge pull request #513 from tobiasge/remove-secret-initializers
Secrets are removed in Netbox 2.12
2021-05-18 14:23:07 +02:00
0def662e53 Merge pull request #508 from netbox-community/renovate/postgres-13.x
Update postgres Docker tag to v13
2021-05-18 14:22:45 +02:00
49b7c267b9 Update postgres Docker tag to v13 2021-05-18 08:03:10 +00:00
02f30f3a68 'ttf-ubuntu-font-family' was remove from Alpine 2021-05-18 09:34:44 +02:00
e2cc9386fb Secrets are removed in Netbox 2.12 2021-05-18 09:32:48 +02:00
43b8b36951 Merge pull request #507 from tobiasge/run-update-when-needed
Optimise migrations on startup
2021-05-18 08:55:31 +02:00
4d320f34d5 Optimise migrations on startup
The migrations are only started if there are some that have not been
applied. Additionally the maintenace task needed after an update are
now run after the migrations
2021-05-05 11:42:25 +02:00
676ca798cd Merge pull request #493 from netbox-community/develop
Release 1.2.0
2021-04-27 09:47:38 +02:00
60428d5639 Merge pull request #498 from tobiasge/build-feature-branch
Build feature branch
2021-04-27 09:16:06 +02:00
fd55ec220c Merge pull request #497 from ryanmerolle/startup-scripts-2.10+
user, group, & permissions fix
2021-04-27 09:05:14 +02:00
73b07a7181 Merge pull request #500 from ryanmerolle/python-formatting
Python formatting Startup Scripts
2021-04-26 16:32:49 +02:00
1f3d9463f9 apply black formating to all startup_scripts 2021-04-26 10:26:10 -04:00
8678ad92ce update permission user & group lookup as suggested 2021-04-26 09:17:25 -04:00
5b34df1471 Build feature branch
The branch for the next version of Netbox is now called "feature".
2021-04-26 09:44:52 +02:00
3d063a4b35 Merge branch 'ryanmerolle-plugins-and-logging' into develop 2021-04-26 08:55:41 +02:00
f924e76adf Formatting 2021-04-26 08:55:22 +02:00
604ff3b76d Merge branch 'plugins-and-logging' of https://github.com/ryanmerolle/netbox-docker into ryanmerolle-plugins-and-logging 2021-04-26 08:54:31 +02:00
96545135cb remove example evn var for logging 2021-04-25 16:38:03 -04:00
474ca9e78f fully working object permissions 2021-04-25 16:31:50 -04:00
12401f2a3f correct black formatting for object_permissions.py 2021-04-25 12:13:27 -04:00
528bc17eb8 correct flake8 in object_permissions.py 2021-04-25 11:59:13 -04:00
4e31218ce6 update object permission conditionals 2021-04-25 11:15:46 -04:00
d1b70ba2d4 Merge pull request #499 from ryanmerolle/ldap-example-var-name 2021-04-24 23:58:30 +02:00
ff0bc9757a correct ldap example var name case 2021-04-24 10:57:15 -04:00
a1e0c52825 revert startup scripts to use key for object name 2021-04-24 10:41:06 -04:00
45889c3811 commented out the logging 2021-04-23 22:38:38 -04:00
71d8ac10ac correct issues with users.yml spacing 2021-04-21 12:59:30 -04:00
744ed91e2a permissions script cleanup 2021-04-21 12:33:35 -04:00
b1bcfcbc4e fix isort on groups & permissions scripts 2021-04-21 08:27:20 -04:00
a7a5d13637 updated given linting feedback 2021-04-20 18:05:47 -04:00
5d4ecb7f9e user, group, & permissions fix 2021-04-20 17:47:49 -04:00
69dd87689c switch plugin example to netbox_bgp 2021-04-20 07:55:12 -04:00
9fab9a3434 mention plugin wiki page in plugins.py comment 2021-04-20 07:52:08 -04:00
b69a97d2ca add LOGLEVEL into netbox.env 2021-04-20 07:48:41 -04:00
8176ef8499 Add expample logging configuration 2021-04-20 07:46:39 -04:00
eb5cc88b25 Add expample plugin configuration 2021-04-20 07:46:29 -04:00
f2731d3fe6 Merge pull request #448 from ryanmerolle/develop
AUTH_LDAP_MIRROR_GROUPS ldap_config tweak
2021-04-20 10:15:52 +02:00
6f4d025cb7 backed out ldap_config changes 2021-04-20 03:38:20 -04:00
222ede2c4b enahance ldap extra.py with more examples 2021-04-20 03:35:57 -04:00
5304c8f901 Merge pull request #483 from netbox-community/renovate/django-auth-ldap-2.x
Update dependency django-auth-ldap to v2.4.0
2021-04-20 09:24:20 +02:00
28a26288c9 Merge pull request #3 from netbox-community/develop
pull in develop changes
2021-04-19 22:25:55 -04:00
53d759e263 Update dependency django-auth-ldap to v2.4.0 2021-04-19 13:13:02 +00:00
6879412e2b Merge pull request #495 from tobiasge/no-random-port
Don't publish Netbox on random port
2021-04-19 11:33:23 +02:00
a89d2e035c Don't publish Netbox on random port 2021-04-17 10:16:40 +02:00
d5c92e9a7d Preparation for 1.2.0 2021-04-16 20:27:33 +02:00
c7df608696 Merge pull request #485 from tobiasge/prepare-2.11
Initializer updates for Netbox 2.11
2021-04-16 20:00:35 +02:00
eee07f703a Merge pull request #492 from jhujhiti/upstreaming
Fix quoting of exec argument in the entrypoint script
2021-04-16 08:42:15 +02:00
6e7d5a6f59 Fix quoting of exec argument in the entrypoint script 2021-04-15 17:36:14 -04:00
752f592e58 Fixed Python f-string
Co-authored-by: Christian Mäder <cimnine@users.noreply.github.com>
2021-04-13 15:50:23 +02:00
f637de88f0 Improved error logging 2021-04-13 14:38:52 +02:00
a5da38203f Merge pull request #482 from Daimler/custom-link-error-fix
Fixes #480: Custom Links initialiser breaks if content_type is invalid
2021-04-13 09:33:41 +02:00
14c0d17704 Merge pull request #486 from netbox-community/renovate/ruamel.yaml-0.x
Update dependency ruamel.yaml to v0.17.4
2021-04-12 17:12:05 +02:00
a572d5f5de Update dependency ruamel.yaml to v0.17.4 2021-04-07 20:52:56 +00:00
3673196c16 Fields in Custom links have been renamed 2021-04-07 15:19:14 +02:00
9874cef369 VLAN Groups can be scoped to multiple types 2021-04-07 15:18:33 +02:00
1c4b6741ac Fixed isort issues 2021-04-07 11:01:01 +02:00
b18e4aaf92 Fix super-linter on PRs
See: https://github.com/github/super-linter#example-connecting-github-action-workflow
2021-04-07 10:57:14 +02:00
45824ba4f3 Devices can be added to locations 2021-04-07 09:57:59 +02:00
5944086435 Rack groups have been renamed to locations 2021-04-07 09:40:58 +02:00
a2e33c166d Fix link name reference if content type is invalid
Currently, the name of a custom link is referenced
as if it is an object attribute which causes a break
due to it actually being a dictionary.

This minor change means that the startup script won't
*ahem* fail upon failing :)

Signed-Off-by: Marcus Crane <marcus.crane@daimler.com>
2021-04-01 18:48:13 +13:00
9ab202f921 Merge pull request #479 from netbox-community/renovate/ruamel.yaml-0.x 2021-03-29 19:25:17 +02:00
cca79b5dbd Update dependency ruamel.yaml to v0.17.2 2021-03-29 17:03:30 +00:00
61eecdd343 Merge pull request #477 from netbox-community/renovate/ruamel.yaml-0.x
Update dependency ruamel.yaml to v0.17.0
2021-03-26 18:16:33 +01:00
ce6fe5cb83 Update dependency ruamel.yaml to v0.17.0 2021-03-26 11:37:33 +00:00
8f119ede13 Merge pull request #469 from cimnine/Sponsoring
Sponsor Message
2021-03-12 18:31:53 +01:00
edb61f3d90 Sponsor Message 2021-03-11 19:06:49 +01:00
cb5ffa0354 Merge pull request #460 from netbox-community/renovate/ruamel.yaml-0.x
Update dependency ruamel.yaml to v0.16.13
2021-03-05 15:31:33 +01:00
ff1eed3cf0 Update dependency ruamel.yaml to v0.16.13 2021-03-05 09:58:42 +00:00
53d593de25 Preparation for 1.1.0 2021-03-04 12:07:21 +01:00
8111da308b Merge pull request #455 from cimnine/NewSlack
New Slack
2021-03-04 12:04:02 +01:00
0125ab4849 New Slack and wording improvements in templates 2021-03-04 09:59:05 +01:00
ad0c04985b Merge pull request #452 from cimnine/ReleaseScript
Release Script
2021-03-01 08:52:17 +01:00
793393fe0f Fix DEFAULT_REPO in release.sh 2021-03-01 08:27:24 +01:00
59995a8719 Add release script 2021-02-27 15:05:05 +01:00
f19d650412 Merge pull request #1 from netbox-community/develop
Merge upstream changes
2021-02-25 12:14:16 -05:00
6cd156f7d5 Merge pull request #450 from netbox-community/FilterMainConfig
Fix loading main_config again during discovery of dynamic configurations
2021-02-24 08:21:18 +01:00
95976f4cf4 Don't load main config twice
Before, the main_config (e.g. 'configuration.py' or 'ldap_config.py') were loaded twice.
The first load was hard-coded and correct.
The second load was during the discovery phase for dynamic configurations.
This has now been fixed. During the discovery for dynamic configurations,
the main_config file is now excluded.

Thanks @tobiasge for discovering this bug.
2021-02-23 22:50:16 +01:00
0dec4d8df4 Add extra.py example for ldap config 2021-02-22 16:00:08 -05:00
22186b267d do not set AUTH_LDAP_MIRROR_GROUPS if not defined 2021-02-22 15:55:40 -05:00
020e0adeb4 update .gitignore to keep extra.py in ldap config 2021-02-22 15:53:02 -05:00
009eb1fc6d Merge pull request #444 from netbox-community/RemoveMicroBadger
Remove MicroBadger Badges
2021-02-19 08:52:06 +01:00
989c250a82 Remove MicroBadger Badges
The service will shutdown in 2021:
https://microbadger.com/shutdown
2021-02-18 16:57:51 +01:00
3ee231bdd8 Merge pull request #438 from netbox-community/renovate/django-auth-ldap-2.x
Update dependency django-auth-ldap to v2.3.0
2021-02-16 08:54:57 +01:00
3338cdc9d7 Update dependency django-auth-ldap to v2.3.0 2021-02-16 00:06:58 +00:00
c80fb19507 Merge pull request #432 from netbox-community/develop
Version 1.0.2
2021-02-10 13:15:49 +01:00
74543ec272 Preparation for 1.0.2 2021-02-10 12:47:54 +01:00
9ccf0ac921 Merge pull request #431 from netbox-community/VersionsToWiki
Move Documentation about Version to Wiki
2021-02-10 12:47:09 +01:00
8aed79363a Move Documentation about Version to Wiki
See https://github.com/netbox-community/netbox-docker/wiki/Version.
2021-02-10 12:45:37 +01:00
f7337ed1e9 Merge pull request #427 from netbox-community/AddEditorconfig
Introduce Linting-Step in Build
2021-02-10 12:35:48 +01:00
4c8435e874 fixup! Lint the syntax of changes 2021-02-10 10:48:45 +01:00
a37f1592fc Sort env files 2021-02-08 18:56:30 +01:00
04ac3d5f4b Format shell scripts with shfmt 2021-02-08 18:56:30 +01:00
c6df6a040a Fix shellcheck complaint 2021-02-08 18:56:30 +01:00
28e4ae44fb Lint the syntax of changes 2021-02-08 18:56:30 +01:00
493fc60401 Use black as formatter for python files 2021-02-08 18:24:29 +01:00
0d25aff744 Add editorconfig 2021-02-08 18:24:29 +01:00
f33c647f24 Merge branch 'MajesticFalcon-feature' into develop 2021-02-08 10:37:04 +01:00
16ae063321 Adjust to repository standards 2021-02-08 10:36:50 +01:00
e4e2c788a9 Update 290_webhooks.py
Move to a more standard method of object handling
2021-02-08 10:09:55 +01:00
2e5d84612d Update initializers/custom_links.yml
Co-authored-by: Christian Mäder <cimnine@users.noreply.github.com>
2021-02-08 10:09:55 +01:00
744f0e57ad Update initializers/webhooks.yml
Co-authored-by: Christian Mäder <cimnine@users.noreply.github.com>
2021-02-08 10:09:55 +01:00
52c51b5f99 Update initializers/custom_links.yml
Co-authored-by: Christian Mäder <cimnine@users.noreply.github.com>
2021-02-08 10:09:55 +01:00
f88f4e1579 Update startup_scripts/290_webhooks.py
Co-authored-by: Christian Mäder <cimnine@users.noreply.github.com>
2021-02-08 10:09:55 +01:00
95f4d7856a Update startup_scripts/280_custom_links.py
Co-authored-by: Christian Mäder <cimnine@users.noreply.github.com>
2021-02-08 10:09:55 +01:00
07a0b1d7ef Update startup_scripts/280_custom_links.py
Co-authored-by: Christian Mäder <cimnine@users.noreply.github.com>
2021-02-08 10:09:55 +01:00
fe811f37bd replace loop with list comprehension 2021-02-08 10:09:55 +01:00
8321449cc0 add icons to help messages 2021-02-08 10:09:55 +01:00
618feff63a add error handling for webhook and custom links. fix initializer comments 2021-02-08 10:09:55 +01:00
a3cf645dc5 fix webhook initializer yaml and webhook startup script to work with latest netbox release 2021-02-08 10:09:55 +01:00
d0c786e831 Update webhooks.yml
fix comment
2021-02-08 10:09:54 +01:00
7112a88359 add webhook initializer 2021-02-08 10:09:54 +01:00
187ae4b2a1 add custom link initializers 2021-02-08 10:09:54 +01:00
3a0b3fe133 Merge pull request #426 from netbox-community/FixBuild
Dependencies to build 'cryptography' Python package
2021-02-08 09:55:12 +01:00
5343eaae65 Fix building cryptography pip 2021-02-08 09:03:33 +01:00
83a0d5d12f Merge pull request #425 from ypid/fix/branding
NetBox should always be referred to as NetBox
2021-02-04 22:17:29 +01:00
ee40e339c8 NetBox should always be referred to as NetBox
Fix all instances of "Netbox".

```Shell
git ls-files -z . | xargs --null -I '{}' find './{}' -type f -print0 | xargs --null sed --in-place --regexp-extended 's#Netbox#NetBox#g;'
```

Ref: https://netbox.readthedocs.io/en/stable/development/style-guide/#branding
2021-02-04 21:48:08 +01:00
04e0b3d3ca Merge pull request #421 from tobiasge/django-storages-backends
Provide backends for django-storages in our images
2021-02-04 19:36:21 +01:00
fa70e0b761 Merge pull request #423 from netbox-community/ImprovedIssueTemplate
Change the phrasing of the alternative issue options
2021-02-03 21:59:42 +01:00
88b35eb48e Change the phrasing of the alternative options 2021-02-03 21:46:11 +01:00
5644254113 Provide backends for django-storages in our images 2021-02-03 20:01:36 +01:00
4dd7a51c7d Merge pull request #419 from netbox-community/develop
Version 1.0.1
2021-02-03 15:30:31 +01:00
c7e259e116 Merge branch 'release' into develop 2021-02-03 15:01:11 +01:00
3cbe07cb0e Preparation for 1.0.1 2021-02-03 14:52:21 +01:00
70b38d52b9 Merge pull request #413 from tobiasge/fix-412
Is greater than or equal to is "-ge" and not "-gte".
2021-01-31 21:38:49 +01:00
a21d146b60 Is greater than or equal to is "-ge" and not "-gte". 2021-01-31 16:39:45 +01:00
6e7a64bd81 Merge pull request #410 from netbox-community/renovate/django-storages-1.x
Update dependency django-storages to v1.11.1
2021-01-31 16:07:40 +01:00
f8360ba6aa Update dependency django-storages to v1.11.1 2021-01-31 14:42:24 +00:00
bab8373f66 Merge pull request #411 from netbox-community/renovate/actions-checkout-2.x
Update actions/checkout action to v2
2021-01-31 15:41:41 +01:00
ad93c99f46 Update actions/checkout action to v2 2021-01-31 11:55:20 +00:00
ed6256172f Merge pull request #394 from netbox-community/develop
Prepare version 1.0.0
2021-01-29 10:48:29 +01:00
5109e340ca Prepare for Version 1.0.0 2021-01-28 10:22:48 +01:00
62d31fda58 Merge pull request #398 from netbox-community/updateYAML
Update of ruamel.yaml
2021-01-20 16:08:03 +01:00
ed141c8a4e Merge pull request #399 from tobiasge/prevent-edge-from-failing
Prevent "alpine:edge" from failling the workflow
2021-01-20 13:14:09 +01:00
4d8d02e35a Merge pull request #397 from netbox-community/SkipStartupScriptsForUnitTests
Skip Startup Scripts in Unit Tests
2021-01-20 13:08:25 +01:00
96132e1dcc Prevent "alpine:edge" from failling the workflow
Alpine is releases a new version once a year. Therefore our workflow
runs don't need to be marked as failed when run on alpine:edge
2021-01-20 10:43:07 +01:00
896651ed97 Update of ruamel.yaml 2021-01-20 09:50:00 +01:00
f810d0342d Skip Startup Scripts in Unit Tests 2021-01-20 09:36:13 +01:00
323e18278a Merge branch 'MajesticFalcon-iss365' into develop 2021-01-20 09:03:31 +01:00
a0f7737916 rebase and fix script order 2021-01-20 09:03:04 +01:00
7f8cc76af6 address issue #365 2021-01-20 09:03:04 +01:00
21bd7f426c Merge pull request #393 from MajesticFalcon/vm_init_bug
Bugfix - Allow primary device IP without virtual machine initialization
2021-01-20 08:54:13 +01:00
3758bc805a Merge pull request #396 from netbox-community/renovate/configure
Configure Renovate
2021-01-20 08:26:35 +01:00
72859ca71a Configure Renovate 2021-01-20 08:24:47 +01:00
0022392f03 Add renovate.json 2021-01-20 08:24:28 +01:00
385c66e30d Update startup_scripts/270_primary_ips.py
Ah, of course.. I would agree. :)

Co-authored-by: Christian Mäder <cimnine@users.noreply.github.com>
2021-01-19 12:54:52 -06:00
65023a7dd4 Merge pull request #384 from ryanmerolle/develop
Expand Initialization Support
2021-01-19 18:59:49 +01:00
426adb2333 Preparation for 0.28.0 2021-01-18 08:38:44 +01:00
584566b0f0 allow simultaneous virtual machine and device primary ip initialization 2021-01-15 23:44:10 -06:00
5399f8c890 Update 270_primary_ips.py
fix issue where user has no virtual machines defined, but startup script still tries to iterate over empty file.
2021-01-15 23:42:26 -06:00
2372c1eeff remove site from power_feeds 2021-01-15 15:02:01 -05:00
788aeacd9b correct missing required sites in power_feeds 2021-01-15 14:25:42 -05:00
00fa1793d0 update services examples 2021-01-15 14:14:07 -05:00
4260e9b864 more comment corrections 2021-01-15 09:26:09 -05:00
02713e1465 showcase protcol options in services initializer 2021-01-15 09:23:21 -05:00
728a16c93d correct initializers commenting 2021-01-15 09:19:21 -05:00
742560c571 Merge pull request #361 from tobiasge/nginx-unit
Use Nginx Unit to serve the application
2021-01-15 13:33:55 +01:00
d273391773 Gunicorn is replaced with nginx-unit
We now serve Netbox with an nginx-unit instance instead of Gunicorn.
This allows us to get rid of the extra Nginx container because Unit is
also serving the static files. The static files are now collected at container
buildtime instead of every startup.
2021-01-15 09:22:22 +01:00
380cb77080 Merge pull request #386 from netbox-community/LinksForIssues
Links for issues
2021-01-12 11:08:50 +01:00
92b6608403 Create config.yml for ISSUE_TEMPLATE
This commit adds links to the _New Issue_ section of Github.
The intention is to provide more hints where to get help and
further reduce the amount of Github issues that can not be
acted upon.
2021-01-07 14:08:06 +01:00
94509f86d7 added route_targets startup_script 2020-12-30 19:11:09 -05:00
818266ace1 added services startup_script 2020-12-30 19:10:46 -05:00
dfb0327340 Added power startup_scripts 2020-12-30 19:10:30 -05:00
e3946af27c added tenant to example aggregates.yml 2020-12-30 19:09:27 -05:00
8d8c58df54 optional assoc to cluster & circuit startup_script 2020-12-30 19:09:08 -05:00
cbaaffc589 add extra space after ▶️ to remove text overlap 2020-12-30 18:23:12 -05:00
0f1cc9eea0 add tenant to aggregate startup_script 2020-12-30 18:22:12 -05:00
90018fc6d7 add cluster group startup script 2020-12-29 22:10:19 -05:00
621fa12934 comment out secret roles 2020-12-29 22:09:31 -05:00
3094665092 add tags & secret roles 2020-12-29 19:36:58 -05:00
31f52041f8 correct circuit model startup scripts 2020-12-29 18:27:41 -05:00
6ab38472be circuits model startup_scripts 2020-12-29 16:24:16 -05:00
aa4d630a0f Merge pull request #371 from netbox-community/develop
Version 0.27.0
2020-12-15 09:53:01 +01:00
4e8588accf Preparation for 0.27.0 2020-12-15 08:59:42 +01:00
07469b2b72 Merge pull request #370 from netbox-community/GettingHelp
Introducing our Github Community
2020-12-15 08:54:30 +01:00
a7c1d9f550 Merge pull request #369 from netbox-community/AddQuayIo
Add quay.io as fallback registry
2020-12-15 08:53:35 +01:00
5605b9b218 Introduce our Github Community 2020-12-15 00:50:02 +01:00
b92c652d99 Add quay.io as fallback registry 2020-12-15 00:41:01 +01:00
d77b3c1222 Merge pull request #342 from netbox-community/Fix337
Prepare for Netbox v2.10.x
2020-12-14 22:51:24 +01:00
e383fd42bd Fix custom fields initializer 2020-12-14 22:11:01 +01:00
234baa40a5 Remove redundant assignment in for loop 2020-12-14 20:58:50 +01:00
77d3dcded0 Fix leftover from testing in test.sh 2020-12-14 20:58:50 +01:00
349e269356 Remove the legacy select_field from the samples
This was only used for testing.
2020-12-14 20:58:50 +01:00
5c9bea8b50 Update Custom Field logic for Netbox v2.10.x 2020-12-14 20:58:43 +01:00
036f94a450 Simplify test script for manual tests 2020-12-14 20:54:19 +01:00
9d51762161 Merge pull request #359 from devon-mar/login-timeout-fix
Fix TypeError when using LOGIN_TIMEOUT
2020-11-13 15:36:16 +01:00
4276c941eb Change LOGIN_TIMEOUT default to int
Co-authored-by: Christian Mäder <cimnine@users.noreply.github.com>
2020-11-03 14:57:12 -08:00
3cbdf26773 Merge pull request #356 from timrabl/enviroment-changes
Enviroment changes
2020-11-03 18:44:44 +01:00
fbfce46ce5 Fix TypeError when using LOGIN_TIMEOUT 2020-11-02 22:39:06 -08:00
255889288c Rename SESSION_FILE_PATH default environment variable in configration.py 2020-10-30 23:06:42 +01:00
c068db1751 Merge pull request #348 from tobiasge/python-upgrade
Upgrade Python image to 3.9-alpine
2020-10-29 17:12:24 +01:00
378784a19c Merge pull request #328 from pruiz/pruiz/make-ldap-group-settings-optional
Allow disabling LDAP-group related settings when AUTH_LDAP_*_GROUP environment variables are not defined
2020-10-29 16:24:17 +01:00
dcb3b5495d Remove now unneeded os. prefix from environ calls. 2020-10-29 14:57:34 +01:00
60f4e8b2ed Allow disabling LDAP-group related settings when AUTH_LDAP_*_GROUP environment variables are not defined. This is required in order to work with Google's Secure LDAP, due to some limitations on django-auth-ldap plugin (see: https://github.com/django-auth-ldap/django-auth-ldap/issues/201) 2020-10-29 14:56:35 +01:00
a51ad36801 Merge pull request #355 from netbox-community/develop
Version 0.26.2
2020-10-27 16:41:48 +01:00
953ee09b0c Preparation for 0.26.2 2020-10-27 16:24:10 +01:00
94047d60ed Merge branch 'release' into develop 2020-10-27 16:22:59 +01:00
80bfd98000 Merge pull request #354 from comphilip/release
Fix ldap configuration in /etc/netbox/config/ldap/*.py not loaded
2020-10-27 16:11:55 +01:00
7694fd320a use extend method for simplification.
Co-authored-by: Christian Mäder <cimnine@users.noreply.github.com>
2020-10-27 21:12:26 +08:00
097bea8702 Merge pull request #353 from netbox-community/develop
Version 0.26.1
2020-10-27 12:32:43 +01:00
a3c21ae0ac Fix ldap configuration in /etc/netbox/config/ldap/*.py not loaded 2020-10-27 19:27:51 +08:00
074960327b Preparation for 0.26.1 2020-10-27 10:30:55 +01:00
e1462d9ca4 Merge pull request #351 from netbox-community/RevertPrometheusPreps
Revert changes to 'gunicorn_config.py'
2020-10-27 10:29:07 +01:00
a5aa1bfd3b Revert changes to 'gunicorn_config.py' 2020-10-27 09:31:47 +01:00
cb02450783 Merge pull request #350 from comphilip/release
Fix "'NoneType' object has no attribute 'lower'" when no AUTH_LDAP_MI…
2020-10-27 09:29:34 +01:00
8307560c88 Fix "'NoneType' object has no attribute 'lower'" when no AUTH_LDAP_MIRROR_GROUPS defined 2020-10-27 15:51:12 +08:00
43aea3a1dd Merge pull request #349 from netbox-community/develop
Version 0.26.0
2020-10-26 16:55:21 +01:00
bb2ac7bd71 Disable tests for Python 3.10-rc
Some of the dependencies of Netbox can't be built with Python 3.10.
2020-10-26 16:47:38 +01:00
30a98c5009 Upgrade Python image to 3.9-alpine
Upgrade the default base image to Python 3.9 and start testing on Python 3.10-rc
2020-10-26 16:25:38 +01:00
a52a5547be Preparation for 0.26.0 2020-10-26 16:21:47 +01:00
120a605d35 Merge pull request #347 from tobiasge/python-final
Use release version of Python 3.9 in tests
2020-10-26 16:06:12 +01:00
e51f9cbc18 Merge pull request #344 from netbox-community/Prometheus
Prepare for Monitoring with Prometheus
2020-10-26 15:58:52 +01:00
071401b771 Merge pull request #346 from tobiasge/fix-action-warning
Fix warning in Github Actions
2020-10-26 15:48:50 +01:00
911488242f Use release version of Python 3.9 in tests 2020-10-26 15:42:31 +01:00
5512ea68b3 Ignore prometheus.yml 2020-10-26 15:40:22 +01:00
7d055fbcaf Mention monitoring in README 2020-10-26 15:29:41 +01:00
3d244a1946 Fix warning in Github Actions
Our build script is using "set-env" which has been deprecated by Github.
See this bolg entry:
https://github.blog/changelog/2020-10-01-github-actions-deprecating-set-env-and-add-path-commands/
2020-10-26 15:23:17 +01:00
e18d6c53b3 Revert most changes 2020-10-26 15:22:56 +01:00
48decdeb0e Monitoring parts to docker-compose.monitorin.yml 2020-10-26 15:22:56 +01:00
6ac65a64c9 Fix test 2020-10-26 15:22:56 +01:00
f46d8a7782 Adds Prometheus/Grafana monitoring infrastructure 2020-10-26 15:22:52 +01:00
64d82b5e42 Merge pull request #343 from netbox-community/DynamicVariables
Dynamic Configuration
2020-10-26 15:21:42 +01:00
58050e5287 Merge core functionality into configuration.py
Which is the file `docker/configuration.docker.py` in our repo.
The common code is then imported by `docker/ldap_config.docker.py`.
2020-10-26 14:43:11 +01:00
2dba2b8811 Fix default for secret_key in configuration.py 2020-10-20 21:45:37 +02:00
d0c7b87925 Improve order in configuration.py 2020-10-20 21:40:14 +02:00
ec3fd8a790 Revert accidential change to _read_secret order 2020-10-20 21:36:40 +02:00
75554ef5b4 Consistency in namespace name 2020-10-20 21:29:08 +02:00
dad0608834 Rename example.py to extra.py
And add some comments to the the file that hopefully guide the user.
2020-10-20 20:51:43 +02:00
dc77f1a0b1 Ignore non-default configuration files 2020-10-20 20:51:43 +02:00
16b567939c Dot character has special meaning in module names
Therefore we esacpe it using the underscore character.
2020-10-20 20:51:43 +02:00
20820e10c2 Optimize Imports in ldap_config.py 2020-10-20 20:51:35 +02:00
553c8ea470 Update configuration.py 2020-10-20 20:49:59 +02:00
811618b359 Lower gunicorn default loglevel 2020-10-20 20:46:43 +02:00
7429835970 Sample dynamic configuration file 2020-10-20 20:46:43 +02:00
43c05d816d Dynamically load configuration files 2020-10-20 20:46:43 +02:00
fd3d3d11d1 Tiny refactoring 2020-10-20 20:46:43 +02:00
121c3f800d Merge branch 'eemil-develop' into develop 2020-10-20 19:23:11 +02:00
9287995df4 Update to latest configuration 2020-10-20 19:22:52 +02:00
85fbb0af70 fix typo
Co-authored-by: Christian Mäder <cimnine@users.noreply.github.com>
2020-10-20 19:20:29 +02:00
6bada6660a Prefer secret to env variable if both are configured 2020-10-20 19:20:29 +02:00
df3ab69c0f Merge pull request #310 from shuichiro-makigaki/add-remote-auth
Add REMOTE_AUTH_* configs
2020-10-20 09:02:27 +02:00
38f4474b14 Add REMOTE_AUTH_* support 2020-10-20 11:11:32 +09:00
51331621ab Merge pull request #345 from netbox-community/enable_sponsoring
Enable Sponsoring Button
2020-10-19 17:13:34 +02:00
156681f68d Merge pull request #327 from madnutter56/mirror_ldap_groups
add option to mirror ldap groups into netbox
2020-10-19 17:06:51 +02:00
9f4a9f528c add option to mirror ldap groups into netbox
this commit allows ldap assigned groups to be mirrored into
netbox users.

The default is None as this is not the primary way to do this
change.
2020-10-19 07:50:33 -07:00
cad803ed31 Create FUNDING.yml to enable sponsoring 2020-10-19 16:50:04 +02:00
9efaccadf7 Merge branch 'Tassatux-develop' into develop 2020-10-18 11:41:03 +02:00
f553d17655 Change log message 2020-10-18 11:31:48 +02:00
2b361c4541 Merge branch 'develop' of https://github.com/Tassatux/netbox-docker into Tassatux-develop 2020-10-18 11:24:51 +02:00
c744603a85 Merge pull request #336 from ericgeldmacher/develop
Fix sites.yml initializer
2020-09-21 21:04:39 +02:00
1133ef50de Fix sites.yml initializer 2020-09-15 15:38:24 -05:00
b33a509e25 Merge pull request #333 from tobiasge/python-3.8
Move default source image to Python 3.8
2020-09-01 15:35:17 +02:00
79f0b997f3 Merge pull request #332 from tobiasge/image-deps
Update images in docker-compose
2020-09-01 14:04:21 +02:00
32cef1dcf8 Enable test on Python 3.9 2020-09-01 13:52:01 +02:00
74833a9b21 Update images in docker-compose 2020-09-01 13:34:42 +02:00
a68f315acb Move default source image to Python 3.8 2020-09-01 12:27:39 +02:00
00022e7d79 Merge pull request #331 from netbox-community/develop
Develop
2020-09-01 11:05:25 +02:00
dd490605ca Preparation for 0.25.0 2020-09-01 10:40:16 +02:00
e2711ca205 Merge pull request #326 from tobiasge/fix-startup-2.9
Fixes for Netbox 2.9
2020-09-01 10:37:37 +02:00
a87f2b3331 Merge pull request #329 from tdorsey/patch-1
Fix typo in Readme
2020-08-31 08:03:33 +02:00
f174749f98 chore: fix typo 2020-08-30 22:06:20 -04:00
b02a93904e Fixed IP address creation for Netbox 2.9 2020-08-24 14:20:35 +02:00
3ace32dfc2 Fixed creation of passwords for Netbox 2.9 2020-08-24 11:08:28 +02:00
9fae2b0f74 Fixed VM interface creation for Netbox 2.9 2020-08-24 11:08:23 +02:00
23c3240863 Merge pull request #319 from jamiereid/release
Update README.md
2020-07-14 09:09:20 +02:00
3f9e874d77 Update README.md
fix spelling mistake
2020-07-14 11:19:49 +10:00
4b0f158852 Merge pull request #313 from jgcasd/jgcasd-patch-1
Add optional LOGIN_TIMEOUT to configuration.py
2020-06-17 15:26:16 +02:00
51490d0039 Added LOGIN_TIMEOUT option to configuration.py
Added LOGIN_TIMEOUT option to configuration.py. The option is already available in standard Netbox configuration.
2020-06-16 11:27:59 -07:00
df72d6bbb5 Handle primary IPs on devices and VMs 2020-06-05 13:12:27 +02:00
688672de26 Merge pull request #308 from netbox-community/XForwardedProto
Remove the 'X-Forwarded-Proto' line from the nginx config
2020-06-05 11:57:23 +02:00
5624ecc65e Remove the 'X-Forwarded-Proto' line from the nginx config
The reason is that in the default configuration nginx is only serving 'http' traffic.
So if an upstream proxy sets the 'X-Forwarded-Proto' header, because it is terminating
TLS, then nginx will overwrite it to 'http'. This will cause django to think the page
is served via 'http' and it will not create 'https://...' URLs.

Related to #292
2020-06-02 16:06:52 +02:00
7f93b328af Merge pull request #307 from netbox-community/FixFileMatching
Don't try to run non-python files
2020-06-02 14:42:58 +02:00
ccad15ecf7 Don't try to run non-python files 2020-06-02 13:37:57 +02:00
e9a9d9b70b Merge pull request #305 from netbox-community/develop
Preparation for 0.24.1
2020-05-29 14:41:15 +02:00
03b36058cd Preparation for 0.24.1 2020-05-29 10:09:08 +02:00
9e06a38d41 Merge pull request #304 from tobiasge/fix-303
Fix #303 for Netbox v2.8.5
2020-05-29 10:03:22 +02:00
b7ad18afb0 Fix #303 for Netbox v2.8.5
In this Netbox version the ColorChoices where moved to utilities.choiceFix #303 for Netbox v2.8.5

In this Netbox version the ColorChoices where moved to utilities.choicess
2020-05-27 09:10:24 +02:00
a9232e4f30 Add optional primary_ip on virtual machines initializer 2020-05-22 17:40:11 +02:00
93a3784295 Merge pull request #296 from netbox-community/develop
Release 0.24.0
2020-05-16 18:56:06 +02:00
45f7823a17 Preparation for 0.24.0 2020-05-15 13:59:45 +02:00
a6584d2874 Merge pull request #274 from tobiasge/optimise-builds
Optimise builds
2020-05-15 13:57:43 +02:00
fd87c7cb98 Merge pull request #294 from netbox-community/Fix284
Fix #284: Fixes the bug that initializers with no data stopped the execution of the later initializers
2020-05-15 13:57:23 +02:00
1f38ca0a86 Merge pull request #295 from minitriga/#293_ssl_tls_env
Implement SSL and TLS Config
2020-05-15 09:29:02 +02:00
efec435ba0 fix some issues 2020-05-14 15:37:47 +00:00
ab8ff04852 #293 2020-05-14 15:09:25 +00:00
77feec30a0 Don't stop when startup_scripts quit
Fixes #284
2020-05-14 16:59:30 +02:00
bed40b0d05 Add STARTTLS option. (#277)
* Add STARTTLS option.
2020-05-14 16:41:42 +02:00
24f0545bc6 Merge branch 'ryanmerolle-develop' into develop 2020-05-14 16:20:07 +02:00
1bc1ab2a0a Preserve compatibility 2020-05-14 16:19:38 +02:00
bfa69dc0e9 Merge branch 'develop' of https://github.com/ryanmerolle/netbox-docker into ryanmerolle-develop 2020-05-14 16:17:59 +02:00
6c8042b63d Merge pull request #289 from weisdd/bugfix/devices.py.example
Fixes #246: Non-working devices.py.example
2020-05-14 15:35:34 +02:00
795e82be46 Fix shellcheck error 2020-05-14 13:54:40 +02:00
d8a6c321a1 Update build.sh
Include suggestion from cimnine

Co-authored-by: Christian Mäder <cimnine@users.noreply.github.com>
2020-05-14 13:49:19 +02:00
1ecf4853b8 Fixed devices.py.example report 2020-05-11 16:46:10 +03:00
5cb8e97e65 Merge pull request #276 from weisdd/bugfix/dockerfile-media-permissions
Dockerfile: Fixed file permissions for media
2020-05-06 18:40:00 +02:00
98e131fa30 Merge pull request #279 from hoanhan101/release
Fix typo in overriding docker-compose config
2020-04-22 22:51:44 +02:00
d6323ce40f Fix typo in overriding docker-compose config 2020-04-22 16:24:34 -04:00
1c65f7af10 Dockerfile: Fixed file permissions for media 2020-04-18 17:08:42 +03:00
7fb78b3fd2 Fixed script in case no branch for next exists
Build now prints a message when no devlop-* branch is found instead of crashing
2020-04-13 21:44:18 +02:00
aa9f01a778 Merge pull request #273 from cimnine/NoResponse
No response
2020-04-09 21:17:42 +02:00
786f9b50d2 Fixes build when DOCKER_FROM is set but empty
The DOCKER_FROM is set to an empty value in the push tests.
This expands the check to catch this test case
2020-04-09 10:26:21 +02:00
5909670690 Fixed "latest" tag
The variable for the latest tag didn't contain all the needed values.
2020-04-09 09:04:20 +02:00
231de236e0 Removed Travis CI configuration and script
We are no longer building the images with Travis CI.
2020-04-09 08:47:07 +02:00
9ea95950b9 probot/no-response configuration 2020-04-09 08:30:30 +02:00
d84c399c00 Let "latest" tag follow the highest version
Latest tag is now added to the new version when it is release by Netbox.
2020-04-09 08:17:05 +02:00
a217ce8ffd Changed "build-branches.sh" to "build-next.sh"
The old version of "build-branches.sh" skipped the pushing of images when one of
them didn't change its sources. When looking at the Netbox branches I noticed
that the "master" branch only changes when there is a new release. Because we
build the new releases anyway in "build-latest.sh" that leaves "develop" and
"develop-*" which change regularly. The new script "build-next.sh" is responsible
for building "develop-*" as the next major release of Netbox. The build of
"develop" is moved to the Github Action build matrix. This has the additional
advantage of being faster because more builds are done in parallel.
2020-04-08 22:11:37 +02:00
794fb45e0e Fix shellcheck items found by shellcheck 0.7.1 2020-04-08 16:06:55 +02:00
8e34f46bad Add checks to verifiy if a new build is needed
This checks if the source materials (python image, Netbox commit,
netbox-docker commit) have changed since the last build. This check is done
by comparing the digest and commit ids from the previous image with the
given tag to the current values taken from the Git and Docker repositories.

The checks are only performed for builds by the automated builds on Github.
2020-04-08 15:50:06 +02:00
ed0d099df7 Merge pull request #271 from tobiasge/labels-in-build
Add labels for all variants
2020-04-05 13:14:48 +02:00
26d08302e3 Add labels for all variants
When we don't set the --label argument on the commandline for all
build variants we lose them in the image.
This also prints out the labes on image push.
2020-04-05 09:29:31 +02:00
64b763429f update configuration.py for netbox 2.7.11 REDIS config
update configuration.py to use REDIS config referencing `tasks` in place of `webhooks`
2020-04-01 23:41:35 -04:00
5769684c98 Merge pull request #265 from netbox-community/develop
Release 0.23.0
2020-03-30 20:51:22 +02:00
23e2da52f8 Preparation for 0.23.0 2020-03-30 15:15:30 +02:00
edba1a22fc Merge pull request #263 from general-programming/RELEASE_CHECK_URL
Add RELEASE_CHECK_URL to configuration and default env.
2020-03-30 15:13:59 +02:00
f87ffe7c33 Update configuration/configuration.py
Co-Authored-By: Christian Mäder <cimnine@users.noreply.github.com>
2020-03-29 01:40:08 -07:00
8bc77c1bc0 Add RELEASE_CHECK_URL to configuration and default env. 2020-03-27 21:34:51 -07:00
7662d81efe Merge pull request #258 from netbox-community/readme_improvements
Readme improvements
2020-03-17 16:39:43 +01:00
7f489aa11d Improved the README
- adjust the _Quick Start_ section to match the instructions in the _Getting Started_ guide on our wiki
- Adds a new _Getting Help_ section
- Improvements in explaining the tags of the published Docker image
2020-03-17 16:07:15 +01:00
5c3eff0823 Merge pull request #255 from minitriga/issue_253_docs_2
Fix embedded documents for Netbox version v2.7.10 and higher.
2020-03-11 12:16:48 +01:00
5f90ad8c56 inlude docs in container 2020-03-11 10:40:10 +00:00
5f1c241145 Merge pull request #245 from ScanPlusGmbH/fix-configuration-inconsistencies
Fix configuration inconsistencies
2020-03-11 09:53:21 +01:00
20c7461c7b Fixed test failures because of missing cache
When running tests with ´test.sh´ some errors where logged because now
redis-cache instance was running.
2020-02-14 12:38:05 +01:00
b9c44b85cc The Redis cache container was using the wrong env
Our docker-compose.yml pointed the env file for the Redis cache to the
wrong file. Now the Redis cache password between the netbox.env and
redis-cache.env match.
2020-02-14 12:38:05 +01:00
355ebadd10 Fixed configuration inconsistency for Redis cache
In the configuration.py we use database 1 as the default but in the .env
file we used 0. This sets both values to 1 as the default.
2020-02-14 12:38:05 +01:00
880628876f Merge pull request #244 from ScanPlusGmbH/init-perms-function
Permission handling in external function
2020-02-13 08:15:27 +01:00
8d3bd48c7a Permission handling in external function
This move the setting of user and group permissions in the startup
script to its own function.
2020-02-12 09:36:49 +01:00
882f7bcaf2 Merge pull request #238 from ScanPlusGmbH/remove-redundancy
Add function to load YAML files
2020-02-10 19:25:42 +01:00
50ade7bce1 Add function to load YAML files
This commit starts to remove some code redundancy from the startup
scripts for easier maintenance.
2020-02-10 07:47:17 +01:00
130 changed files with 3148 additions and 1800 deletions

View File

@ -7,5 +7,4 @@ build*
docker-compose.override.yml
.netbox/.git*
.netbox/.travis.yml
.netbox/docs
.netbox/scripts

23
.ecrc Normal file
View File

@ -0,0 +1,23 @@
{
"Verbose": false,
"Debug": false,
"IgnoreDefaults": false,
"SpacesAftertabs": false,
"NoColor": false,
"Exclude": [
"LICENSE",
"\\.initializers",
"\\.vscode"
],
"AllowedContentTypes": [],
"PassedFiles": [],
"Disable": {
// set these options to true to disable specific checks
"EndOfLine": false,
"Indentation": false,
"InsertFinalNewline": false,
"TrimTrailingWhitespace": false,
"IndentSize": true,
"MaxLineLength": false
}
}

11
.editorconfig Normal file
View File

@ -0,0 +1,11 @@
root = true
[*]
end_of_line = lf
insert_final_newline = true
charset = utf-8
indent_style = space
indent_size = 2
[*.py]
indent_size = 4

7
.flake8 Normal file
View File

@ -0,0 +1,7 @@
[flake8]
max-line-length = 100
extend-ignore = E203, W503
per-file-ignores =
configuration/*:E131,E251,E266,E302,E305,E501,E722
startup_scripts/startup_script_utils/__init__.py:F401
docker/*:E266,E722

14
.github/FUNDING.yml vendored Normal file
View File

@ -0,0 +1,14 @@
# These are supported funding model platforms
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
- cimnine
- tobiasge
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']

View File

@ -1,77 +0,0 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
<!--
Before raising an issue here, answer the following questions for yourself, please:
* Did you read through the troubleshooting section? (https://github.com/netbox-community/netbox-docker/wiki/Troubleshooting)
* Have you had a look at the rest of the wiki? (https://github.com/netbox-community/netbox-docker/wiki)
* Have you updated to the latest version and tried again? (i.e. `git pull` and `docker-compose pull`)
* Have you reset the project and tried again? (i.e. `docker-compose down -v`)
* Are you confident that your problem is related to the Docker image or Docker Compose file this project provides?
(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
Please don't open an issue when you have a PR ready. Just submit the PR, that's good enough.
-->
## Current Behavior
<!-- describe what you did and how it misbehaved -->
...
## Expected Behavior
<!-- describe what you expected instead -->
...
## Debug Information
<!-- please fill in the following information that might helps us debug your problem more quickly -->
The output of `docker-compose version`: `XXXXX`
The output of `docker version`: `XXXXX`
The output of `git rev-parse HEAD`: `XXXXX`
The command you used to start the project: `XXXXX`
<!-- adjust the `latest` tag to the version you're using -->
The output of `docker inspect netboxcommunity/netbox:latest --format "{{json .Config.Labels}}"`:
```json
{
"JSON JSON JSON":
"--> Please paste formatted json. (Use e.g. `jq` or https://jsonformatter.curiousconcept.com/)"
}
```
The output of `docker-compose logs netbox`:
<!--
If your log is very long, create a Gist instead (and post the link to it): https://gist.github.com
-->
```text
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
-->
```text
LOG LOG LOG
```

148
.github/ISSUE_TEMPLATE/bug_report.yml vendored Normal file
View File

@ -0,0 +1,148 @@
name: Bug report
description: Create a report about a malfunction of the Docker setup
body:
- type: markdown
attributes:
value: |
Please only raise an issue if you're certain that you've found a bug.
Else, see these other means to get help:
- See our troubleshooting section:
https://github.com/netbox-community/netbox-docker/wiki/Troubleshooting
- Have a look at the rest of the wiki:
https://github.com/netbox-community/netbox-docker/wiki
- Check the release notes:
https://github.com/netbox-community/netbox-docker/releases
- Look through the issues already resolved:
https://github.com/netbox-community/netbox-docker/issues?q=is%3Aclosed
If you did not find what you're looking for,
try the help of our community:
- Post to Github Discussions:
https://github.com/netbox-community/netbox-docker/discussions
- Join the `#netbox-docker` channel on our Slack:
https://join.slack.com/t/netdev-community/shared_invite/zt-mtts8g0n-Sm6Wutn62q_M4OdsaIycrQ
- Ask on the NetBox mailing list:
https://groups.google.com/d/forum/netbox-discuss
Please don't open an issue to open a PR.
Just submit the PR, that's good enough.
- type: textarea
id: current-behavior
attributes:
label: Current Behavior
description: Please describe what you did and how you think it misbehaved
placeholder: I tried to … by doing …, but it …
validations:
required: true
- type: textarea
id: expected-behavior
attributes:
label: Expected Behavior
description: Please describe what you expected instead
placeholder: I expected that … when I do …
validations:
required: true
- type: input
id: docker-compose-version
attributes:
label: Docker Compose Version
description: Please paste the output of `docker-compose version`
placeholder: Docker Compose version vX.Y.Z
validations:
required: true
- type: textarea
id: docker-version
attributes:
label: Docker Version
description: Please paste the output of `docker version`
render: text
placeholder: |
Client:
Cloud integration: 1.0.17
Version: 20.10.8
API version: 1.41
Go version: go1.16.6
Git commit: 3967b7d
Built: Fri Jul 30 19:55:20 2021
OS/Arch: darwin/amd64
Context: default
Experimental: true
Server: Docker Engine - Community
Engine:
Version: 20.10.8
API version: 1.41 (minimum version 1.12)
Go version: go1.16.6
Git commit: 75249d8
Built: Fri Jul 30 19:52:10 2021
OS/Arch: linux/amd64
Experimental: false
containerd:
Version: 1.4.9
GitCommit: e25210fe30a0a703442421b0f60afac609f950a3
runc:
Version: 1.0.1
GitCommit: v1.0.1-0-g4144b63
docker-init:
Version: 0.19.0
GitCommit: de40ad0
validations:
required: true
- type: input
id: git-rev
attributes:
label: The git Revision
description: Please paste the output of `git rev-parse HEAD`
validations:
required: true
- type: textarea
id: git-status
attributes:
label: The git Status
description: Please paste the output of `git status`
render: text
placeholder: |
On branch main
nothing to commit, working tree clean
validations:
required: true
- type: input
id: run-command
attributes:
label: Startup Command
description: Please specify the command you used to start the project
placeholder: docker compose up
validations:
required: true
- type: textarea
id: netbox-logs
attributes:
label: NetBox Logs
description: Please paste the output of `docker-compose logs netbox` (or `docker compose logs netbox`)
render: text
placeholder: |
netbox_1 | ⚙️ Applying database migrations
netbox_1 | 🧬 loaded config '/etc/netbox/config/configuration.py'
netbox_1 | 🧬 loaded config '/etc/netbox/config/a.py'
netbox_1 | 🧬 loaded config '/etc/netbox/config/extra.py'
netbox_1 | 🧬 loaded config '/etc/netbox/config/logging.py'
netbox_1 | 🧬 loaded config '/etc/netbox/config/plugins.py'
...
validations:
required: true
- type: textarea
id: docker-compose-override-yml
attributes:
label: Content of docker-compose.override.yml
description: Please paste the output of `cat docker-compose.override.yml`
render: yaml
placeholder: |
version: '3.4'
services:
netbox:
ports:
- '8080:8080'
validations:
required: true

15
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@ -0,0 +1,15 @@
blank_issues_enabled: false
contact_links:
- name: Question
url: https://github.com/netbox-community/netbox-docker/discussions
about: The Github Discussions are the right place to ask questions about how to use or do certain things with NetBox Docker.
- name: Chat
url: https://join.slack.com/t/netdev-community/shared_invite/zt-mtts8g0n-Sm6Wutn62q_M4OdsaIycrQ
about: 'Usually the quickest way to seek help with small issues is to join our #netbox-docker Slack channel.'
- name: Community Wiki
url: https://github.com/netbox-community/netbox-docker/wiki
about: |
Our wiki contains information for common problems and tips for operating NetBox Docker in production.
It's maintained by our excellent community.

View File

@ -1,54 +0,0 @@
---
name: Feature or Change Request
about: Request a new feature or a change of the current behavior
title: ''
labels: ''
assignees: ''
---
<!--
Before raising an issue here, answer the following questions for yourself, please:
* Did you read through the troubleshooting section? (https://github.com/netbox-community/netbox-docker/wiki/Troubleshooting)
* Have you had a look at the rest of the wiki? (https://github.com/netbox-community/netbox-docker/wiki)
* Have you read the release notes recently (https://github.com/netbox-community/netbox-docker/releases)
* Are you confident that your feature/change request is related to the Docker image or Docker Compose file this project provides?
(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
Please don't open an issue when you have a PR ready. Just submit the PR, that's good enough.
-->
## Desired Behavior
<!-- please describe the behavior you desire -->
...
## Contrast to Current Behavior
<!-- please describe how the desired behavior is different from the current behavior -->
...
## Changes Required
<!-- if you can, please elaborate what changes would exactly be required -->
...
## Discussion: Benefits and Drawbacks
<!--
Please make your case here:
- Why do you think this project and the community will benefit from your suggestion?
- What are the drawbacks of this change? Is it backwards-compatible?
- Anything else that you think is relevant to the discussion of this feature/change request.
-->
...

View File

@ -0,0 +1,68 @@
name: Feature or Change Request
description: Request a new feature or a change of the current behavior
body:
- type: markdown
attributes:
value: |
This issue type is to propose new features for the Docker setup.
To just spin an idea, see the Github Discussions section, please.
Before asking for help, see these links first:
- See our troubleshooting section:
https://github.com/netbox-community/netbox-docker/wiki/Troubleshooting
- Have a look at the rest of the wiki:
https://github.com/netbox-community/netbox-docker/wiki
- Check the release notes:
https://github.com/netbox-community/netbox-docker/releases
- Look through the issues already resolved:
https://github.com/netbox-community/netbox-docker/issues?q=is%3Aclosed
If you did not find what you're looking for,
try the help of our community:
- Post to Github Discussions:
https://github.com/netbox-community/netbox-docker/discussions
- Join the `#netbox-docker` channel on our Slack:
https://join.slack.com/t/netdev-community/shared_invite/zt-mtts8g0n-Sm6Wutn62q_M4OdsaIycrQ
- Ask on the NetBox mailing list:
https://groups.google.com/d/forum/netbox-discuss
Please don't open an issue to open a PR.
Just submit the PR, that's good enough.
- type: textarea
id: desired-behavior
attributes:
label: Desired Behavior
description: Please describe the desired behavior
placeholder: To me, it would be useful, if … because …
validations:
required: true
- type: textarea
id: contrast-to-current
attributes:
label: Contrast to Current Behavior
description: Please describe how the desired behavior is different from the current behavior
placeholder: The current behavior is …, but this lacks …
validations:
required: true
- type: textarea
id: required-changes
attributes:
label: Required Changes
description: If you can, please elaborate what changes will be required to implement the desired behavior
placeholder: I suggest to change the file …
validations:
required: false
- type: textarea
id: discussion
attributes:
label: 'Discussion: Benefits and Drawbacks'
description: |
Please make your case here:
- Why do you think this project and the community will benefit from your suggestion?
- What are the drawbacks of this change? Is it backwards-compatible?
- Anything else that you think is relevant to the discussion of this feature/change request.
placeholder: I suggest to change the file …
validations:
required: false

10
.github/no-response.yml vendored Normal file
View File

@ -0,0 +1,10 @@
# Configuration for probot-no-response - https://github.com/probot/no-response
# Number of days of inactivity before an Issue is closed for lack of response
daysUntilClose: 30
# Label requiring a response
responseRequiredLabel: awaiting answer
# Comment to post when closing an Issue for lack of response. Set to `false` to disable
closeComment: >
This issue has been automatically closed because there has been no response
to our request for more information from the original author.

View File

@ -9,25 +9,51 @@ on:
- release
jobs:
lint:
runs-on: ubuntu-latest
name: Checks syntax of our code
steps:
- uses: actions/checkout@v2
with:
# Full git history is needed to get a proper list of changed files within `super-linter`
fetch-depth: 0
- uses: actions/setup-python@v2
- name: Lint Code Base
uses: github/super-linter@v4
env:
DEFAULT_BRANCH: develop
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SUPPRESS_POSSUM: true
LINTER_RULES_PATH: /
VALIDATE_ALL_CODEBASE: false
VALIDATE_DOCKERFILE: false
FILTER_REGEX_EXCLUDE: (.*/)?(LICENSE|configuration/.*)
EDITORCONFIG_FILE_NAME: .ecrc
DOCKERFILE_HADOLINT_FILE_NAME: .hadolint.yaml
MARKDOWN_CONFIG_FILE: .markdown-lint.yml
PYTHON_BLACK_CONFIG_FILE: pyproject.toml
PYTHON_FLAKE8_CONFIG_FILE: .flake8
PYTHON_ISORT_CONFIG_FILE: pyproject.toml
build:
continue-on-error: ${{ matrix.docker_from == 'alpine:edge' }}
strategy:
matrix:
build_cmd:
- ./build-latest.sh
- PRERELEASE=true ./build-latest.sh
- ./build-branches.sh
- ./build.sh feature
- ./build.sh develop
docker_from:
- '' # use the default of the DOCKERFILE
- python:3.7-alpine
- python:3.8-alpine
# - python:3.9-rc-alpine # disable until Netbox's unit tests work
- '' # use the default of the build script
- alpine:edge
fail-fast: false
runs-on: ubuntu-latest
name: Builds new Netbox Docker Images
name: Builds new NetBox Docker Images
steps:
- id: git-checkout
name: Checkout
uses: actions/checkout@v1
uses: actions/checkout@v2
- id: docker-build
name: Build the image from '${{ matrix.docker_from }}' with '${{ matrix.build_cmd }}'
run: ${{ matrix.build_cmd }}

View File

@ -14,14 +14,15 @@ jobs:
build_cmd:
- ./build-latest.sh
- PRERELEASE=true ./build-latest.sh
- ./build-branches.sh
- ./build.sh feature
- ./build.sh develop
fail-fast: false
runs-on: ubuntu-latest
name: Builds new Netbox Docker Images
name: Builds new NetBox Docker Images
steps:
- id: git-checkout
name: Checkout
uses: actions/checkout@v1
uses: actions/checkout@v2
- id: docker-build
name: Build the image with '${{ matrix.build_cmd }}'
run: ${{ matrix.build_cmd }}
@ -49,3 +50,34 @@ jobs:
name: Logout of the Docker Registry
run: docker logout "${DOCKER_REGISTRY}"
if: steps.docker-build.outputs.skipped != 'true'
# Quay.io
- id: quayio-docker-build
name: Build the image with '${{ matrix.build_cmd }}'
run: ${{ matrix.build_cmd }}
env:
DOCKER_REGISTRY: quay.io
GH_ACTION: enable
- id: quayio-registry-login
name: Login to the Quay.io Registry
run: |
echo "::add-mask::$QUAYIO_USERNAME"
echo "::add-mask::$QUAYIO_PASSWORD"
docker login -u "$QUAYIO_USERNAME" --password "${QUAYIO_PASSWORD}" "${DOCKER_REGISTRY}"
env:
DOCKER_REGISTRY: quay.io
QUAYIO_USERNAME: ${{ secrets.quayio_username }}
QUAYIO_PASSWORD: ${{ secrets.quayio_password }}
if: steps.docker-build.outputs.skipped != 'true'
- id: quayio-registry-push
name: Push the image
run: ${{ matrix.build_cmd }} --push-only
env:
DOCKER_REGISTRY: quay.io
if: steps.docker-build.outputs.skipped != 'true'
- id: quayio-registry-logout
name: Logout of the Docker Registry
run: docker logout "${DOCKER_REGISTRY}"
env:
DOCKER_REGISTRY: quay.io
if: steps.docker-build.outputs.skipped != 'true'

11
.gitignore vendored
View File

@ -2,3 +2,14 @@
.netbox
.initializers
docker-compose.override.yml
*.pem
configuration/*
!configuration/configuration.py
!configuration/extra.py
configuration/ldap/*
!configuration/ldap/extra.py
!configuration/ldap/ldap_config.py
!configuration/logging.py
!configuration/plugins.py
prometheus.yml
super-linter.log

3
.hadolint.yaml Normal file
View File

@ -0,0 +1,3 @@
ignored:
- DL3006
- DL3018

2
.markdown-lint.yml Normal file
View File

@ -0,0 +1,2 @@
MD013: false
MD041: false

View File

@ -1,32 +0,0 @@
sudo: required
language: python
env:
- BUILD=release
- BUILD=prerelease
- BUILD=branches
- BUILD=special
git:
depth: 5
services:
- docker
install:
- docker-compose pull --parallel
- docker-compose build
script:
- docker-compose run netbox ./manage.py test
after_script:
- docker-compose down
after_success:
- docker login -u="$DOCKER_USERNAME" -p="$DOCKER_PASSWORD"
- ./build-all.sh --push
notifications:
slack:
secure: F3VsWcvU/XYyjGjU8ZAVGpREe7F1NjKq6LuMRzhQORbXUvanxDQtLzEe0Y5zm/6+gHkx6t8cX/v2PiCI+v46pkapYMUimd+QEOL1WxbUdnw2kQxcgw/R3wX34l2FHXbG3/a+TmH3euqbSCTIrPy9ufju948i+Q0E0u0fyInmozl8qOT23C4joQOpVAq7y+wHxTxsEg46ZzL2Ties+dmqjMsvHocv7mPI2IWzAWA8SJZxS82Amoapww++QjgEmoY+tMimLkdeXCRgeoj41UGHDg54rbEXh/PTaWiuzyzTr1WLmsGRScC57fDRivp3mSM37/MlNxsRj1z+j4zrvWFQgNfJ2yMjBHroc1jOX/uCY4dwbpSPqUCpc4idMGCGZFItgzTQ3lAPYAsom0C6n8C08Xk8EsNKWwXrDSd4ZUhIwptkNPCFK+kXbLFsMzSApnaBYW0T+wba57nZdiWjOPYmvJr49MDm5NHv2KaRBX2gpw7t7ZLhTgwGEWcZvcDebiLneXcXY5hZ7v2NHJkx/2x1yNXo85xZDy0wK1FGoOOHwPhvqOB+pcQZ/pUOSPTKqGw5l/CexoRm1shFsK+19FnSgimqTHjcuCo4lFW3JlEvlFhtfFXIte2Wjp1ALZgTrSq8zSD5rRxYCUKmM7b3EJwdaIgbvKWPdS4sCXlXU1bHx0g=

View File

@ -1,38 +1,50 @@
ARG FROM=python:3.7-alpine
ARG FROM
FROM ${FROM} as builder
RUN apk add --no-cache \
bash \
build-base \
cargo \
ca-certificates \
cmake \
cyrus-sasl-dev \
git \
graphviz \
jpeg-dev \
libevent-dev \
libffi-dev \
libxslt-dev \
make \
musl-dev \
openldap-dev \
postgresql-dev
postgresql-dev \
py3-pip \
python3-dev \
&& python3 -m venv /opt/netbox/venv \
&& /opt/netbox/venv/bin/python3 -m pip install --upgrade \
pip \
setuptools \
wheel
WORKDIR /install
RUN pip install --prefix="/install" --no-warn-script-location \
# gunicorn is used for launching netbox
gunicorn \
greenlet \
eventlet \
# napalm is used for gathering information from network devices
napalm \
# ruamel is used in startup_scripts
'ruamel.yaml>=0.15,<0.16' \
# django_auth_ldap is required for ldap
django_auth_ldap \
# django-storages was introduced in 2.7 and is optional
django-storages
# Build libcrc32c for google-crc32c python module
RUN git clone https://github.com/google/crc32c \
&& cd crc32c \
&& git submodule update --init --recursive \
&& mkdir build \
&& cd build \
&& cmake \
-DCMAKE_BUILD_TYPE=Release \
-DCRC32C_BUILD_TESTS=no \
-DCRC32C_BUILD_BENCHMARKS=no \
-DBUILD_SHARED_LIBS=yes \
.. \
&& make all install
ARG NETBOX_PATH
COPY ${NETBOX_PATH}/requirements.txt /
RUN pip install --prefix="/install" --no-warn-script-location -r /requirements.txt
COPY ${NETBOX_PATH}/requirements.txt requirements-container.txt /
RUN /opt/netbox/venv/bin/pip install \
-r /requirements.txt \
-r /requirements-container.txt
###
# Main stage
@ -44,42 +56,53 @@ FROM ${FROM} as main
RUN apk add --no-cache \
bash \
ca-certificates \
curl \
graphviz \
libevent \
libffi \
libjpeg-turbo \
libressl \
libxslt \
openssl \
postgresql-libs \
ttf-ubuntu-font-family
py3-pip \
python3 \
tini \
unit \
unit-python3
WORKDIR /opt
COPY --from=builder /install /usr/local
COPY --from=builder /usr/local/lib/libcrc32c.* /usr/local/lib/
COPY --from=builder /usr/local/include/crc32c /usr/local/include
COPY --from=builder /usr/local/lib/cmake/Crc32c /usr/local/lib/cmake/
COPY --from=builder /opt/netbox/venv /opt/netbox/venv
ARG NETBOX_PATH
COPY ${NETBOX_PATH} /opt/netbox
COPY docker/configuration.docker.py /opt/netbox/netbox/netbox/configuration.py
COPY configuration/gunicorn_config.py /etc/netbox/config/
COPY docker/nginx.conf /etc/netbox-nginx/nginx.conf
COPY docker/docker-entrypoint.sh /opt/netbox/docker-entrypoint.sh
COPY docker/housekeeping.sh /opt/netbox/housekeeping.sh
COPY docker/launch-netbox.sh /opt/netbox/launch-netbox.sh
COPY startup_scripts/ /opt/netbox/startup_scripts/
COPY initializers/ /opt/netbox/initializers/
COPY configuration/configuration.py /etc/netbox/config/configuration.py
COPY configuration/ /etc/netbox/config/
COPY docker/nginx-unit.json /etc/unit/
WORKDIR /opt/netbox/netbox
# Must set permissions for '/opt/netbox/netbox/static' directory
# to g+w so that `./manage.py collectstatic` can be executed during
# container startup.
# Must set permissions for '/opt/netbox/netbox/media' directory
# to g+w so that pictures can be uploaded to netbox.
RUN mkdir static && chmod g+w static media
RUN mkdir -p static /opt/unit/state/ /opt/unit/tmp/ \
&& chown -R unit:root media /opt/unit/ \
&& chmod -R g+w media /opt/unit/ \
&& cd /opt/netbox/ && /opt/netbox/venv/bin/python -m mkdocs build \
--config-file /opt/netbox/mkdocs.yml --site-dir /opt/netbox/netbox/project-static/docs/ \
&& SECRET_KEY="dummy" /opt/netbox/venv/bin/python /opt/netbox/netbox/manage.py collectstatic --no-input
ENTRYPOINT [ "/opt/netbox/docker-entrypoint.sh" ]
ENTRYPOINT [ "/sbin/tini", "--" ]
CMD ["gunicorn", "-c /etc/netbox/config/gunicorn_config.py", "netbox.wsgi"]
CMD [ "/opt/netbox/docker-entrypoint.sh", "/opt/netbox/launch-netbox.sh" ]
LABEL ORIGINAL_TAG="" \
NETBOX_GIT_BRANCH="" \
@ -89,8 +112,8 @@ LABEL ORIGINAL_TAG="" \
# Also https://microbadger.com/labels
org.label-schema.schema-version="1.0" \
org.label-schema.build-date="" \
org.label-schema.name="Netbox Docker" \
org.label-schema.description="A container based distribution of Netbox, the free and open IPAM and DCIM solution." \
org.label-schema.name="NetBox Docker" \
org.label-schema.description="A container based distribution of NetBox, the free and open IPAM and DCIM solution." \
org.label-schema.vendor="The netbox-docker contributors." \
org.label-schema.url="https://github.com/netbox-community/netbox-docker" \
org.label-schema.usage="https://github.com/netbox-community/netbox-docker/wiki" \
@ -99,8 +122,8 @@ LABEL ORIGINAL_TAG="" \
org.label-schema.version="snapshot" \
# See https://github.com/opencontainers/image-spec/blob/master/annotations.md#pre-defined-annotation-keys
org.opencontainers.image.created="" \
org.opencontainers.image.title="Netbox Docker" \
org.opencontainers.image.description="A container based distribution of Netbox, the free and open IPAM and DCIM solution." \
org.opencontainers.image.title="NetBox Docker" \
org.opencontainers.image.description="A container based distribution of NetBox, the free and open IPAM and DCIM solution." \
org.opencontainers.image.licenses="Apache-2.0" \
org.opencontainers.image.authors="The netbox-docker contributors." \
org.opencontainers.image.vendor="The netbox-docker contributors." \
@ -122,4 +145,3 @@ RUN apk add --no-cache \
util-linux
COPY docker/ldap_config.docker.py /opt/netbox/netbox/netbox/ldap_config.py
COPY configuration/ldap_config.py /etc/netbox/config/ldap_config.py

133
README.md
View File

@ -5,36 +5,40 @@
![GitHub closed pull requests](https://img.shields.io/github/issues-pr-closed-raw/netbox-community/netbox-docker)
![Github release workflow](https://img.shields.io/github/workflow/status/netbox-community/netbox-docker/release)
![Docker Pulls](https://img.shields.io/docker/pulls/netboxcommunity/netbox)
[![MicroBadger Layers](https://img.shields.io/microbadger/layers/netboxcommunity/netbox)][netbox-docker-microbadger]
[![MicroBadger Size](https://img.shields.io/microbadger/image-size/netboxcommunity/netbox)][netbox-docker-microbadger]
[![GitHub license](https://img.shields.io/github/license/netbox-community/netbox-docker)][netbox-docker-license]
[The Github repository](netbox-docker-github) houses the components needed to build Netbox as a Docker container.
Images are built using this code and are released to [Docker Hub][netbox-dockerhub] once a day.
[The Github repository](netbox-docker-github) houses the components needed to build NetBox as a Docker container.
Images are built using this code and are released to [Docker Hub][netbox-dockerhub] and [Quay.io][netbox-quayio] once a day.
Do you have any questions? Before opening an issue on Github, please join the [Network To Code][ntc-slack] Slack and ask for help in our [`#netbox-docker`][netbox-docker-slack] channel.
Do you have any questions?
Before opening an issue on Github,
please join the [our Slack][netbox-docker-slack] and ask for help in the [`#netbox-docker`][netbox-docker-slack-channel] channel.
[github-stargazers]: https://github.com/netbox-community/netbox-docker/stargazers
[github-release]: https://github.com/netbox-community/netbox-docker/releases
[netbox-docker-microbadger]: https://microbadger.com/images/netboxcommunity/netbox
[netbox-dockerhub]: https://hub.docker.com/r/netboxcommunity/netbox/tags/
[netbox-dockerhub]: https://hub.docker.com/r/netboxcommunity/netbox/
[netbox-docker-github]: https://github.com/netbox-community/netbox-docker/
[ntc-slack]: http://slack.networktocode.com/
[netbox-docker-slack]: https://slack.com/app_redirect?channel=netbox-docker&team=T09LQ7E9E
[netbox-docker-slack]: https://join.slack.com/t/netdev-community/shared_invite/zt-mtts8g0n-Sm6Wutn62q_M4OdsaIycrQ
[netbox-docker-slack-channel]: https://netdev-community.slack.com/archives/C01P0GEVBU7
[netbox-slack-channel]: https://netdev-community.slack.com/archives/C01P0FRSXRV
[netbox-docker-license]: https://github.com/netbox-community/netbox-docker/blob/release/LICENSE
[netbox-quayio]: https://quay.io/repository/netboxcommunity/netbox
## Docker Tags
* `vX.Y.Z`: Release builds, built from [releases of Netbox][netbox-releases].
* `latest`: Release builds, built from [`master` branch of Netbox][netbox-master].
* `snapshot`: Pre-release builds, built from the [`develop` branch of Netbox][netbox-develop].
* `develop-X.Y`: Pre-release builds, built from the corresponding [branch of Netbox][netbox-branches].
* `vX.Y.Z`: These are release builds, automatically built from [the corresponding releases of NetBox][netbox-releases].
* `latest`: These are release builds, automatically built from [the `master` branch of NetBox][netbox-master].
* `snapshot`: These are pre-release builds, automatically built from the [`develop` branch of NetBox][netbox-develop].
* `develop-X.Y`: These are pre-release builds, automatically built from the corresponding [branch of NetBox][netbox-branches].
Then there is currently one extra tags for each of the above labels:
Then there is currently one extra tags for each of the above tags:
* `-ldap`: Contains additional dependencies and configurations for connecting Netbox to an LDAP directroy.
* `-ldap`: Contains additional dependencies and configurations for connecting NetBox to an LDAP directory.
[Learn more about that in our wiki][netbox-docker-ldap].
New images are built and published automatically every ~24h.
[netbox-releases]: https://github.com/netbox-community/netbox/releases
[netbox-master]: https://github.com/netbox-community/netbox/tree/master
[netbox-develop]: https://github.com/netbox-community/netbox/tree/develop
@ -43,83 +47,63 @@ Then there is currently one extra tags for each of the above labels:
## Quickstart
To get Netbox up and running in Docker:
To get NetBox Docker up and running run the following commands.
There is a more complete [_Getting Started_ guide on our wiki][wiki-getting-started] which explains every step.
```bash
git clone -b release https://github.com/netbox-community/netbox-docker.git
cd netbox-docker
tee docker-compose.override.yml <<EOF
version: '3.4'
services:
netbox:
ports:
- 8000:8080
EOF
docker-compose pull
docker-compose up -d
docker-compose up
```
The application will be available after a few minutes.
Use `docker-compose port nginx 8080` to find out where to connect to.
```bash
$ echo "http://$(docker-compose port nginx 8080)/"
http://0.0.0.0:32768/
# Open netbox in your default browser on macOS:
$ open "http://$(docker-compose port nginx 8080)/"
# Open netbox in your default browser on (most) linuxes:
$ xdg-open "http://$(docker-compose port nginx 8080)/" &>/dev/null &
```
Alternatively, use something like [Reception][docker-reception] to connect to _docker-compose_ projects.
The whole application will be available after a few minutes.
Open the URL `http://0.0.0.0:8000/` in a web-browser.
You should see the NetBox homepage.
In the top-right corner you can login.
The default credentials are:
* Username: **admin**
* Password: **admin**
* API Token: **0123456789abcdef0123456789abcdef01234567**
There is a more complete [Getting Started guide on our Wiki][wiki-getting-started].
[wiki-getting-started]: https://github.com/netbox-community/netbox-docker/wiki/Getting-Started
[docker-reception]: https://github.com/nxt-engineering/reception
## Documentation
Please refer [to our wiki on Github][netbox-docker-wiki] for further information on how to use this NetBox Docker image properly.
It covers advanced topics such as using files for secrets, deployment to Kubernetes, monitoring and configuring NAPALM or LDAP.
[netbox-docker-wiki]: https://github.com/netbox-community/netbox-docker/wiki/
## Getting Help
Feel free to ask questions in our [Github Community][netbox-community]
or [join our Slack][netbox-docker-slack] and ask [in our channel `#netbox-docker`][netbox-docker-slack-channel],
which is free to use and where there are almost always people online that can help you in the Slack channel.
If you need help with using NetBox or developing for it or against it's API
you may find [the `#netbox` channel][netbox-slack-channel] on the same Slack instance very helpful.
[netbox-community]: https://github.com/netbox-community/netbox-docker/discussions
## Dependencies
This project relies only on *Docker* and *docker-compose* meeting these requirements:
* The *Docker version* must be at least `17.05`.
* The *docker-compose version* must be at least `1.17.0`.
* The *Docker version* must be at least `19.03`.
* The *docker-compose version* must be at least `1.28.0`.
To check the version installed on your system run `docker --version` and `docker-compose --version`.
## Documentation
Please refer [to our wiki on Github][netbox-docker-wiki] for further information on how to use this Netbox Docker image properly.
It covers advanced topics such as using secret files, deployment to Kubernetes as well as NAPALM and LDAP configuration.
[netbox-docker-wiki]: https://github.com/netbox-community/netbox-docker/wiki/
## Netbox Version
The `docker-compose.yml` file is prepared to run a specific version of Netbox.
To use this feature, set the environment-variable `VERSION` before launching `docker-compose`, as shown below.
`VERSION` may be set to the name of
[any tag of the `netboxcommunity/netbox` Docker image on Docker Hub][netbox-dockerhub].
```bash
export VERSION=v2.7.1
docker-compose pull netbox
docker-compose up -d
```
You can also build a specific version of the Netbox Docker image yourself.
`VERSION` can be any valid [git ref][git-ref] in that case.
```bash
export VERSION=v2.7.1
./build.sh $VERSION
docker-compose up -d
```
[git-ref]: https://git-scm.com/book/en/v2/Git-Internals-Git-References
[netbox-github]: https://github.com/netbox-community/netbox/releases
## Breaking Changes
From time to time it might become necessary to re-engineer the structure of this setup.
@ -141,21 +125,16 @@ For more details on custom builds [consult our wiki][netbox-docker-wiki-build].
[netbox-docker-wiki-build]: https://github.com/netbox-community/netbox-docker/wiki/Build
### Pre-made Docker Images
New Docker images are built and published every 24h.
## Tests
We have a test script.
It runs Netbox's own unit tests and ensures that all initializers work:
It runs NetBox's own unit tests and ensures that all initializers work:
```bash
IMAGE=netboxcommunity/netbox:latest ./test.sh
```
## About
## Support
This repository is currently maintained and funded by [nxt][nxt].
[nxt]: https://nxt.engineering/en/
This repository is currently maintained by the community.
Please consider sponsoring the maintainers of this project.

View File

@ -1 +1 @@
0.22.0
1.4.1

View File

@ -1,51 +0,0 @@
#!/bin/bash
# Builds all Docker images this project provides
# Arguments:
# BUILD: The release to build.
# Allowed: release, prerelease, branches, special
# Default: undefined
echo "▶️ $0 $*"
ALL_BUILDS=("release" "prerelease" "branches" "special")
BUILDS=("${BUILD:-"${ALL_BUILDS[@]}"}")
echo "⚙️ Configured builds: ${BUILDS[*]}"
if [ -n "${DEBUG}" ]; then
export DEBUG
fi
ERROR=0
for BUILD in "${BUILDS[@]}"; do
echo "🛠 Building '$BUILD' from '$DOCKERFILE'"
case $BUILD in
release)
# build the latest release
# shellcheck disable=SC2068
./build-latest.sh $@ || ERROR=1
;;
prerelease)
# build the latest pre-release
# shellcheck disable=SC2068
PRERELEASE=true ./build-latest.sh $@ || ERROR=1
;;
branches)
# build all branches
# shellcheck disable=SC2068
./build-branches.sh $@ || ERROR=1
;;
*)
echo "🚨 Unrecognized build '$BUILD'."
if [ -z "$DEBUG" ]; then
exit 1
else
echo "⚠️ Would exit here with code '1', but DEBUG is enabled."
fi
;;
esac
done
exit $ERROR

View File

@ -1,47 +0,0 @@
#!/bin/bash
# Builds develop, develop-* and master branches of Netbox
echo "▶️ $0 $*"
###
# Checking for the presence of GITHUB_OAUTH_CLIENT_ID
# and GITHUB_OAUTH_CLIENT_SECRET
###
if [ -n "${GITHUB_OAUTH_CLIENT_ID}" ] && [ -n "${GITHUB_OAUTH_CLIENT_SECRET}" ]; then
echo "🗝 Performing authenticated Github API calls."
GITHUB_OAUTH_PARAMS="client_id=${GITHUB_OAUTH_CLIENT_ID}&client_secret=${GITHUB_OAUTH_CLIENT_SECRET}"
else
echo "🕶 Performing unauthenticated Github API calls. This might result in lower Github rate limits!"
GITHUB_OAUTH_PARAMS=""
fi
###
# Calling Github to get the all branches
###
ORIGINAL_GITHUB_REPO="${SRC_ORG-netbox-community}/${SRC_REPO-netbox}"
GITHUB_REPO="${GITHUB_REPO-$ORIGINAL_GITHUB_REPO}"
URL_RELEASES="https://api.github.com/repos/${GITHUB_REPO}/branches?${GITHUB_OAUTH_PARAMS}"
# Composing the JQ commans to extract the most recent version number
JQ_BRANCHES='map(.name) | .[] | scan("^[^v].+") | match("^(master|develop).*") | .string'
CURL="curl -sS"
# Querying the Github API to fetch all branches
BRANCHES=$($CURL "${URL_RELEASES}" | jq -r "$JQ_BRANCHES")
###
# Building each branch
###
# keeping track whether an error occured
ERROR=0
# calling build.sh for each branch
for BRANCH in $BRANCHES; do
# shellcheck disable=SC2068
./build.sh "${BRANCH}" $@ || ERROR=1
done
# returning whether an error occured
exit $ERROR

View File

@ -0,0 +1,8 @@
#!/bin/bash
push_image_to_registry() {
local target_tag=$1
echo "⏫ Pushing '${target_tag}'"
$DRY docker push "${target_tag}"
echo "✅ Finished pushing the Docker image '${target_tag}'."
}

View File

@ -0,0 +1,82 @@
#!/bin/bash
# Retrieves image configuration from public images in DockerHub
# Functions from https://gist.github.com/cirocosta/17ea17be7ac11594cb0f290b0a3ac0d1
# Optimised for our use case
get_image_label() {
local label=$1
local image=$2
local tag=$3
local token
token=$(_get_token "$image")
local digest
digest=$(_get_digest "$image" "$tag" "$token")
local retval="null"
if [ "$digest" != "null" ]; then
retval=$(_get_image_configuration "$image" "$token" "$digest" "$label")
fi
echo "$retval"
}
get_image_layers() {
local image=$1
local tag=$2
local token
token=$(_get_token "$image")
_get_layers "$image" "$tag" "$token"
}
get_image_last_layer() {
local image=$1
local tag=$2
local token
token=$(_get_token "$image")
local layers
mapfile -t layers < <(_get_layers "$image" "$tag" "$token")
echo "${layers[-1]}"
}
_get_image_configuration() {
local image=$1
local token=$2
local digest=$3
local label=$4
curl \
--silent \
--location \
--header "Authorization: Bearer $token" \
"https://registry-1.docker.io/v2/$image/blobs/$digest" |
jq -r ".config.Labels.\"$label\""
}
_get_token() {
local image=$1
curl \
--silent \
"https://auth.docker.io/token?scope=repository:$image:pull&service=registry.docker.io" |
jq -r '.token'
}
_get_digest() {
local image=$1
local tag=$2
local token=$3
curl \
--silent \
--header "Accept: application/vnd.docker.distribution.manifest.v2+json" \
--header "Authorization: Bearer $token" \
"https://registry-1.docker.io/v2/$image/manifests/$tag" |
jq -r '.config.digest'
}
_get_layers() {
local image=$1
local tag=$2
local token=$3
curl \
--silent \
--header "Accept: application/vnd.docker.distribution.manifest.v2+json" \
--header "Authorization: Bearer $token" \
"https://registry-1.docker.io/v2/$image/manifests/$tag" |
jq -r '.layers[].digest'
}

View File

@ -0,0 +1,21 @@
#!/bin/bash
###
# A regular echo, that only prints if ${GH_ACTION} is defined.
###
gh_echo() {
if [ -n "${GH_ACTION}" ]; then
echo "${@}"
fi
}
###
# Prints the output to the file defined in ${GITHUB_ENV}.
# Only executes if ${GH_ACTION} is defined.
# Example Usage: gh_env "FOO_VAR=bar_value"
###
gh_env() {
if [ -n "${GH_ACTION}" ]; then
echo "${@}" >>"${GITHUB_ENV}"
fi
}

View File

@ -19,7 +19,7 @@ fi
# Checking if PRERELEASE is either unset, 'true' or 'false'
###
if [ -n "${PRERELEASE}" ] &&
{ [ "${PRERELEASE}" != "true" ] && [ "${PRERELEASE}" != "false" ]; }; then
{ [ "${PRERELEASE}" != "true" ] && [ "${PRERELEASE}" != "false" ]; }; then
if [ -z "${DEBUG}" ]; then
echo "⚠️ PRERELEASE must be either unset, 'true' or 'false', but was '${PRERELEASE}'!"
@ -60,9 +60,10 @@ if [ "${PRERELEASE}" == "true" ]; then
# shellcheck disable=SC2003
MINOR_UNSTABLE=$(expr match "${VERSION}" 'v[0-9]\+\.\([0-9]\+\)')
if { [ "${MAJOR_STABLE}" -eq "${MAJOR_UNSTABLE}" ] \
&& [ "${MINOR_STABLE}" -ge "${MINOR_UNSTABLE}" ];
} || [ "${MAJOR_STABLE}" -gt "${MAJOR_UNSTABLE}" ]; then
if {
[ "${MAJOR_STABLE}" -eq "${MAJOR_UNSTABLE}" ] &&
[ "${MINOR_STABLE}" -ge "${MINOR_UNSTABLE}" ]
} || [ "${MAJOR_STABLE}" -gt "${MAJOR_UNSTABLE}" ]; then
echo "❎ Latest unstable version '${VERSION}' is not higher than the latest stable version '$STABLE_VERSION'."
if [ -z "$DEBUG" ]; then

221
build.sh
View File

@ -1,5 +1,5 @@
#!/bin/bash
# Clones the Netbox repository with git from Github and builds the Dockerfile
# Clones the NetBox repository with git from Github and builds the Dockerfile
echo "▶️ $0 $*"
@ -49,7 +49,7 @@ if [ "${1}x" == "x" ] || [ "${1}" == "--help" ] || [ "${1}" == "-h" ]; then
echo " DOCKERFILE The name of Dockerfile to use."
echo " Default: Dockerfile"
echo " DOCKER_FROM The base image to use."
echo " Default: Whatever is defined as default in the Dockerfile."
echo " Default: 'alpine:3.14'"
echo " DOCKER_TARGET A specific target to build."
echo " It's currently not possible to pass multiple targets."
echo " Default: main ldap"
@ -95,6 +95,8 @@ if [ "${1}x" == "x" ] || [ "${1}" == "--help" ] || [ "${1}" == "-h" ]; then
fi
fi
source ./build-functions/gh-functions.sh
###
# Enabling dry-run mode
###
@ -105,8 +107,10 @@ else
DRY="echo"
fi
gh_echo "::group::⤵️ Fetching the NetBox source code"
###
# Variables for fetching the source
# Variables for fetching the NetBox source
###
SRC_ORG="${SRC_ORG-netbox-community}"
SRC_REPO="${SRC_REPO-netbox}"
@ -115,17 +119,23 @@ URL="${URL-https://github.com/${SRC_ORG}/${SRC_REPO}.git}"
NETBOX_PATH="${NETBOX_PATH-.netbox}"
###
# Fetching the source
# Fetching the NetBox source
###
if [ "${2}" != "--push-only" ] && [ -z "${SKIP_GIT}" ] ; then
echo "🌐 Checking out '${NETBOX_BRANCH}' of netbox from the url '${URL}' into '${NETBOX_PATH}'"
if [ "${2}" != "--push-only" ] && [ -z "${SKIP_GIT}" ]; then
REMOTE_EXISTS=$(git ls-remote --heads --tags "${URL}" "${NETBOX_BRANCH}" | wc -l)
if [ "${REMOTE_EXISTS}" == "0" ]; then
echo "❌ Remote branch '${NETBOX_BRANCH}' not found in '${URL}'; Nothing to do"
gh_echo "::set-output name=skipped::true"
exit 0
fi
echo "🌐 Checking out '${NETBOX_BRANCH}' of NetBox from the url '${URL}' into '${NETBOX_PATH}'"
if [ ! -d "${NETBOX_PATH}" ]; then
$DRY git clone -q --depth 10 -b "${NETBOX_BRANCH}" "${URL}" "${NETBOX_PATH}"
fi
(
$DRY cd "${NETBOX_PATH}"
# shellcheck disable=SC2030
if [ -n "${HTTP_PROXY}" ]; then
git config http.proxy "${HTTP_PROXY}"
fi
@ -135,9 +145,12 @@ if [ "${2}" != "--push-only" ] && [ -z "${SKIP_GIT}" ] ; then
$DRY git checkout -qf FETCH_HEAD
$DRY git prune
)
echo "✅ Checked out netbox"
echo "✅ Checked out NetBox"
fi
gh_echo "::endgroup::"
gh_echo "::group::🧮 Calculating Values"
###
# Determining the value for DOCKERFILE
# and checking whether it exists
@ -153,6 +166,13 @@ if [ ! -f "${DOCKERFILE}" ]; then
fi
fi
###
# Determining the value for DOCKER_FROM
###
if [ -z "$DOCKER_FROM" ]; then
DOCKER_FROM="alpine:3.14"
fi
###
# Variables for labelling the docker image
###
@ -167,9 +187,18 @@ PROJECT_VERSION="${PROJECT_VERSION-$(sed -e 's/^[[:space:]]*//' -e 's/[[:space:]
# Get the Git information from the netbox directory
if [ -d "${NETBOX_PATH}/.git" ]; then
NETBOX_GIT_REF=$(cd ${NETBOX_PATH}; git rev-parse HEAD)
NETBOX_GIT_BRANCH=$(cd ${NETBOX_PATH}; git rev-parse --abbrev-ref HEAD)
NETBOX_GIT_URL=$(cd ${NETBOX_PATH}; git remote get-url origin)
NETBOX_GIT_REF=$(
cd "${NETBOX_PATH}"
git rev-parse HEAD
)
NETBOX_GIT_BRANCH=$(
cd "${NETBOX_PATH}"
git rev-parse --abbrev-ref HEAD
)
NETBOX_GIT_URL=$(
cd "${NETBOX_PATH}"
git remote get-url origin
)
fi
###
@ -179,26 +208,32 @@ DOCKER_REGISTRY="${DOCKER_REGISTRY-docker.io}"
DOCKER_ORG="${DOCKER_ORG-netboxcommunity}"
DOCKER_REPO="${DOCKER_REPO-netbox}"
case "${NETBOX_BRANCH}" in
master)
TAG="${TAG-latest}";;
develop)
TAG="${TAG-snapshot}";;
*)
TAG="${TAG-$NETBOX_BRANCH}";;
master)
TAG="${TAG-latest}"
;;
develop)
TAG="${TAG-snapshot}"
;;
*)
TAG="${TAG-$NETBOX_BRANCH}"
;;
esac
###
# Determine targets to build
###
DEFAULT_DOCKER_TARGETS=("main" "ldap")
DOCKER_TARGETS=( "${DOCKER_TARGET:-"${DEFAULT_DOCKER_TARGETS[@]}"}")
DOCKER_TARGETS=("${DOCKER_TARGET:-"${DEFAULT_DOCKER_TARGETS[@]}"}")
echo "🏭 Building the following targets:" "${DOCKER_TARGETS[@]}"
gh_echo "::endgroup::"
###
# Build each target
###
export DOCKER_BUILDKIT=${DOCKER_BUILDKIT-1}
for DOCKER_TARGET in "${DOCKER_TARGETS[@]}"; do
gh_echo "::group::🏗 Building the target '${DOCKER_TARGET}'"
echo "🏗 Building the target '${DOCKER_TARGET}'"
###
@ -208,31 +243,79 @@ for DOCKER_TARGET in "${DOCKER_TARGETS[@]}"; do
if [ "${DOCKER_TARGET}" != "main" ]; then
TARGET_DOCKER_TAG="${TARGET_DOCKER_TAG}-${DOCKER_TARGET}"
fi
if [ -n "${GH_ACTION}" ]; then
echo "::set-env name=FINAL_DOCKER_TAG::${TARGET_DOCKER_TAG}"
echo "::set-output name=skipped::false"
fi
TARGET_DOCKER_TAG_PROJECT="${TARGET_DOCKER_TAG}-${PROJECT_VERSION}"
gh_env "FINAL_DOCKER_TAG=${TARGET_DOCKER_TAG_PROJECT}"
gh_echo "::set-output name=skipped::false"
###
# composing the additional DOCKER_SHORT_TAG,
# i.e. "v2.6.1" becomes "v2.6",
# which is only relevant for version tags
# Also let "latest" follow the highest version
###
if [[ "${TAG}" =~ ^v([0-9]+)\.([0-9]+)\.[0-9]+$ ]]; then
MAJOR=${BASH_REMATCH[1]}
MINOR=${BASH_REMATCH[2]}
TARGET_DOCKER_SHORT_TAG="${DOCKER_SHORT_TAG-${DOCKER_REGISTRY}/${DOCKER_ORG}/${DOCKER_REPO}:v${MAJOR}.${MINOR}}"
TARGET_DOCKER_LATEST_TAG="${DOCKER_REGISTRY}/${DOCKER_ORG}/${DOCKER_REPO}:latest"
if [ "${DOCKER_TARGET}" != "main" ]; then
TARGET_DOCKER_SHORT_TAG="${TARGET_DOCKER_SHORT_TAG}-${DOCKER_TARGET}"
TARGET_DOCKER_LATEST_TAG="${TARGET_DOCKER_LATEST_TAG}-${DOCKER_TARGET}"
fi
TARGET_DOCKER_SHORT_TAG_PROJECT="${TARGET_DOCKER_SHORT_TAG}-${PROJECT_VERSION}"
TARGET_DOCKER_LATEST_TAG_PROJECT="${TARGET_DOCKER_LATEST_TAG}-${PROJECT_VERSION}"
fi
###
# Proceeding to buils stage, except if `--push-only` is passed
###
if [ "${2}" != "--push-only" ] ; then
if [ "${2}" != "--push-only" ]; then
###
# Checking if the build is necessary,
# meaning build only if one of those values changed:
# - Python base image digest (Label: PYTHON_BASE_DIGEST)
# - netbox git ref (Label: NETBOX_GIT_REF)
# - netbox-docker git ref (Label: org.label-schema.vcs-ref)
###
# Load information from registry (only for docker.io)
SHOULD_BUILD="false"
BUILD_REASON=""
if [ -z "${GH_ACTION}" ]; then
# Asuming non Github builds should always proceed
SHOULD_BUILD="true"
BUILD_REASON="${BUILD_REASON} interactive"
elif [ "$DOCKER_REGISTRY" = "docker.io" ]; then
source ./build-functions/get-public-image-config.sh
IFS=':' read -ra DOCKER_FROM_SPLIT <<<"${DOCKER_FROM}"
if ! [[ ${DOCKER_FROM_SPLIT[0]} =~ .*/.* ]]; then
# Need to use "library/..." for images the have no two part name
DOCKER_FROM_SPLIT[0]="library/${DOCKER_FROM_SPLIT[0]}"
fi
PYTHON_LAST_LAYER=$(get_image_last_layer "${DOCKER_FROM_SPLIT[0]}" "${DOCKER_FROM_SPLIT[1]}")
mapfile -t IMAGES_LAYERS_OLD < <(get_image_layers "${DOCKER_ORG}"/"${DOCKER_REPO}" "${TAG}")
NETBOX_GIT_REF_OLD=$(get_image_label NETBOX_GIT_REF "${DOCKER_ORG}"/"${DOCKER_REPO}" "${TAG}")
GIT_REF_OLD=$(get_image_label org.label-schema.vcs-ref "${DOCKER_ORG}"/"${DOCKER_REPO}" "${TAG}")
if ! printf '%s\n' "${IMAGES_LAYERS_OLD[@]}" | grep -q -P "^${PYTHON_LAST_LAYER}\$"; then
SHOULD_BUILD="true"
BUILD_REASON="${BUILD_REASON} alpine"
fi
if [ "${NETBOX_GIT_REF}" != "${NETBOX_GIT_REF_OLD}" ]; then
SHOULD_BUILD="true"
BUILD_REASON="${BUILD_REASON} netbox"
fi
if [ "${GIT_REF}" != "${GIT_REF_OLD}" ]; then
SHOULD_BUILD="true"
BUILD_REASON="${BUILD_REASON} netbox-docker"
fi
else
SHOULD_BUILD="true"
BUILD_REASON="${BUILD_REASON} no-check"
fi
###
# Composing all arguments for `docker build`
###
@ -241,71 +324,89 @@ for DOCKER_TARGET in "${DOCKER_TARGETS[@]}"; do
--target "${DOCKER_TARGET}"
-f "${DOCKERFILE}"
-t "${TARGET_DOCKER_TAG}"
-t "${TARGET_DOCKER_TAG_PROJECT}"
)
if [ -n "${TARGET_DOCKER_SHORT_TAG}" ]; then
DOCKER_BUILD_ARGS+=( -t "${TARGET_DOCKER_SHORT_TAG}" )
DOCKER_BUILD_ARGS+=(-t "${TARGET_DOCKER_SHORT_TAG}")
DOCKER_BUILD_ARGS+=(-t "${TARGET_DOCKER_SHORT_TAG_PROJECT}")
DOCKER_BUILD_ARGS+=(-t "${TARGET_DOCKER_LATEST_TAG}")
DOCKER_BUILD_ARGS+=(-t "${TARGET_DOCKER_LATEST_TAG_PROJECT}")
fi
# --label
if [ "${DOCKER_TARGET}" == "main" ]; then
DOCKER_BUILD_ARGS+=(
--label "ORIGINAL_TAG=${TARGET_DOCKER_TAG_PROJECT}"
--label "org.label-schema.build-date=${BUILD_DATE}"
--label "org.opencontainers.image.created=${BUILD_DATE}"
--label "org.label-schema.version=${PROJECT_VERSION}"
--label "org.opencontainers.image.version=${PROJECT_VERSION}"
)
if [ -d ".git" ]; then
DOCKER_BUILD_ARGS+=(
--label "ORIGINAL_TAG=${TARGET_DOCKER_TAG}"
--label "org.label-schema.build-date=${BUILD_DATE}"
--label "org.opencontainers.image.created=${BUILD_DATE}"
--label "org.label-schema.version=${PROJECT_VERSION}"
--label "org.opencontainers.image.version=${PROJECT_VERSION}"
--label "org.label-schema.vcs-ref=${GIT_REF}"
--label "org.opencontainers.image.revision=${GIT_REF}"
)
if [ -d ".git" ]; then
DOCKER_BUILD_ARGS+=(
--label "org.label-schema.vcs-ref=${GIT_REF}"
--label "org.opencontainers.image.revision=${GIT_REF}"
)
fi
if [ -d "${NETBOX_PATH}/.git" ]; then
DOCKER_BUILD_ARGS+=(
--label "NETBOX_GIT_BRANCH=${NETBOX_GIT_BRANCH}"
--label "NETBOX_GIT_REF=${NETBOX_GIT_REF}"
--label "NETBOX_GIT_URL=${NETBOX_GIT_URL}"
)
fi
fi
if [ -d "${NETBOX_PATH}/.git" ]; then
DOCKER_BUILD_ARGS+=(
--label "NETBOX_GIT_BRANCH=${NETBOX_GIT_BRANCH}"
--label "NETBOX_GIT_REF=${NETBOX_GIT_REF}"
--label "NETBOX_GIT_URL=${NETBOX_GIT_URL}"
)
fi
if [ -n "${BUILD_REASON}" ]; then
BUILD_REASON=$(sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//' <<<"$BUILD_REASON")
DOCKER_BUILD_ARGS+=(--label "BUILD_REASON=${BUILD_REASON}")
fi
# --build-arg
DOCKER_BUILD_ARGS+=( --build-arg "NETBOX_PATH=${NETBOX_PATH}" )
DOCKER_BUILD_ARGS+=(--build-arg "NETBOX_PATH=${NETBOX_PATH}")
if [ -n "${DOCKER_FROM}" ]; then
DOCKER_BUILD_ARGS+=( --build-arg "FROM=${DOCKER_FROM}" )
DOCKER_BUILD_ARGS+=(--build-arg "FROM=${DOCKER_FROM}")
fi
# shellcheck disable=SC2031
if [ -n "${HTTP_PROXY}" ]; then
DOCKER_BUILD_ARGS+=( --build-arg "http_proxy=${HTTP_PROXY}" )
DOCKER_BUILD_ARGS+=( --build-arg "https_proxy=${HTTPS_PROXY}" )
DOCKER_BUILD_ARGS+=(--build-arg "http_proxy=${HTTP_PROXY}")
DOCKER_BUILD_ARGS+=(--build-arg "https_proxy=${HTTPS_PROXY}")
fi
if [ -n "${NO_PROXY}" ]; then
DOCKER_BUILD_ARGS+=( --build-arg "no_proxy=${NO_PROXY}" )
DOCKER_BUILD_ARGS+=(--build-arg "no_proxy=${NO_PROXY}")
fi
###
# Building the docker image
###
echo "🐳 Building the Docker image '${TARGET_DOCKER_TAG}'."
$DRY docker build "${DOCKER_BUILD_ARGS[@]}" .
echo "✅ Finished building the Docker images '${TARGET_DOCKER_TAG}'"
if [ "${SHOULD_BUILD}" == "true" ]; then
echo "🐳 Building the Docker image '${TARGET_DOCKER_TAG_PROJECT}'."
echo " Build reason set to: ${BUILD_REASON}"
$DRY docker build "${DOCKER_BUILD_ARGS[@]}" .
echo "✅ Finished building the Docker images '${TARGET_DOCKER_TAG_PROJECT}'"
echo "🔎 Inspecting labels on '${TARGET_DOCKER_TAG_PROJECT}'"
$DRY docker inspect "${TARGET_DOCKER_TAG_PROJECT}" --format "{{json .Config.Labels}}"
else
echo "Build skipped because sources didn't change"
echo "::set-output name=skipped::true"
fi
fi
###
# Pushing the docker images if either `--push` or `--push-only` are passed
###
if [ "${2}" == "--push" ] || [ "${2}" == "--push-only" ] ; then
echo "⏫ Pushing '${TARGET_DOCKER_TAG}"
$DRY docker push "${TARGET_DOCKER_TAG}"
echo "✅ Finished pushing the Docker image '${TARGET_DOCKER_TAG}'."
if [ "${2}" == "--push" ] || [ "${2}" == "--push-only" ]; then
source ./build-functions/docker-functions.sh
push_image_to_registry "${TARGET_DOCKER_TAG}"
push_image_to_registry "${TARGET_DOCKER_TAG_PROJECT}"
if [ -n "${TARGET_DOCKER_SHORT_TAG}" ]; then
echo "⏫ Pushing '${TARGET_DOCKER_SHORT_TAG}'"
$DRY docker push "${TARGET_DOCKER_SHORT_TAG}"
echo "✅ Finished pushing the Docker image '${TARGET_DOCKER_SHORT_TAG}'."
push_image_to_registry "${TARGET_DOCKER_SHORT_TAG}"
push_image_to_registry "${TARGET_DOCKER_SHORT_TAG_PROJECT}"
push_image_to_registry "${TARGET_DOCKER_LATEST_TAG}"
push_image_to_registry "${TARGET_DOCKER_LATEST_TAG_PROJECT}"
fi
fi
gh_echo "::endgroup::"
done

View File

@ -1,21 +1,27 @@
import os
import re
import socket
####
## We recommend to not edit this file.
## Create separate files to overwrite the settings.
## See `extra.py` as an example.
####
# For reference see http://netbox.readthedocs.io/en/latest/configuration/mandatory-settings/
# Based on https://github.com/netbox-community/netbox/blob/develop/netbox/netbox/configuration.example.py
import re
from os import environ
from os.path import abspath, dirname, join
# For reference see https://netbox.readthedocs.io/en/stable/configuration/
# Based on https://github.com/netbox-community/netbox/blob/master/netbox/netbox/configuration.example.py
# Read secret from file
def read_secret(secret_name):
def _read_secret(secret_name, default = None):
try:
f = open('/run/secrets/' + secret_name, 'r', encoding='utf-8')
except EnvironmentError:
return ''
return default
else:
with f:
return f.readline().strip()
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
_BASE_DIR = dirname(dirname(abspath(__file__)))
#########################
# #
@ -27,47 +33,51 @@ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# access to the server via any other hostnames. The first FQDN in the list will be treated as the preferred name.
#
# Example: ALLOWED_HOSTS = ['netbox.example.com', 'netbox.internal.local']
ALLOWED_HOSTS = os.environ.get('ALLOWED_HOSTS', '*').split(' ')
ALLOWED_HOSTS = environ.get('ALLOWED_HOSTS', '*').split(' ')
# PostgreSQL database configuration.
# 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': os.environ.get('DB_NAME', 'netbox'), # Database name
'USER': os.environ.get('DB_USER', ''), # PostgreSQL username
'PASSWORD': os.environ.get('DB_PASSWORD', read_secret('db_password')),
# PostgreSQL password
'HOST': os.environ.get('DB_HOST', 'localhost'), # Database server
'PORT': os.environ.get('DB_PORT', ''), # Database port (leave blank for default)
'OPTIONS': {'sslmode': os.environ.get('DB_SSLMODE', 'prefer')},
# Database connection SSLMODE
'CONN_MAX_AGE': int(os.environ.get('DB_CONN_MAX_AGE', '300')),
# Database connection persistence
'NAME': environ.get('DB_NAME', 'netbox'), # Database name
'USER': environ.get('DB_USER', ''), # PostgreSQL username
'PASSWORD': _read_secret('db_password', environ.get('DB_PASSWORD', '')),
# PostgreSQL password
'HOST': environ.get('DB_HOST', 'localhost'), # Database server
'PORT': environ.get('DB_PORT', ''), # Database port (leave blank for default)
'OPTIONS': {'sslmode': environ.get('DB_SSLMODE', 'prefer')},
# Database connection SSLMODE
'CONN_MAX_AGE': int(environ.get('DB_CONN_MAX_AGE', '300')),
# Max database connection age
'DISABLE_SERVER_SIDE_CURSORS': environ.get('DB_DISABLE_SERVER_SIDE_CURSORS', 'False').lower() == 'true',
# Disable the use of server-side cursors transaction pooling
}
# Redis database settings. Redis is used for caching and for queuing background tasks such as webhook events. A separate
# configuration exists for each. Full connection details are required in both sections, and it is strongly recommended
# to use two separate database IDs.
REDIS = {
'tasks': {
'HOST': environ.get('REDIS_HOST', 'localhost'),
'PORT': int(environ.get('REDIS_PORT', 6379)),
'PASSWORD': _read_secret('redis_password', environ.get('REDIS_PASSWORD', '')),
'DATABASE': int(environ.get('REDIS_DATABASE', 0)),
'SSL': environ.get('REDIS_SSL', 'False').lower() == 'true',
},
'caching': {
'HOST': environ.get('REDIS_CACHE_HOST', environ.get('REDIS_HOST', 'localhost')),
'PORT': int(environ.get('REDIS_CACHE_PORT', environ.get('REDIS_PORT', 6379))),
'PASSWORD': _read_secret('redis_cache_password', environ.get('REDIS_CACHE_PASSWORD', environ.get('REDIS_PASSWORD', ''))),
'DATABASE': int(environ.get('REDIS_CACHE_DATABASE', 1)),
'SSL': environ.get('REDIS_CACHE_SSL', environ.get('REDIS_SSL', 'False')).lower() == 'true',
},
}
# This key is used for secure generation of random numbers and strings. It must never be exposed outside of this file.
# For optimal security, SECRET_KEY should be at least 50 characters in length and contain a mix of letters, numbers, and
# symbols. NetBox will not run without this defined. For more information, see
# https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-SECRET_KEY
SECRET_KEY = os.environ.get('SECRET_KEY', read_secret('secret_key'))
# https://docs.djangoproject.com/en/stable/ref/settings/#std:setting-SECRET_KEY
SECRET_KEY = _read_secret('secret_key', environ.get('SECRET_KEY', ''))
# Redis database settings. The Redis database is used for caching and background processing such as webhooks
REDIS = {
'webhooks': {
'HOST': os.environ.get('REDIS_HOST', 'localhost'),
'PORT': int(os.environ.get('REDIS_PORT', 6379)),
'PASSWORD': os.environ.get('REDIS_PASSWORD', read_secret('redis_password')),
'DATABASE': int(os.environ.get('REDIS_DATABASE', 0)),
'DEFAULT_TIMEOUT': int(os.environ.get('REDIS_TIMEOUT', 300)),
'SSL': os.environ.get('REDIS_SSL', 'False').lower() == 'true',
},
'caching': {
'HOST': os.environ.get('REDIS_CACHE_HOST', os.environ.get('REDIS_HOST', 'localhost')),
'PORT': int(os.environ.get('REDIS_CACHE_PORT', os.environ.get('REDIS_PORT', 6379))),
'PASSWORD': os.environ.get('REDIS_CACHE_PASSWORD', os.environ.get('REDIS_PASSWORD', read_secret('redis_cache_password'))),
'DATABASE': int(os.environ.get('REDIS_CACHE_DATABASE', 1)),
'DEFAULT_TIMEOUT': int(os.environ.get('REDIS_CACHE_TIMEOUT', os.environ.get('REDIS_TIMEOUT', 300))),
'SSL': os.environ.get('REDIS_CACHE_SSL', os.environ.get('REDIS_SSL', 'False')).lower() == 'true',
},
}
#########################
# #
@ -81,111 +91,153 @@ ADMINS = [
# ['John Doe', 'jdoe@example.com'],
]
# URL schemes that are allowed within links in NetBox
ALLOWED_URL_SCHEMES = (
'file', 'ftp', 'ftps', 'http', 'https', 'irc', 'mailto', 'sftp', 'ssh', 'tel', 'telnet', 'tftp', 'vnc', 'xmpp',
)
# Optionally display a persistent banner at the top and/or bottom of every page. HTML is allowed. To display the same
# content in both banners, define BANNER_TOP and set BANNER_BOTTOM = BANNER_TOP.
BANNER_TOP = os.environ.get('BANNER_TOP', '')
BANNER_BOTTOM = os.environ.get('BANNER_BOTTOM', '')
BANNER_TOP = environ.get('BANNER_TOP', '')
BANNER_BOTTOM = environ.get('BANNER_BOTTOM', '')
# Text to include on the login page above the login form. HTML is allowed.
BANNER_LOGIN = os.environ.get('BANNER_LOGIN', '')
BANNER_LOGIN = environ.get('BANNER_LOGIN', '')
# Base URL path if accessing NetBox within a directory. For example, if installed at http://example.com/netbox/, set:
# BASE_PATH = 'netbox/'
BASE_PATH = os.environ.get('BASE_PATH', '')
# Cache timeout in seconds. Set to 0 to dissable caching. Defaults to 900 (15 minutes)
CACHE_TIMEOUT = int(os.environ.get('CACHE_TIMEOUT', 900))
BASE_PATH = environ.get('BASE_PATH', '')
# Maximum number of days to retain logged changes. Set to 0 to retain changes indefinitely. (Default: 90)
CHANGELOG_RETENTION = int(os.environ.get('CHANGELOG_RETENTION', 90))
CHANGELOG_RETENTION = int(environ.get('CHANGELOG_RETENTION', 90))
# API Cross-Origin Resource Sharing (CORS) settings. If CORS_ORIGIN_ALLOW_ALL is set to True, all origins will be
# allowed. Otherwise, define a list of allowed origins using either CORS_ORIGIN_WHITELIST or
# CORS_ORIGIN_REGEX_WHITELIST. For more information, see https://github.com/ottoyiu/django-cors-headers
CORS_ORIGIN_ALLOW_ALL = os.environ.get('CORS_ORIGIN_ALLOW_ALL', 'False').lower() == 'true'
CORS_ORIGIN_WHITELIST = list(filter(None, os.environ.get('CORS_ORIGIN_WHITELIST', 'https://localhost').split(' ')))
CORS_ORIGIN_REGEX_WHITELIST = [re.compile(r) for r in list(filter(None, os.environ.get('CORS_ORIGIN_REGEX_WHITELIST', '').split(' ')))]
CORS_ORIGIN_ALLOW_ALL = environ.get('CORS_ORIGIN_ALLOW_ALL', 'False').lower() == 'true'
CORS_ORIGIN_WHITELIST = list(filter(None, environ.get('CORS_ORIGIN_WHITELIST', 'https://localhost').split(' ')))
CORS_ORIGIN_REGEX_WHITELIST = [re.compile(r) for r in list(filter(None, environ.get('CORS_ORIGIN_REGEX_WHITELIST', '').split(' ')))]
# Set to True to enable server debugging. WARNING: Debugging introduces a substantial performance penalty and may reveal
# sensitive information about your installation. Only enable debugging while performing testing. Never enable debugging
# on a production system.
DEBUG = os.environ.get('DEBUG', 'False').lower() == 'true'
DEBUG = environ.get('DEBUG', 'False').lower() == 'true'
# Email settings
EMAIL = {
'SERVER': os.environ.get('EMAIL_SERVER', 'localhost'),
'PORT': int(os.environ.get('EMAIL_PORT', 25)),
'USERNAME': os.environ.get('EMAIL_USERNAME', ''),
'PASSWORD': os.environ.get('EMAIL_PASSWORD', read_secret('email_password')),
'TIMEOUT': int(os.environ.get('EMAIL_TIMEOUT', 10)), # seconds
'FROM_EMAIL': os.environ.get('EMAIL_FROM', ''),
'SERVER': environ.get('EMAIL_SERVER', 'localhost'),
'PORT': int(environ.get('EMAIL_PORT', 25)),
'USERNAME': environ.get('EMAIL_USERNAME', ''),
'PASSWORD': _read_secret('email_password', environ.get('EMAIL_PASSWORD', '')),
'USE_SSL': environ.get('EMAIL_USE_SSL', 'False').lower() == 'true',
'USE_TLS': environ.get('EMAIL_USE_TLS', 'False').lower() == 'true',
'SSL_CERTFILE': environ.get('EMAIL_SSL_CERTFILE', ''),
'SSL_KEYFILE': environ.get('EMAIL_SSL_KEYFILE', ''),
'TIMEOUT': int(environ.get('EMAIL_TIMEOUT', 10)), # seconds
'FROM_EMAIL': environ.get('EMAIL_FROM', ''),
}
# Enforcement of unique IP space can be toggled on a per-VRF basis.
# To enforce unique IP space within the global table (all prefixes and IP addresses not assigned to a VRF),
# set ENFORCE_GLOBAL_UNIQUE to True.
ENFORCE_GLOBAL_UNIQUE = os.environ.get('ENFORCE_GLOBAL_UNIQUE', 'False').lower() == 'true'
# Enforcement of unique IP space can be toggled on a per-VRF basis. To enforce unique IP space within the global table
# (all prefixes and IP addresses not assigned to a VRF), set ENFORCE_GLOBAL_UNIQUE to True.
ENFORCE_GLOBAL_UNIQUE = environ.get('ENFORCE_GLOBAL_UNIQUE', 'False').lower() == 'true'
# Exempt certain models from the enforcement of view permissions. Models listed here will be viewable by all users and
# by anonymous users. List models in the form `<app>.<model>`. Add '*' to this list to exempt all models.
EXEMPT_VIEW_PERMISSIONS = list(filter(None, os.environ.get('EXEMPT_VIEW_PERMISSIONS', '').split(' ')))
EXEMPT_VIEW_PERMISSIONS = list(filter(None, environ.get('EXEMPT_VIEW_PERMISSIONS', '').split(' ')))
# Enable custom logging. Please see the Django documentation for detailed guidance on configuring custom logs:
# https://docs.djangoproject.com/en/1.11/topics/logging/
# https://docs.djangoproject.com/en/stable/topics/logging/
LOGGING = {}
# Setting this to True will permit only authenticated users to access any part of NetBox. By default, anonymous users
# are permitted to access most data in NetBox (excluding secrets) but not make any changes.
LOGIN_REQUIRED = os.environ.get('LOGIN_REQUIRED', 'False').lower() == 'true'
LOGIN_REQUIRED = environ.get('LOGIN_REQUIRED', 'False').lower() == 'true'
# The length of time (in seconds) for which a user will remain logged into the web UI before being prompted to
# re-authenticate. (Default: 1209600 [14 days])
LOGIN_TIMEOUT = int(environ.get('LOGIN_TIMEOUT', 1209600))
# Setting this to True will display a "maintenance mode" banner at the top of every page.
MAINTENANCE_MODE = os.environ.get('MAINTENANCE_MODE', 'False').lower() == 'true'
MAINTENANCE_MODE = environ.get('MAINTENANCE_MODE', 'False').lower() == 'true'
# An API consumer can request an arbitrary number of objects =by appending the "limit" parameter to the URL (e.g.
# "?limit=1000"). This setting defines the maximum limit. Setting it to 0 or None will allow an API consumer to request
# all objects by specifying "?limit=0".
MAX_PAGE_SIZE = int(os.environ.get('MAX_PAGE_SIZE', 1000))
MAX_PAGE_SIZE = int(environ.get('MAX_PAGE_SIZE', 1000))
# The file path where uploaded media such as image attachments are stored. A trailing slash is not needed. Note that
# the default value of this setting is derived from the installed location.
MEDIA_ROOT = os.environ.get('MEDIA_ROOT', os.path.join(BASE_DIR, 'media'))
MEDIA_ROOT = environ.get('MEDIA_ROOT', join(_BASE_DIR, 'media'))
# Expose Prometheus monitoring metrics at the HTTP endpoint '/metrics'
METRICS_ENABLED = os.environ.get('METRICS_ENABLED', 'False').lower() == 'true'
METRICS_ENABLED = environ.get('METRICS_ENABLED', 'False').lower() == 'true'
# Credentials that NetBox will use to access live devices.
NAPALM_USERNAME = os.environ.get('NAPALM_USERNAME', '')
NAPALM_PASSWORD = os.environ.get('NAPALM_PASSWORD', read_secret('napalm_password'))
# Credentials that NetBox will uses to authenticate to devices when connecting via NAPALM.
NAPALM_USERNAME = environ.get('NAPALM_USERNAME', '')
NAPALM_PASSWORD = _read_secret('napalm_password', environ.get('NAPALM_PASSWORD', ''))
# NAPALM timeout (in seconds). (Default: 30)
NAPALM_TIMEOUT = int(os.environ.get('NAPALM_TIMEOUT', 30))
NAPALM_TIMEOUT = int(environ.get('NAPALM_TIMEOUT', 30))
# NAPALM optional arguments (see http://napalm.readthedocs.io/en/latest/support/#optional-arguments). Arguments must
# be provided as a dictionary.
NAPALM_ARGS = {}
# Determine how many objects to display per page within a list. (Default: 50)
PAGINATE_COUNT = int(os.environ.get('PAGINATE_COUNT', 50))
PAGINATE_COUNT = int(environ.get('PAGINATE_COUNT', 50))
# Enable installed plugins. Add the name of each plugin to the list.
PLUGINS = []
# Plugins configuration settings. These settings are used by various plugins that the user may have installed.
# Each key in the dictionary is the name of an installed plugin and its value is a dictionary of settings.
PLUGINS_CONFIG = {
}
# When determining the primary IP address for a device, IPv6 is preferred over IPv4 by default. Set this to True to
# prefer IPv4 instead.
PREFER_IPV4 = os.environ.get('PREFER_IPV4', 'False').lower() == 'true'
PREFER_IPV4 = environ.get('PREFER_IPV4', 'False').lower() == 'true'
# Rack elevation size defaults, in pixels. For best results, the ratio of width to height should be roughly 10:1.
RACK_ELEVATION_DEFAULT_UNIT_HEIGHT = int(environ.get('RACK_ELEVATION_DEFAULT_UNIT_HEIGHT', 22))
RACK_ELEVATION_DEFAULT_UNIT_WIDTH = int(environ.get('RACK_ELEVATION_DEFAULT_UNIT_WIDTH', 220))
# Remote authentication support
REMOTE_AUTH_ENABLED = environ.get('REMOTE_AUTH_ENABLED', 'False').lower() == 'true'
REMOTE_AUTH_BACKEND = environ.get('REMOTE_AUTH_BACKEND', 'netbox.authentication.RemoteUserBackend')
REMOTE_AUTH_HEADER = environ.get('REMOTE_AUTH_HEADER', 'HTTP_REMOTE_USER')
REMOTE_AUTH_AUTO_CREATE_USER = environ.get('REMOTE_AUTH_AUTO_CREATE_USER', 'True').lower() == 'true'
REMOTE_AUTH_DEFAULT_GROUPS = list(filter(None, environ.get('REMOTE_AUTH_DEFAULT_GROUPS', '').split(' ')))
# This repository is used to check whether there is a new release of NetBox available. Set to None to disable the
# version check or use the URL below to check for release in the official NetBox repository.
# https://api.github.com/repos/netbox-community/netbox/releases
RELEASE_CHECK_URL = environ.get('RELEASE_CHECK_URL', None)
# The file path where custom reports will be stored. A trailing slash is not needed. Note that the default value of
# this setting is derived from the installed location.
REPORTS_ROOT = os.environ.get('REPORTS_ROOT', '/etc/netbox/reports')
REPORTS_ROOT = environ.get('REPORTS_ROOT', '/etc/netbox/reports')
# Maximum execution time for background tasks, in seconds.
RQ_DEFAULT_TIMEOUT = int(environ.get('RQ_DEFAULT_TIMEOUT', 300))
# The file path where custom scripts will be stored. A trailing slash is not needed. Note that the default value of
# this setting is derived from the installed location.
SCRIPTS_ROOT = os.environ.get('SCRIPTS_ROOT', '/etc/netbox/scripts')
SCRIPTS_ROOT = environ.get('SCRIPTS_ROOT', '/etc/netbox/scripts')
# By default, NetBox will store session data in the database. Alternatively, a file path can be specified here to use
# local file storage instead. (This can be useful for enabling authentication on a standby instance with read-only
# database access.) Note that the user as which NetBox runs must have read and write permissions to this path.
SESSION_FILE_PATH = environ.get('SESSIONS_ROOT', None)
# Time zone (default: UTC)
TIME_ZONE = os.environ.get('TIME_ZONE', 'UTC')
TIME_ZONE = environ.get('TIME_ZONE', 'UTC')
# Date/time formatting. See the following link for supported formats:
# https://docs.djangoproject.com/en/dev/ref/templates/builtins/#date
DATE_FORMAT = os.environ.get('DATE_FORMAT', 'N j, Y')
SHORT_DATE_FORMAT = os.environ.get('SHORT_DATE_FORMAT', 'Y-m-d')
TIME_FORMAT = os.environ.get('TIME_FORMAT', 'g:i a')
SHORT_TIME_FORMAT = os.environ.get('SHORT_TIME_FORMAT', 'H:i:s')
DATETIME_FORMAT = os.environ.get('DATETIME_FORMAT', 'N j, Y g:i a')
SHORT_DATETIME_FORMAT = os.environ.get('SHORT_DATETIME_FORMAT', 'Y-m-d H:i')
# https://docs.djangoproject.com/en/stable/ref/templates/builtins/#date
DATE_FORMAT = environ.get('DATE_FORMAT', 'N j, Y')
SHORT_DATE_FORMAT = environ.get('SHORT_DATE_FORMAT', 'Y-m-d')
TIME_FORMAT = environ.get('TIME_FORMAT', 'g:i a')
SHORT_TIME_FORMAT = environ.get('SHORT_TIME_FORMAT', 'H:i:s')
DATETIME_FORMAT = environ.get('DATETIME_FORMAT', 'N j, Y g:i a')
SHORT_DATETIME_FORMAT = environ.get('SHORT_DATETIME_FORMAT', 'Y-m-d H:i')

55
configuration/extra.py Normal file
View File

@ -0,0 +1,55 @@
####
## This file contains extra configuration options that can't be configured
## directly through environment variables.
####
## Specify one or more name and email address tuples representing NetBox administrators. These people will be notified of
## application errors (assuming correct email settings are provided).
# ADMINS = [
# # ['John Doe', 'jdoe@example.com'],
# ]
## URL schemes that are allowed within links in NetBox
# ALLOWED_URL_SCHEMES = (
# 'file', 'ftp', 'ftps', 'http', 'https', 'irc', 'mailto', 'sftp', 'ssh', 'tel', 'telnet', 'tftp', 'vnc', 'xmpp',
# )
## NAPALM optional arguments (see http://napalm.readthedocs.io/en/latest/support/#optional-arguments). Arguments must
## be provided as a dictionary.
# NAPALM_ARGS = {}
## Enable installed plugins. Add the name of each plugin to the list.
# from netbox.configuration.configuration import PLUGINS
# PLUGINS.append('my_plugin')
## Plugins configuration settings. These settings are used by various plugins that the user may have installed.
## Each key in the dictionary is the name of an installed plugin and its value is a dictionary of settings.
# from netbox.configuration.configuration import PLUGINS_CONFIG
# PLUGINS_CONFIG['my_plugin'] = {
# 'foo': 'bar',
# 'buzz': 'bazz'
# }
## Remote authentication support
# REMOTE_AUTH_DEFAULT_PERMISSIONS = {}
## By default uploaded media is stored on the local filesystem. Using Django-storages is also supported. Provide the
## class path of the storage driver in STORAGE_BACKEND and any configuration options in STORAGE_CONFIG. For example:
# STORAGE_BACKEND = 'storages.backends.s3boto3.S3Boto3Storage'
# STORAGE_CONFIG = {
# 'AWS_ACCESS_KEY_ID': 'Key ID',
# 'AWS_SECRET_ACCESS_KEY': 'Secret',
# 'AWS_STORAGE_BUCKET_NAME': 'netbox',
# 'AWS_S3_REGION_NAME': 'eu-west-1',
# }
## This file can contain arbitrary Python code, e.g.:
# from datetime import datetime
# now = datetime.now().strftime("%d/%m/%Y %H:%M:%S")
# BANNER_TOP = f'<marquee width="200px">This instance started on {now}.</marquee>'

View File

@ -1,8 +0,0 @@
command = '/usr/bin/gunicorn'
pythonpath = '/opt/netbox/netbox'
bind = '0.0.0.0:8001'
workers = 3
errorlog = '-'
accesslog = '-'
capture_output = False
loglevel = 'debug'

View File

@ -0,0 +1,28 @@
####
## 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"]

View File

@ -0,0 +1,90 @@
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 users 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')
}

View File

@ -1,80 +0,0 @@
import ldap
import os
from django_auth_ldap.config import LDAPSearch
from importlib import import_module
# Read secret from file
def read_secret(secret_name):
try:
f = open('/run/secrets/' + secret_name, 'r', encoding='utf-8')
except EnvironmentError:
return ''
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 = os.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 = os.environ.get('AUTH_LDAP_BIND_DN', '')
AUTH_LDAP_BIND_PASSWORD = os.environ.get('AUTH_LDAP_BIND_PASSWORD', read_secret('auth_ldap_bind_password'))
# Set a string template that describes any users distinguished name based on the username.
AUTH_LDAP_USER_DN_TEMPLATE = os.environ.get('AUTH_LDAP_USER_DN_TEMPLATE', None)
# 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 = os.environ.get('LDAP_IGNORE_CERT_ERRORS', 'False').lower() == 'true'
AUTH_LDAP_USER_SEARCH_BASEDN = os.environ.get('AUTH_LDAP_USER_SEARCH_BASEDN', '')
AUTH_LDAP_USER_SEARCH_ATTR = os.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 = os.environ.get('AUTH_LDAP_GROUP_SEARCH_BASEDN', '')
AUTH_LDAP_GROUP_SEARCH_CLASS = os.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(os.environ.get('AUTH_LDAP_GROUP_TYPE', 'GroupOfNamesType'))
# Define a group required to login.
AUTH_LDAP_REQUIRE_GROUP = os.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 = {
"is_active": os.environ.get('AUTH_LDAP_REQUIRE_GROUP_DN', ''),
"is_staff": os.environ.get('AUTH_LDAP_IS_ADMIN_DN', ''),
"is_superuser": os.environ.get('AUTH_LDAP_IS_SUPERUSER_DN', '')
}
# For more granular permissions, we can map LDAP groups to Django groups.
AUTH_LDAP_FIND_GROUP_PERMS = os.environ.get('AUTH_LDAP_FIND_GROUP_PERMS', 'True').lower() == 'true'
# Cache groups for one hour to reduce LDAP traffic
AUTH_LDAP_CACHE_TIMEOUT = int(os.environ.get('AUTH_LDAP_CACHE_TIMEOUT', 3600))
# Populate the Django user from the LDAP directory.
AUTH_LDAP_USER_ATTR_MAP = {
"first_name": os.environ.get('AUTH_LDAP_ATTR_FIRSTNAME', 'givenName'),
"last_name": os.environ.get('AUTH_LDAP_ATTR_LASTNAME', 'sn'),
"email": os.environ.get('AUTH_LDAP_ATTR_MAIL', 'mail')
}

55
configuration/logging.py Normal file
View File

@ -0,0 +1,55 @@
# # Remove first comment(#) on each line to implement this working logging example.
# # Add LOGLEVEL environment variable to netbox if you use this example & want a different log level.
# from os import environ
# # Set LOGLEVEL in netbox.env or docker-compose.overide.yml to override a logging level of INFO.
# LOGLEVEL = environ.get('LOGLEVEL', 'INFO')
# LOGGING = {
# 'version': 1,
# 'disable_existing_loggers': False,
# 'formatters': {
# 'verbose': {
# 'format': '{levelname} {asctime} {module} {process:d} {thread:d} {message}',
# 'style': '{',
# },
# 'simple': {
# 'format': '{levelname} {message}',
# 'style': '{',
# },
# },
# 'filters': {
# 'require_debug_false': {
# '()': 'django.utils.log.RequireDebugFalse',
# },
# },
# 'handlers': {
# 'console': {
# 'level': LOGLEVEL,
# 'filters': ['require_debug_false'],
# 'class': 'logging.StreamHandler',
# 'formatter': 'simple'
# },
# 'mail_admins': {
# 'level': 'ERROR',
# 'class': 'django.utils.log.AdminEmailHandler',
# 'filters': ['require_debug_false']
# }
# },
# 'loggers': {
# 'django': {
# 'handlers': ['console'],
# 'propagate': True,
# },
# 'django.request': {
# 'handlers': ['mail_admins'],
# 'level': 'ERROR',
# 'propagate': False,
# },
# 'django_auth_ldap': {
# 'handlers': ['console',],
# 'level': LOGLEVEL,
# }
# }
# }

13
configuration/plugins.py Normal file
View File

@ -0,0 +1,13 @@
# Add your plugins and plugin settings here.
# Of course uncomment this file out.
# To learn how to build images with your required plugins
# See https://github.com/netbox-community/netbox-docker/wiki/Using-Netbox-Plugins
# PLUGINS = ["netbox_bgp"]
# PLUGINS_CONFIG = {
# "netbox_bgp": {
# ADD YOUR SETTINGS HERE
# }
# }

View File

@ -0,0 +1,5 @@
version: '3.4'
services:
netbox:
ports:
- 8000:8080

View File

@ -5,41 +5,35 @@ services:
depends_on:
- postgres
- redis
- redis-cache
env_file: env/netbox.env
user: '101'
environment:
SKIP_STARTUP_SCRIPTS: ${SKIP_STARTUP_SCRIPTS-false}
user: 'unit:root'
volumes:
- ./startup_scripts:/opt/netbox/startup_scripts:z,ro
- ./${INITIALIZERS_DIR-initializers}:/opt/netbox/initializers:z,ro
- ./configuration:/etc/netbox/config:z,ro
- ./reports:/etc/netbox/reports:z,ro
- ./scripts:/etc/netbox/scripts:z,ro
- netbox-nginx-config:/etc/netbox-nginx:z
- netbox-static-files:/opt/netbox/netbox/static:z
- netbox-media-files:/opt/netbox/netbox/media:z
nginx:
command: nginx -c /etc/netbox-nginx/nginx.conf
image: nginx:1.17-alpine
depends_on:
- netbox
ports:
- 8080
volumes:
- netbox-static-files:/opt/netbox/netbox/static:ro
- netbox-nginx-config:/etc/netbox-nginx/:ro
postgres:
image: postgres:11-alpine
image: postgres:13-alpine
env_file: env/postgres.env
redis:
image: redis:5-alpine
image: redis:6-alpine
command:
- sh
- -c # this is to evaluate the $REDIS_PASSWORD from the env
- redis-server --appendonly yes --requirepass $$REDIS_PASSWORD ## $$ because of docker-compose
env_file: env/redis.env
redis-cache:
image: redis:6-alpine
command:
- sh
- -c # this is to evaluate the $REDIS_PASSWORD from the env
- redis-server --requirepass $$REDIS_PASSWORD ## $$ because of docker-compose
env_file: env/redis.env
env_file: env/redis-cache.env
volumes:
netbox-static-files:
driver: local
netbox-nginx-config:
driver: local
netbox-media-files:
driver: local

View File

@ -1,49 +1,48 @@
version: '3.4'
services:
netbox: &netbox
image: netboxcommunity/netbox:${VERSION-latest}
image: netboxcommunity/netbox:${VERSION-v3.0-1.4.1}
depends_on:
- postgres
- redis
- redis-cache
- netbox-worker
env_file: env/netbox.env
user: '101'
user: 'unit:root'
volumes:
- ./startup_scripts:/opt/netbox/startup_scripts:z,ro
- ./initializers:/opt/netbox/initializers:z,ro
- ./configuration:/etc/netbox/config:z,ro
- ./reports:/etc/netbox/reports:z,ro
- ./scripts:/etc/netbox/scripts:z,ro
- netbox-nginx-config:/etc/netbox-nginx:z
- netbox-static-files:/opt/netbox/netbox/static:z
- netbox-media-files:/opt/netbox/netbox/media:z
netbox-worker:
<<: *netbox
depends_on:
- redis
entrypoint:
- python3
- /opt/netbox/netbox/manage.py
- postgres
command:
- /opt/netbox/venv/bin/python
- /opt/netbox/netbox/manage.py
- rqworker
nginx:
command: nginx -c /etc/netbox-nginx/nginx.conf
image: nginx:1.17-alpine
netbox-housekeeping:
<<: *netbox
depends_on:
- netbox
ports:
- 8080
volumes:
- netbox-static-files:/opt/netbox/netbox/static:ro
- netbox-nginx-config:/etc/netbox-nginx/:ro
- redis
- postgres
command:
- /opt/netbox/housekeeping.sh
# postgres
postgres:
image: postgres:11-alpine
image: postgres:13-alpine
env_file: env/postgres.env
volumes:
- netbox-postgres-data:/var/lib/postgresql/data
# redis
redis:
image: redis:5-alpine
image: redis:6-alpine
command:
- sh
- -c # this is to evaluate the $REDIS_PASSWORD from the env
@ -52,17 +51,14 @@ services:
volumes:
- netbox-redis-data:/data
redis-cache:
image: redis:5-alpine
image: redis:6-alpine
command:
- sh
- -c # this is to evaluate the $REDIS_PASSWORD from the env
- redis-server --requirepass $$REDIS_PASSWORD ## $$ because of docker-compose
env_file: env/redis.env
env_file: env/redis-cache.env
volumes:
netbox-static-files:
driver: local
netbox-nginx-config:
driver: local
netbox-media-files:
driver: local
netbox-postgres-data:

View File

@ -1,10 +1,84 @@
## Generic Parts
# These functions are providing the functionality to load
# arbitrary configuration files.
#
# They can be imported by other code (see `ldap_config.py` for an example).
import importlib.util
import sys
from os import scandir
from os.path import abspath, isfile
try:
spec = importlib.util.spec_from_file_location('configuration', '/etc/netbox/config/configuration.py')
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
sys.modules['netbox.configuration'] = module
except:
raise ImportError('')
def _filename(f):
return f.name
def _import(module_name, path, loaded_configurations):
spec = importlib.util.spec_from_file_location("", path)
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
sys.modules[module_name] = module
loaded_configurations.insert(0, module)
print(f"🧬 loaded config '{path}'")
def read_configurations(config_module, config_dir, main_config):
loaded_configurations = []
main_config_path = abspath(f"{config_dir}/{main_config}.py")
if isfile(main_config_path):
_import(f"{config_module}.{main_config}", main_config_path, loaded_configurations)
else:
print(f"⚠️ Main configuration '{main_config_path}' not found.")
with scandir(config_dir) as it:
for f in sorted(it, key=_filename):
if not f.is_file():
continue
if f.name.startswith("__"):
continue
if not f.name.endswith(".py"):
continue
if f.name == f"{main_config}.py":
continue
if f.name == f"{config_dir}.py":
continue
module_name = f"{config_module}.{f.name[:-len('.py')]}".replace(".", "_")
_import(module_name, f.path, loaded_configurations)
if len(loaded_configurations) == 0:
print(f"‼️ No configuration files found in '{config_dir}'.")
raise ImportError(f"No configuration files found in '{config_dir}'.")
return loaded_configurations
## Specific Parts
# This section's code actually loads the various configuration files
# into the module with the given name.
# It contains the logic to resolve arbitrary configuration options by
# levaraging dynamic programming using `__getattr__`.
_loaded_configurations = read_configurations(
config_dir="/etc/netbox/config/",
config_module="netbox.configuration",
main_config="configuration",
)
def __getattr__(name):
for config in _loaded_configurations:
try:
return getattr(config, name)
except:
pass
raise AttributeError

View File

@ -1,25 +1,52 @@
#!/bin/bash
# Runs on every start of the Netbox Docker container
# Runs on every start of the NetBox Docker container
# Stop when an error occures
set -e
# Allows Netbox to be run as non-root users
# Allows NetBox to be run as non-root users
umask 002
# Load correct Python3 env
# shellcheck disable=SC1091
source /opt/netbox/venv/bin/activate
# Try to connect to the DB
DB_WAIT_TIMEOUT=${DB_WAIT_TIMEOUT-3}
MAX_DB_WAIT_TIME=${MAX_DB_WAIT_TIME-30}
CUR_DB_WAIT_TIME=0
while ! ./manage.py migrate 2>&1 && [ "${CUR_DB_WAIT_TIME}" -lt "${MAX_DB_WAIT_TIME}" ]; do
while [ "${CUR_DB_WAIT_TIME}" -lt "${MAX_DB_WAIT_TIME}" ]; do
# Read and truncate connection error tracebacks to last line by default
exec {psfd}< <(./manage.py showmigrations 2>&1)
read -rd '' DB_ERR <&$psfd || :
exec {psfd}<&-
wait $! && break
if [ -n "$DB_WAIT_DEBUG" ]; then
echo "$DB_ERR"
else
readarray -tn 0 DB_ERR_LINES <<<"$DB_ERR"
echo "${DB_ERR_LINES[@]: -1}"
echo "[ Use DB_WAIT_DEBUG=1 in netbox.env to print full traceback for errors here ]"
fi
echo "⏳ Waiting on DB... (${CUR_DB_WAIT_TIME}s / ${MAX_DB_WAIT_TIME}s)"
sleep "${DB_WAIT_TIMEOUT}"
CUR_DB_WAIT_TIME=$(( CUR_DB_WAIT_TIME + DB_WAIT_TIMEOUT ))
CUR_DB_WAIT_TIME=$((CUR_DB_WAIT_TIME + DB_WAIT_TIMEOUT))
done
if [ "${CUR_DB_WAIT_TIME}" -ge "${MAX_DB_WAIT_TIME}" ]; then
echo "❌ Waited ${MAX_DB_WAIT_TIME}s or more for the DB to become ready."
exit 1
fi
# Check if update is needed
if ! ./manage.py migrate --check >/dev/null 2>&1; then
echo "⚙️ Applying database migrations"
./manage.py migrate --no-input
echo "⚙️ Running trace_paths"
./manage.py trace_paths --no-input
echo "⚙️ Removing stale content types"
./manage.py remove_stale_contenttypes --no-input
echo "⚙️ Removing expired user sessions"
./manage.py clearsessions
fi
# Create Superuser if required
if [ "$SKIP_SUPERUSER" == "true" ]; then
@ -31,22 +58,18 @@ else
if [ -z ${SUPERUSER_EMAIL+x} ]; then
SUPERUSER_EMAIL='admin@example.com'
fi
if [ -z ${SUPERUSER_PASSWORD+x} ]; then
if [ -f "/run/secrets/superuser_password" ]; then
SUPERUSER_PASSWORD="$(< /run/secrets/superuser_password)"
else
SUPERUSER_PASSWORD='admin'
fi
if [ -f "/run/secrets/superuser_password" ]; then
SUPERUSER_PASSWORD="$(</run/secrets/superuser_password)"
elif [ -z ${SUPERUSER_PASSWORD+x} ]; then
SUPERUSER_PASSWORD='admin'
fi
if [ -z ${SUPERUSER_API_TOKEN+x} ]; then
if [ -f "/run/secrets/superuser_api_token" ]; then
SUPERUSER_API_TOKEN="$(< /run/secrets/superuser_api_token)"
else
SUPERUSER_API_TOKEN='0123456789abcdef0123456789abcdef01234567'
fi
if [ -f "/run/secrets/superuser_api_token" ]; then
SUPERUSER_API_TOKEN="$(</run/secrets/superuser_api_token)"
elif [ -z ${SUPERUSER_API_TOKEN+x} ]; then
SUPERUSER_API_TOKEN='0123456789abcdef0123456789abcdef01234567'
fi
./manage.py shell --interface python << END
./manage.py shell --interface python <<END
from django.contrib.auth.models import User
from users.models import Token
if not User.objects.filter(username='${SUPERUSER_NAME}'):
@ -64,13 +87,8 @@ else
echo "import runpy; runpy.run_path('../startup_scripts')" | ./manage.py shell --interface python
fi
# Copy static files
./manage.py collectstatic --no-input
echo "✅ Initialisation is done."
# Launch whatever is passed by docker
# (i.e. the RUN instruction in the Dockerfile)
#
# shellcheck disable=SC2068
exec $@
exec "$@"

8
docker/housekeeping.sh Executable file
View File

@ -0,0 +1,8 @@
#!/bin/bash
SECONDS=${HOUSEKEEPING_INTERVAL:=86400}
echo "Interval set to ${SECONDS} seconds"
while true; do
date
/opt/netbox/venv/bin/python /opt/netbox/netbox/manage.py housekeeping
sleep "${SECONDS}s"
done

56
docker/launch-netbox.sh Executable file
View File

@ -0,0 +1,56 @@
#!/bin/bash
UNIT_CONFIG="${UNIT_CONFIG-/etc/unit/nginx-unit.json}"
UNIT_SOCKET="/opt/unit/unit.sock"
load_configuration() {
MAX_WAIT=10
WAIT_COUNT=0
while [ ! -S $UNIT_SOCKET ]; do
if [ $WAIT_COUNT -ge $MAX_WAIT ]; then
echo "⚠️ No control socket found; configuration will not be loaded."
return 1
fi
WAIT_COUNT=$((WAIT_COUNT + 1))
echo "⏳ Waiting for control socket to be created... (${WAIT_COUNT}/${MAX_WAIT})"
sleep 1
done
# even when the control socket exists, it does not mean unit has finished initialisation
# this curl call will get a reply once unit is fully launched
curl --silent --output /dev/null --request GET --unix-socket $UNIT_SOCKET http://localhost/
echo "⚙️ Applying configuration from $UNIT_CONFIG"
RESP_CODE=$(
curl \
--silent \
--output /dev/null \
--write-out '%{http_code}' \
--request PUT \
--data-binary "@${UNIT_CONFIG}" \
--unix-socket $UNIT_SOCKET \
http://localhost/config
)
if [ "$RESP_CODE" != "200" ]; then
echo "⚠️ Could no load Unit configuration"
kill "$(cat /opt/unit/unit.pid)"
return 1
fi
echo "✅ Unit configuration loaded successfully"
}
load_configuration &
exec unitd \
--no-daemon \
--control unix:$UNIT_SOCKET \
--pid /opt/unit/unit.pid \
--log /dev/stdout \
--state /opt/unit/state/ \
--tmp /opt/unit/tmp/ \
--user unit \
--group root

View File

@ -1,10 +1,23 @@
import importlib.util
import sys
from .configuration import read_configurations
try:
spec = importlib.util.spec_from_file_location('ldap_config', '/etc/netbox/config/ldap_config.py')
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
sys.modules['netbox.ldap_config'] = module
except:
raise ImportError('')
_loaded_configurations = read_configurations(
config_dir="/etc/netbox/config/ldap/",
config_module="netbox.configuration.ldap",
main_config="ldap_config",
)
def __getattr__(name):
for config in _loaded_configurations:
try:
return getattr(config, name)
except:
pass
raise AttributeError
def __dir__():
names = []
for config in _loaded_configurations:
names.extend(config.__dir__())
return names

40
docker/nginx-unit.json Normal file
View File

@ -0,0 +1,40 @@
{
"listeners": {
"*:8080": {
"pass": "routes"
}
},
"routes": [
{
"match": {
"uri": "/static/*"
},
"action": {
"share": "/opt/netbox/netbox"
}
},
{
"action": {
"pass": "applications/netbox"
}
}
],
"applications": {
"netbox": {
"type": "python 3",
"path": "/opt/netbox/netbox/",
"module": "netbox.wsgi",
"home": "/opt/netbox/venv",
"processes": {
"max": 4,
"spare": 1,
"idle_timeout": 120
}
}
},
"access_log": "/dev/stdout"
}

View File

@ -1,36 +0,0 @@
daemon off;
worker_processes 1;
error_log /dev/stderr info;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
sendfile on;
tcp_nopush on;
keepalive_timeout 65;
gzip on;
server_tokens off;
client_max_body_size 10M;
server {
listen 8080;
access_log off;
location /static/ {
alias /opt/netbox/netbox/static/;
}
location / {
proxy_pass http://netbox:8001;
proxy_set_header X-Forwarded-Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
add_header P3P 'CP="ALL DSP COR PSAa PSDa OUR NOR ONL UNI COM NAV"';
}
}
}

44
env/netbox.env vendored
View File

@ -1,32 +1,40 @@
CORS_ORIGIN_ALLOW_ALL=True
DB_NAME=netbox
DB_USER=netbox
DB_PASSWORD=J5brHrAXFLQSif0K
DB_HOST=postgres
EMAIL_SERVER=localhost
EMAIL_PORT=25
EMAIL_USERNAME=netbox
EMAIL_PASSWORD=
EMAIL_TIMEOUT=5
DB_NAME=netbox
DB_PASSWORD=J5brHrAXFLQSif0K
DB_USER=netbox
EMAIL_FROM=netbox@bar.com
EMAIL_PASSWORD=
EMAIL_PORT=25
EMAIL_SERVER=localhost
EMAIL_SSL_CERTFILE=
EMAIL_SSL_KEYFILE=
EMAIL_TIMEOUT=5
EMAIL_USERNAME=netbox
# EMAIL_USE_SSL and EMAIL_USE_TLS are mutually exclusive, i.e. they can't both be `true`!
EMAIL_USE_SSL=false
EMAIL_USE_TLS=false
HOUSEKEEPING_INTERVAL=86400
MAX_PAGE_SIZE=1000
MEDIA_ROOT=/opt/netbox/netbox/media
NAPALM_USERNAME=
METRICS_ENABLED=false
NAPALM_PASSWORD=
NAPALM_TIMEOUT=10
MAX_PAGE_SIZE=1000
REDIS_HOST=redis
REDIS_PASSWORD=H733Kdjndks81
REDIS_DATABASE=0
REDIS_SSL=false
NAPALM_USERNAME=
REDIS_CACHE_DATABASE=1
REDIS_CACHE_HOST=redis-cache
REDIS_CACHE_PASSWORD=t4Ph722qJ5QHeQ1qfu36
REDIS_CACHE_DATABASE=0
REDIS_CACHE_SSL=false
REDIS_DATABASE=0
REDIS_HOST=redis
REDIS_PASSWORD=H733Kdjndks81
REDIS_SSL=false
RELEASE_CHECK_URL=https://api.github.com/repos/netbox-community/netbox/releases
SECRET_KEY=r8OwDznj!!dci#P9ghmRfdu1Ysxm0AiPeDCQhKE+N_rClfWNj
SKIP_STARTUP_SCRIPTS=false
SKIP_SUPERUSER=false
SUPERUSER_NAME=admin
SUPERUSER_EMAIL=admin@example.com
SUPERUSER_PASSWORD=admin
SUPERUSER_API_TOKEN=0123456789abcdef0123456789abcdef01234567
SUPERUSER_EMAIL=admin@example.com
SUPERUSER_NAME=admin
SUPERUSER_PASSWORD=admin
WEBHOOKS_ENABLED=true

4
env/postgres.env vendored
View File

@ -1,3 +1,3 @@
POSTGRES_USER=netbox
POSTGRES_PASSWORD=J5brHrAXFLQSif0K
POSTGRES_DB=netbox
POSTGRES_PASSWORD=J5brHrAXFLQSif0K
POSTGRES_USER=netbox

View File

@ -1,5 +1,6 @@
# - prefix: 10.0.0.0/16
# rir: RFC1918
# tenant: tenant1
# - prefix: fd00:ccdd::/32
# rir: RFC4193 ULA
# - prefix: 2001:db8::/32

View File

@ -0,0 +1,6 @@
# - name: VPLS
# slug: vpls
# - name: MPLS
# slug: mpls
# - name: Internet
# slug: internet

View File

@ -0,0 +1,7 @@
# - cid: Circuit_ID-1
# provider: Provider1
# type: Internet
# tenant: tenant1
# - cid: Circuit_ID-2
# provider: Provider2
# type: MPLS

View File

@ -0,0 +1,4 @@
# - name: Group 1
# slug: group-1
# - name: Group 2
# slug: group-2

View File

@ -1,5 +1,7 @@
# - name: cluster1
# type: Hyper-V
# group: Group 1
# tenant: tenant1
# - name: cluster2
# type: Hyper-V
# site: SING 1

View File

@ -43,40 +43,36 @@
# required: false
# filter_logic: exact
# weight: 30
# default: First Item
# on_objects:
# - dcim.models.Device
# choices:
# - value: First Item
# weight: 10
# - value: Second Item
# weight: 20
# - value: Third Item
# weight: 30
# - value: Fifth Item
# weight: 50
# - value: Fourth Item
# weight: 40
# select_field_auto_weight:
# type: select
# label: Choose between items
# required: false
# filter_logic: loose
# weight: 30
# on_objects:
# - dcim.models.Device
# choices:
# - value: A
# - value: B
# - value: C
# - value: "D like deprecated"
# weight: 999
# - value: E
# - First Item
# - Second Item
# - Third Item
# - Fifth Item
# - Fourth Item
# select_field_legacy_format:
# type: select
# label: Choose between items
# required: false
# filter_logic: loose
# weight: 30
# on_objects:
# - dcim.models.Device
# choices:
# - value: A # this is the deprecated format.
# - value: B # we only use it for the tests.
# - value: C # please see above for the new format.
# - value: "D like deprecated"
# weight: 999
# - value: E
# boolean_field:
# type: boolean
# label: Yes Or No?
# required: true
# filter_logic: loose
# default: "false" # important: but "false" in quotes!
# default: "false" # important: put "false" in quotes!
# weight: 90
# on_objects:
# - dcim.models.Device

View File

@ -0,0 +1,21 @@
## Possible Choices:
## new_window:
## - True
## - False
## content_type:
## - device
## - site
## - any-other-content-type
##
## Examples:
# - name: link_to_repo
# link_text: 'Link to Netbox Docker'
# link_url: 'https://github.com/netbox-community/netbox-docker'
# new_window: False
# content_type: device
# - name: link_to_localhost
# link_text: 'Link to localhost'
# link_url: 'http://localhost'
# new_window: True
# content_type: device

View File

@ -2,22 +2,22 @@
# manufacturer: Manufacturer 1
# slug: model-1
# u_height: 2
# custom_fields:
# custom_field_data:
# text_field: Description
# - model: Model 2
# manufacturer: Manufacturer 1
# slug: model-2
# custom_fields:
# custom_field_data:
# text_field: Description
# - model: Model 3
# manufacturer: Manufacturer 1
# slug: model-3
# is_full_depth: false
# u_height: 0
# custom_fields:
# custom_field_data:
# text_field: Description
# - model: Other
# manufacturer: No Name
# slug: other
# custom_fields:
# custom_field_data:
# text_field: Description

View File

@ -20,7 +20,7 @@
# rack: rack-01
# face: front
# position: 1
# custom_fields:
# custom_field_data:
# text_field: Description
# - name: server02
# device_role: server
@ -29,7 +29,9 @@
# rack: rack-02
# face: front
# position: 2
# custom_fields:
# primary_ip4: 10.1.1.2/24
# primary_ip6: 2001:db8:a000:1::2/64
# custom_field_data:
# text_field: Description
# - name: server03
# device_role: server
@ -38,5 +40,14 @@
# rack: rack-03
# face: front
# position: 3
# custom_fields:
# custom_field_data:
# text_field: Description
# - name: server04
# device_role: server
# device_type: Other
# site: SING 1
# location: cage 101
# face: front
# position: 3
# custom_field_data:
# text_field: Description

View File

@ -1,35 +1,9 @@
## To list all permissions, run:
##
## docker-compose run --rm --entrypoint /bin/bash netbox
## $ ./manage.py migrate
## $ ./manage.py shell
## > from django.contrib.auth.models import Permission
## > print('\n'.join([p.codename for p in Permission.objects.all()]))
##
## Permission lists support wildcards. See the examples below.
##
## Examples:
# applications:
# users:
# - technical_user
# - technical_user
# readers:
# users:
# - reader
# - reader
# writers:
# users:
# - writer
# permissions:
# - delete_device
# - delete_virtualmachine
# - add_*
# - change_*
# vm_managers:
# permissions:
# - '*_virtualmachine'
# device_managers:
# permissions:
# - '*device*'
# creators:
# permissions:
# - add_*
# - writer

View File

@ -0,0 +1,48 @@
# all.ro:
# actions:
# - view
# description: 'Read Only for All Objects'
# enabled: true
# groups:
# - applications
# - readers
# object_types: all
# users:
# - jdoe
# all.rw:
# actions:
# - add
# - change
# - delete
# - view
# description: 'Read/Write for All Objects'
# enabled: true
# groups:
# - writers
# object_types: all
# network_team.rw:
# actions:
# - add
# - change
# - delete
# - view
# description: "Network Team Permissions"
# enabled: true
# object_types:
# circuits:
# - circuit
# - circuittermination
# - circuittype
# - provider
# dcim: all
# ipam:
# - aggregate
# - ipaddress
# - prefix
# - rir
# - role
# - routetarget
# - service
# - vlan
# - vlangroup
# - vrf

View File

@ -0,0 +1,14 @@
# - name: power feed 1
# power_panel: power panel AMS 1
# voltage: 208
# amperage: 50
# max_utilization: 80
# phase: Single phase
# rack: rack-01
# - name: power feed 2
# power_panel: power panel SING 1
# voltage: 208
# amperage: 50
# max_utilization: 80
# phase: Three-phase
# rack: rack-03

View File

@ -0,0 +1,5 @@
# - name: power panel AMS 1
# site: AMS 1
# - name: power panel SING 1
# site: SING 1
# location: cage 101

View File

@ -0,0 +1,6 @@
# - name: Provider1
# slug: provider1
# asn: 121
# - name: Provider2
# slug: provider2
# asn: 122

View File

@ -20,7 +20,7 @@
# type: 4-post-cabinet
# width: 19
# u_height: 47
# custom_fields:
# custom_field_data:
# text_field: Description
# - site: AMS 2
# name: rack-02
@ -28,14 +28,14 @@
# type: 4-post-cabinet
# width: 19
# u_height: 47
# custom_fields:
# custom_field_data:
# text_field: Description
# - site: SING 1
# name: rack-03
# group: cage 101
# location: cage 101
# role: Role 3
# type: 4-post-cabinet
# width: 19
# u_height: 47
# custom_fields:
# custom_field_data:
# text_field: Description

View File

@ -0,0 +1,3 @@
# - name: 65000:1001
# tenant: tenant1
# - name: 65000:1002

15
initializers/services.yml Normal file
View File

@ -0,0 +1,15 @@
# - name: DNS
# protocol: TCP
# ports:
# - 53
# virtual_machine: virtual machine 1
# - name: DNS
# protocol: UDP
# ports:
# - 53
# virtual_machine: virtual machine 1
# - name: MISC
# protocol: UDP
# ports:
# - 4000
# device: server01

View File

@ -1,32 +1,34 @@
# - name: AMS 1
# slug: ams1
# region: Downtown
# status: 1
# status: active
# facility: Amsterdam 1
# asn: 12345
# custom_fields:
# text_field: Description
# custom_field_data:
# text_field: Description for AMS1
# - name: AMS 2
# slug: ams2
# region: Downtown
# status: 1
# status: active
# facility: Amsterdam 2
# asn: 54321
# custom_fields:
# text_field: Description
# custom_field_data:
# text_field: Description for AMS2
# - name: AMS 3
# slug: ams3
# region: Suburbs
# status: 1
# status: active
# facility: Amsterdam 3
# asn: 67890
# custom_fields:
# text_field: Description
# tenant: tenant1
# custom_field_data:
# text_field: Description for AMS3
# - name: SING 1
# slug: sing1
# region: Singapore
# status: 1
# status: active
# facility: Singapore 1
# asn: 09876
# custom_fields:
# text_field: Description
# tenant: tenant2
# custom_field_data:
# text_field: Description for SING1

12
initializers/tags.yml Normal file
View File

@ -0,0 +1,12 @@
# - name: Tag 1
# slug: tag-1
# color: Pink
# - name: Tag 2
# slug: tag-2
# color: Cyan
# - name: Tag 3
# slug: tag-3
# color: Grey
# - name: Tag 4
# slug: tag-4
# color: Teal

View File

@ -1,23 +1,14 @@
## To list all permissions, run:
##
## docker-compose run --rm --entrypoint /bin/bash netbox
## $ ./manage.py migrate
## $ ./manage.py shell
## > from django.contrib.auth.models import Permission
## > print('\n'.join([p.codename for p in Permission.objects.all()]))
##
## Permission lists support wildcards. See the examples below.
##
## Examples:
# technical_user:
# api_token: 0123456789technicaluser789abcdef01234567 # must be looooong!
# reader:
# password: reader
# writer:
# password: writer
# permissions:
# - delete_device
# - delete_virtualmachine
# - add_*
# - change_*
# jdoe:
# first_name: John
# last_name: Doe
# api_token: 0123456789jdoe789abcdef01234567jdoe
# is_active: True
# is_superuser: False
# is_staff: False
# email: john.doe@example.com

View File

@ -21,6 +21,8 @@
# memory: 2048
# name: virtual machine 2
# platform: Platform 2
# primary_ip4: 10.1.1.10/24
# primary_ip6: 2001:db8:a000:1::10/64
# status: active
# tenant: tenant1
# vcpus: 8

View File

@ -1,6 +1,24 @@
# - name: VLAN group 1
# site: AMS 1
# scope_type: dcim.region
# scope: Amsterdam
# slug: vlan-group-1
# - name: VLAN group 2
# site: AMS 1
# scope_type: dcim.site
# scope: AMS 1
# slug: vlan-group-2
# - name: VLAN group 3
# scope_type: dcim.location
# scope: cage 101
# slug: vlan-group-3
# - name: VLAN group 4
# scope_type: dcim.rack
# scope: rack-01
# slug: vlan-group-4
# - name: VLAN group 5
# scope_type: virtualization.cluster
# scope: cluster1
# slug: vlan-group-5
# - name: VLAN group 6
# scope_type: virtualization.clustergroup
# scope: Group 1
# slug: vlan-group-6

27
initializers/webhooks.yml Normal file
View File

@ -0,0 +1,27 @@
## Possible Choices:
## object_types:
## - device
## - site
## - any-other-content-type
## types:
## - type_create
## - type_update
## - type_delete
## Examples:
# - name: device_creation
# payload_url: 'http://localhost:8080'
# object_types:
# - device
# - cable
# type_create: True
# - name: device_update
# payload_url: 'http://localhost:8080'
# object_types:
# - device
# type_update: True
# - name: device_delete
# payload_url: 'http://localhost:8080'
# object_types:
# - device
# type_delete: True

26
pyproject.toml Normal file
View File

@ -0,0 +1,26 @@
[tool.black]
line_length = 100
target-version = ['py38']
include = '\.pyi?$'
exclude = '''
(
/(
\.git
| \.venv
| \.netbox
| \.vscode
| configuration
)/
)
'''
[tool.isort]
profile = "black"
multi_line_output = 3
line_length = 100
[tool.pylint.messages_control]
disable = "C0330, C0326"
[tool.pylint.format]
max-line-length = "100"

188
release.sh Executable file
View File

@ -0,0 +1,188 @@
#!/bin/bash
DEFAULT_REPO=netbox-community/netbox-docker
REPO="${REPO-${DEFAULT_REPO}}"
echomoji() {
EMOJI=${1}
TEXT=${2}
shift 2
if [ -z "$DISABLE_EMOJI" ]; then
echo "${EMOJI}" "${@}"
else
echo "${TEXT}" "${@}"
fi
}
echo_nok() {
echomoji "❌" "!" "${@}"
}
echo_ok() {
echomoji "✅" "-" "${@}"
}
echo_hint() {
echomoji "👉" ">" "${@}"
}
# check errors shall exit with code 1
check_clean_repo() {
changes=$(git status --porcelain 2>/dev/null)
if [ ${?} ] && [ -n "$changes" ]; then
echo_nok "There are git changes pending:"
echo "$changes"
echo_hint "Please clean the repository before continueing: git stash --include-untracked"
exit 1
fi
echo_ok "Repository has no pending changes."
}
check_branch() {
expected_branch="${1}"
actual_branch=$(git rev-parse --abbrev-ref HEAD 2>/dev/null)
if [ ${?} ] && [ "${actual_branch}" != "${expected_branch}" ]; then
echo_nok "Current branch should be '${expected_branch}', but is '${actual_branch}'."
echo_hint "Please change to the '${expected_branch}' branch: git checkout ${expected_branch}"
exit 1
fi
echo_ok "The current branch is '${actual_branch}'."
}
check_upstream() {
expected_upstream_branch="origin/${1}"
actual_upstream_branch=$(git rev-parse --abbrev-ref '@{upstream}' 2>/dev/null)
if [ ${?} ] && [ "${actual_upstream_branch}" != "${expected_upstream_branch}" ]; then
echo_nok "Current upstream branch should be '${expected_upstream_branch}', but is '${actual_upstream_branch}'."
echo_hint "Please set '${expected_upstream_branch}' as the upstream branch: git branch --set-upstream-to=${expected_upstream_branch}"
exit 1
fi
echo_ok "The current upstream branch is '${actual_upstream_branch}'."
}
check_origin() {
expected_origin="git@github.com:${REPO}.git"
actual_origin=$(git remote get-url origin 2>/dev/null)
if [ ${?} ] && [ "${actual_origin}" != "${expected_origin}" ]; then
echo_nok "The url of origin is '${actual_origin}', but '${expected_origin}' is expected."
echo_hint "Please set '${expected_origin}' as the url for origin: git origin set-url '${expected_origin}'"
exit 1
fi
echo_ok "The current origin url is '${actual_origin}'."
}
check_latest() {
git fetch --tags origin
local_head_commit=$(git rev-parse HEAD 2>/dev/null)
remote_head_commit=$(git rev-parse FETCH_HEAD 2>/dev/null)
if [ "${local_head_commit}" != "${remote_head_commit}" ]; then
echo_nok "HEAD is at '${local_head_commit}', but FETCH_HEAD is at '${remote_head_commit}'."
echo_hint "Please ensure that you have pushed and pulled all the latest chanegs: git pull --prune --rebase origin; git push origin"
exit 1
fi
echo_ok "HEAD and FETCH_HEAD both point to '${local_head_commit}'."
}
check_tag() {
local tag
tag=$(<VERSION)
if git rev-parse "${tag}" 2>/dev/null >/dev/null; then
echo_nok "The tag '${tag}' already points to '$(git rev-parse "${tag}" 2>/dev/null)'."
echo_hint "Please ensure that the 'VERSION' file has been updated before trying to release: echo X.Y.Z > VERSION"
exit 1
fi
echo_ok "The tag '${tag}' does not exist yet."
}
check_develop() {
echomoji 📋 "?" "Checking 'develop' branch"
check_branch develop
check_upstream develop
check_clean_repo
check_latest
}
check_release() {
echomoji 📋 "?" "Checking 'release' branch"
check_upstream release
check_clean_repo
check_latest
}
# git errors shall exit with code 2
git_switch() {
echomoji 🔀 "≈" "Switching to '${1}' branch…"
if ! git checkout "${1}" >/dev/null; then
echo_nok "It was not possible to switch to the branch '${1}'."
exit 2
fi
echo_ok "The branch is now '${1}'."
}
git_tag() {
echomoji 🏷 "X" "Tagging version '${1}'…"
if ! git tag "${1}"; then
echo_nok "The tag '${1}' was not created because of an error."
exit 2
fi
echo_ok "The tag '$(<VERSION)' was created."
}
git_push() {
echomoji ⏩ "»" "Pushing the tag '${2}' to '${1}'…"
if ! git push "${1}" "${2}"; then
echo_nok "The tag '${2}' could not be pushed to '${1}'."
exit 2
fi
echo_ok "The tag '${2}' was pushed."
}
git_merge() {
echomoji ⏩ "»" "Merging '${1}'…"
if ! git merge --no-ff "${1}"; then
echo_nok "The branch '${1}' could not be merged."
exit 2
fi
echo_ok "The branch '${2}' was merged."
}
git_merge() {
echomoji ⏩ "»" "Rebasing onto '${1}'…"
if ! git rebase "${1}"; then
echo_nok "Could not rebase onto '${1}'."
exit 2
fi
echo_ok "Rebased onto '${2}'."
}
###
# MAIN
###
echomoji 📋 "▶︎" "Checking pre-requisites for releasing '$(<VERSION)'"
check_origin
check_develop
check_tag
git_switch release
check_release
echomoji 📋 "▶︎" "Releasing '$(<VERSION)'"
git_merge develop
check_tag
git_tag "$(<VERSION)"
git_push "origin" release
git_push "origin" "$(<VERSION)"
git_switch develop
git_rebase release
echomoji ✅ "◼︎" "The release of '$(<VERSION)' is complete."

14
renovate.json Normal file
View File

@ -0,0 +1,14 @@
{
"extends": [
"config:base",
":disableDependencyDashboard"
],
"enabled": true,
"labels": ["maintenance"],
"baseBranches": ["develop"],
"pip_requirements": {
"fileMatch": [
"requirements-container.txt"
]
}
}

View File

@ -1,4 +1,4 @@
from dcim.constants import CONNECTION_STATUS_PLANNED, DEVICE_STATUS_ACTIVE
from dcim.choices import DeviceStatusChoices
from dcim.models import ConsolePort, Device, PowerPort
from extras.reports import Report
@ -9,13 +9,14 @@ class DeviceConnectionsReport(Report):
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):
active = DeviceStatusChoices.STATUS_ACTIVE
for console_port in ConsolePort.objects.prefetch_related('device').filter(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:
elif not console_port.connection_status:
self.log_warning(
console_port.device,
"Console connection for {} marked as planned".format(console_port.name)
@ -26,12 +27,12 @@ class DeviceConnectionsReport(Report):
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):
for device in Device.objects.filter(status=DeviceStatusChoices.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:
if not power_port.connection_status:
self.log_warning(
device,
"Power connection for {} marked as planned".format(power_port.name)
@ -43,4 +44,3 @@ class DeviceConnectionsReport(Report):
)
else:
self.log_success(device)

View File

@ -0,0 +1,5 @@
napalm==3.3.1
ruamel.yaml==0.17.16
django-auth-ldap==3.0.0
google-crc32c==1.3.0
django-storages[azure,boto3,dropbox,google,libcloud,sftp]==1.12.1

View File

@ -1,42 +1,21 @@
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
file = Path('/opt/netbox/initializers/users.yml')
if not file.is_file():
sys.exit()
from django.contrib.auth.models import User
from startup_script_utils import load_yaml
from users.models import Token
with file.open('r') as stream:
yaml=YAML(typ='safe')
users = yaml.load(stream)
users = load_yaml("/opt/netbox/initializers/users.yml")
if users is None:
sys.exit()
if users is not None:
for username, user_details in users.items():
if not User.objects.filter(username=username):
for username, user_details in users.items():
if not User.objects.filter(username=username):
user = User.objects.create_user(
username = username,
password = user_details.get('password', 0) or User.objects.make_random_password)
username=username,
password=user_details.get("password", 0) or User.objects.make_random_password(),
)
print("👤 Created user",username)
print("👤 Created user", username)
if user_details.get('api_token', 0):
Token.objects.create(user=user, key=user_details['api_token'])
yaml_permissions = user_details.get('permissions', [])
if yaml_permissions:
subject = user.user_permissions
subject.clear()
for yaml_permission in yaml_permissions:
if '*' in yaml_permission:
permission_filter = '^' + yaml_permission.replace('*','.*') + '$'
permissions = Permission.objects.filter(codename__iregex=permission_filter)
print(" ⚿ Granting", permissions.count(), "permissions matching '" + yaml_permission + "'")
else:
permissions = Permission.objects.filter(codename=yaml_permission)
print(" ⚿ Granting permission", yaml_permission)
for permission in permissions:
subject.add(permission)
if user_details.get("api_token", 0):
Token.objects.create(user=user, key=user_details["api_token"])

View File

@ -1,41 +1,23 @@
from django.contrib.auth.models import Permission, Group, User
from ruamel.yaml import YAML
from pathlib import Path
import sys
file = Path('/opt/netbox/initializers/groups.yml')
if not file.is_file():
sys.exit()
from startup_script_utils import load_yaml
from users.models import AdminGroup, AdminUser
with file.open('r') as stream:
yaml=YAML(typ='safe')
groups = yaml.load(stream)
groups = load_yaml("/opt/netbox/initializers/groups.yml")
if groups is None:
sys.exit()
if groups is not None:
for groupname, group_details in groups.items():
group, created = Group.objects.get_or_create(name=groupname)
for groupname, group_details in groups.items():
group, created = AdminGroup.objects.get_or_create(name=groupname)
if created:
if created:
print("👥 Created group", groupname)
for username in group_details.get('users', []):
user = User.objects.get(username=username)
for username in group_details.get("users", []):
user = AdminUser.objects.get(username=username)
if user:
user.groups.add(group)
group.user_set.add(user)
print(" 👤 Assigned user %s to group %s" % (username, AdminGroup.name))
yaml_permissions = group_details.get('permissions', [])
if yaml_permissions:
subject = group.permissions
subject.clear()
for yaml_permission in yaml_permissions:
if '*' in yaml_permission:
permission_filter = '^' + yaml_permission.replace('*','.*') + '$'
permissions = Permission.objects.filter(codename__iregex=permission_filter)
print(" ⚿ Granting", permissions.count(), "permissions matching '" + yaml_permission + "'")
else:
permissions = Permission.objects.filter(codename=yaml_permission)
print(" ⚿ Granting permission", yaml_permission)
for permission in permissions:
subject.add(permission)
group.save()

View File

@ -0,0 +1,60 @@
import sys
from django.contrib.contenttypes.models import ContentType
from startup_script_utils import load_yaml
from users.models import AdminGroup, AdminUser, ObjectPermission
object_permissions = load_yaml("/opt/netbox/initializers/object_permissions.yml")
if object_permissions is None:
sys.exit()
for permission_name, permission_details in object_permissions.items():
object_permission, created = ObjectPermission.objects.get_or_create(
name=permission_name,
description=permission_details["description"],
enabled=permission_details["enabled"],
actions=permission_details["actions"],
)
if permission_details.get("object_types", 0):
object_types = permission_details["object_types"]
if object_types == "all":
object_permission.object_types.set(ContentType.objects.all())
else:
for app_label, models in object_types.items():
if models == "all":
app_models = ContentType.objects.filter(app_label=app_label)
for app_model in app_models:
object_permission.object_types.add(app_model.id)
else:
# There is
for model in models:
object_permission.object_types.add(
ContentType.objects.get(app_label=app_label, model=model)
)
print("🔓 Created object permission", object_permission.name)
if permission_details.get("groups", 0):
for groupname in permission_details["groups"]:
group = AdminGroup.objects.filter(name=groupname).first()
if group:
object_permission.groups.add(group)
print(" 👥 Assigned group %s object permission of %s" % (groupname, groupname))
if permission_details.get("users", 0):
for username in permission_details["users"]:
user = AdminUser.objects.filter(username=username).first()
if user:
object_permission.users.add(user)
print(" 👤 Assigned user %s object permission of %s" % (username, groupname))
object_permission.save()

View File

@ -1,59 +1,64 @@
from extras.models import CustomField, CustomFieldChoice
from ruamel.yaml import YAML
from pathlib import Path
import sys
from extras.models import CustomField
from startup_script_utils import load_yaml
def get_class_for_class_path(class_path):
import importlib
from django.contrib.contenttypes.models import ContentType
import importlib
module_name, class_name = class_path.rsplit(".", 1)
module = importlib.import_module(module_name)
clazz = getattr(module, class_name)
return ContentType.objects.get_for_model(clazz)
from django.contrib.contenttypes.models import ContentType
file = Path('/opt/netbox/initializers/custom_fields.yml')
if not file.is_file():
sys.exit()
module_name, class_name = class_path.rsplit(".", 1)
module = importlib.import_module(module_name)
clazz = getattr(module, class_name)
return ContentType.objects.get_for_model(clazz)
with file.open('r') as stream:
yaml = YAML(typ='safe')
customfields = yaml.load(stream)
if customfields is not None:
for cf_name, cf_details in customfields.items():
custom_field, created = CustomField.objects.get_or_create(name = cf_name)
customfields = load_yaml("/opt/netbox/initializers/custom_fields.yml")
if created:
if cf_details.get('default', 0):
custom_field.default = cf_details['default']
if customfields is None:
sys.exit()
if cf_details.get('description', 0):
custom_field.description = cf_details['description']
for cf_name, cf_details in customfields.items():
custom_field, created = CustomField.objects.get_or_create(name=cf_name)
if cf_details.get('label', 0):
custom_field.label = cf_details['label']
if created:
if cf_details.get("default", False):
custom_field.default = cf_details["default"]
for object_type in cf_details.get('on_objects', []):
custom_field.obj_type.add(get_class_for_class_path(object_type))
if cf_details.get("description", False):
custom_field.description = cf_details["description"]
if cf_details.get('required', 0):
custom_field.required = cf_details['required']
if cf_details.get("label", False):
custom_field.label = cf_details["label"]
if cf_details.get('type', 0):
custom_field.type = cf_details['type']
for object_type in cf_details.get("on_objects", []):
custom_field.content_types.add(get_class_for_class_path(object_type))
if cf_details.get('weight', 0):
custom_field.weight = cf_details['weight']
if cf_details.get("required", False):
custom_field.required = cf_details["required"]
if cf_details.get("type", False):
custom_field.type = cf_details["type"]
if cf_details.get("weight", -1) >= 0:
custom_field.weight = cf_details["weight"]
if cf_details.get("choices", False):
custom_field.choices = []
for choice_detail in cf_details.get("choices", []):
if isinstance(choice_detail, dict) and "value" in choice_detail:
# legacy mode
print(
f"⚠️ Please migrate the choice '{choice_detail['value']}' of '{cf_name}'"
+ " to the new format, as 'weight' is no longer supported!"
)
custom_field.choices.append(choice_detail["value"])
else:
custom_field.choices.append(choice_detail)
custom_field.save()
for idx, choice_details in enumerate(cf_details.get('choices', [])):
choice, _ = CustomFieldChoice.objects.get_or_create(
field=custom_field,
value=choice_details['value'],
defaults={'weight': idx * 10}
)
print("🔧 Created custom field", cf_name)

View File

@ -0,0 +1,23 @@
import sys
from extras.models import Tag
from startup_script_utils import load_yaml
from utilities.choices import ColorChoices
tags = load_yaml("/opt/netbox/initializers/tags.yml")
if tags is None:
sys.exit()
for params in tags:
if "color" in params:
color = params.pop("color")
for color_tpl in ColorChoices:
if color in color_tpl:
params["color"] = color_tpl[0]
tag, created = Tag.objects.get_or_create(**params)
if created:
print("🎨 Created Tag", tag.name)

View File

@ -0,0 +1,15 @@
import sys
from startup_script_utils import load_yaml
from tenancy.models import TenantGroup
tenant_groups = load_yaml("/opt/netbox/initializers/tenant_groups.yml")
if tenant_groups is None:
sys.exit()
for params in tenant_groups:
tenant_group, created = TenantGroup.objects.get_or_create(**params)
if created:
print("🔳 Created Tenant Group", tenant_group.name)

View File

@ -1,31 +1,25 @@
from dcim.models import Region
from ruamel.yaml import YAML
from pathlib import Path
import sys
file = Path('/opt/netbox/initializers/regions.yml')
if not file.is_file():
sys.exit()
from dcim.models import Region
from startup_script_utils import load_yaml
with file.open('r') as stream:
yaml=YAML(typ='safe')
regions = yaml.load(stream)
regions = load_yaml("/opt/netbox/initializers/regions.yml")
optional_assocs = {
'parent': (Region, 'name')
}
if regions is None:
sys.exit()
if regions is not None:
for params in regions:
optional_assocs = {"parent": (Region, "name")}
for assoc, details in optional_assocs.items():
for params in regions:
for assoc, details in optional_assocs.items():
if assoc in params:
model, field = details
query = { field: params.pop(assoc) }
model, field = details
query = {field: params.pop(assoc)}
params[assoc] = model.objects.get(**query)
params[assoc] = model.objects.get(**query)
region, created = Region.objects.get_or_create(**params)
region, created = Region.objects.get_or_create(**params)
if created:
if created:
print("🌐 Created region", region.name)

View File

@ -0,0 +1,28 @@
import sys
from startup_script_utils import load_yaml, pop_custom_fields, set_custom_fields_values
from tenancy.models import Tenant, TenantGroup
tenants = load_yaml("/opt/netbox/initializers/tenants.yml")
if tenants is None:
sys.exit()
optional_assocs = {"group": (TenantGroup, "name")}
for params in tenants:
custom_field_data = pop_custom_fields(params)
for assoc, details in optional_assocs.items():
if assoc in params:
model, field = details
query = {field: params.pop(assoc)}
params[assoc] = model.objects.get(**query)
tenant, created = Tenant.objects.get_or_create(**params)
if created:
set_custom_fields_values(tenant, custom_field_data)
print("👩‍💻 Created Tenant", tenant.name)

View File

@ -1,46 +1,29 @@
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
file = Path('/opt/netbox/initializers/sites.yml')
if not file.is_file():
sys.exit()
from dcim.models import Region, Site
from startup_script_utils import load_yaml, pop_custom_fields, set_custom_fields_values
from tenancy.models import Tenant
with file.open('r') as stream:
yaml = YAML(typ='safe')
sites = yaml.load(stream)
sites = load_yaml("/opt/netbox/initializers/sites.yml")
optional_assocs = {
'region': (Region, 'name'),
'tenant': (Tenant, 'name')
}
if sites is None:
sys.exit()
if sites is not None:
for params in sites:
custom_fields = params.pop('custom_fields', None)
optional_assocs = {"region": (Region, "name"), "tenant": (Tenant, "name")}
for assoc, details in optional_assocs.items():
for params in sites:
custom_field_data = pop_custom_fields(params)
for assoc, details in optional_assocs.items():
if assoc in params:
model, field = details
query = { field: params.pop(assoc) }
model, field = details
query = {field: params.pop(assoc)}
params[assoc] = model.objects.get(**query)
params[assoc] = model.objects.get(**query)
site, created = Site.objects.get_or_create(**params)
site, created = Site.objects.get_or_create(**params)
if created:
if custom_fields is not None:
for cf_name, cf_value in custom_fields.items():
custom_field = CustomField.objects.get(name=cf_name)
custom_field_value = CustomFieldValue.objects.create(
field=custom_field,
obj=site,
value=cf_value
)
site.custom_field_values.add(custom_field_value)
if created:
set_custom_fields_values(site, custom_field_data)
print("📍 Created site", site.name)

View File

@ -1,19 +1,15 @@
from dcim.models import Manufacturer
from ruamel.yaml import YAML
from pathlib import Path
import sys
file = Path('/opt/netbox/initializers/manufacturers.yml')
if not file.is_file():
sys.exit()
from dcim.models import Manufacturer
from startup_script_utils import load_yaml
with file.open('r') as stream:
yaml = YAML(typ='safe')
manufacturers = yaml.load(stream)
manufacturers = load_yaml("/opt/netbox/initializers/manufacturers.yml")
if manufacturers is not None:
for params in manufacturers:
manufacturer, created = Manufacturer.objects.get_or_create(**params)
if manufacturers is None:
sys.exit()
if created:
for params in manufacturers:
manufacturer, created = Manufacturer.objects.get_or_create(**params)
if created:
print("🏭 Created Manufacturer", manufacturer.name)

View File

@ -1,56 +1,37 @@
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
file = Path('/opt/netbox/initializers/device_types.yml')
if not file.is_file():
sys.exit()
from dcim.models import DeviceType, Manufacturer, Region
from startup_script_utils import load_yaml, pop_custom_fields, set_custom_fields_values
from tenancy.models import Tenant
with file.open('r') as stream:
yaml = YAML(typ='safe')
device_types = yaml.load(stream)
device_types = load_yaml("/opt/netbox/initializers/device_types.yml")
required_assocs = {
'manufacturer': (Manufacturer, 'name')
}
if device_types is None:
sys.exit()
optional_assocs = {
'region': (Region, 'name'),
'tenant': (Tenant, 'name')
}
required_assocs = {"manufacturer": (Manufacturer, "name")}
if device_types is not None:
for params in device_types:
custom_fields = params.pop('custom_fields', None)
optional_assocs = {"region": (Region, "name"), "tenant": (Tenant, "name")}
for assoc, details in required_assocs.items():
for params in device_types:
custom_field_data = pop_custom_fields(params)
for assoc, details in required_assocs.items():
model, field = details
query = { field: params.pop(assoc) }
query = {field: params.pop(assoc)}
params[assoc] = model.objects.get(**query)
for assoc, details in optional_assocs.items():
for assoc, details in optional_assocs.items():
if assoc in params:
model, field = details
query = { field: params.pop(assoc) }
model, field = details
query = {field: params.pop(assoc)}
params[assoc] = model.objects.get(**query)
params[assoc] = model.objects.get(**query)
device_type, created = DeviceType.objects.get_or_create(**params)
device_type, created = DeviceType.objects.get_or_create(**params)
if created:
if custom_fields is not None:
for cf_name, cf_value in custom_fields.items():
custom_field = CustomField.objects.get(name=cf_name)
custom_field_value = CustomFieldValue.objects.create(
field=custom_field,
obj=device_type,
value=cf_value
)
device_type.custom_field_values.add(custom_field_value)
if created:
set_custom_fields_values(device_type, custom_field_data)
print("🔡 Created device type", device_type.manufacturer, device_type.model)

View File

@ -1,28 +1,23 @@
from dcim.models import RackRole
from ruamel.yaml import YAML
from utilities.forms import COLOR_CHOICES
from pathlib import Path
import sys
file = Path('/opt/netbox/initializers/rack_roles.yml')
if not file.is_file():
sys.exit()
from dcim.models import RackRole
from startup_script_utils import load_yaml
from utilities.choices import ColorChoices
with file.open('r') as stream:
yaml=YAML(typ='safe')
rack_roles = yaml.load(stream)
rack_roles = load_yaml("/opt/netbox/initializers/rack_roles.yml")
if rack_roles is not None:
for params in rack_roles:
if 'color' in params:
color = params.pop('color')
if rack_roles is None:
sys.exit()
for color_tpl in COLOR_CHOICES:
if color in color_tpl:
params['color'] = color_tpl[0]
for params in rack_roles:
if "color" in params:
color = params.pop("color")
rack_role, created = RackRole.objects.get_or_create(**params)
for color_tpl in ColorChoices:
if color in color_tpl:
params["color"] = color_tpl[0]
if created:
rack_role, created = RackRole.objects.get_or_create(**params)
if created:
print("🎨 Created rack role", rack_role.name)

View File

@ -0,0 +1,23 @@
import sys
from dcim.models import Location, Site
from startup_script_utils import load_yaml
rack_groups = load_yaml("/opt/netbox/initializers/locations.yml")
if rack_groups is None:
sys.exit()
required_assocs = {"site": (Site, "name")}
for params in rack_groups:
for assoc, details in required_assocs.items():
model, field = details
query = {field: params.pop(assoc)}
params[assoc] = model.objects.get(**query)
location, created = Location.objects.get_or_create(**params)
if created:
print("🎨 Created location", location.name)

View File

@ -1,31 +0,0 @@
from dcim.models import Site,RackGroup
from ruamel.yaml import YAML
from pathlib import Path
import sys
file = Path('/opt/netbox/initializers/rack_groups.yml')
if not file.is_file():
sys.exit()
with file.open('r') as stream:
yaml=YAML(typ='safe')
rack_groups= yaml.load(stream)
required_assocs = {
'site': (Site, 'name')
}
if rack_groups is not None:
for params in rack_groups:
for assoc, details in required_assocs.items():
model, field = details
query = { field: params.pop(assoc) }
params[assoc] = model.objects.get(**query)
rack_group, created = RackGroup.objects.get_or_create(**params)
if created:
print("🎨 Created rack group", rack_group.name)

View File

@ -1,57 +1,41 @@
from dcim.models import Site, RackRole, Rack, RackGroup
from tenancy.models import Tenant
from extras.models import CustomField, CustomFieldValue
from ruamel.yaml import YAML
from pathlib import Path
import sys
file = Path('/opt/netbox/initializers/racks.yml')
if not file.is_file():
sys.exit()
from dcim.models import Location, Rack, RackRole, Site
from startup_script_utils import load_yaml, pop_custom_fields, set_custom_fields_values
from tenancy.models import Tenant
with file.open('r') as stream:
yaml = YAML(typ='safe')
racks = yaml.load(stream)
racks = load_yaml("/opt/netbox/initializers/racks.yml")
required_assocs = {
'site': (Site, 'name')
}
if racks is None:
sys.exit()
optional_assocs = {
'role': (RackRole, 'name'),
'tenant': (Tenant, 'name'),
'group': (RackGroup, 'name')
}
required_assocs = {"site": (Site, "name")}
if racks is not None:
for params in racks:
custom_fields = params.pop('custom_fields', None)
optional_assocs = {
"role": (RackRole, "name"),
"tenant": (Tenant, "name"),
"location": (Location, "name"),
}
for assoc, details in required_assocs.items():
for params in racks:
custom_field_data = pop_custom_fields(params)
for assoc, details in required_assocs.items():
model, field = details
query = { field: params.pop(assoc) }
query = {field: params.pop(assoc)}
params[assoc] = model.objects.get(**query)
for assoc, details in optional_assocs.items():
for assoc, details in optional_assocs.items():
if assoc in params:
model, field = details
query = { field: params.pop(assoc) }
model, field = details
query = {field: params.pop(assoc)}
params[assoc] = model.objects.get(**query)
params[assoc] = model.objects.get(**query)
rack, created = Rack.objects.get_or_create(**params)
rack, created = Rack.objects.get_or_create(**params)
if created:
if custom_fields is not None:
for cf_name, cf_value in custom_fields.items():
custom_field = CustomField.objects.get(name=cf_name)
custom_field_value = CustomFieldValue.objects.create(
field=custom_field,
obj=rack,
value=cf_value
)
rack.custom_field_values.add(custom_field_value)
if created:
set_custom_fields_values(rack, custom_field_data)
print("🔳 Created rack", rack.site, rack.name)

View File

@ -1,29 +1,24 @@
from dcim.models import DeviceRole
from ruamel.yaml import YAML
from utilities.forms import COLOR_CHOICES
from pathlib import Path
import sys
file = Path('/opt/netbox/initializers/device_roles.yml')
if not file.is_file():
sys.exit()
from dcim.models import DeviceRole
from startup_script_utils import load_yaml
from utilities.choices import ColorChoices
with file.open('r') as stream:
yaml=YAML(typ='safe')
device_roles = yaml.load(stream)
device_roles = load_yaml("/opt/netbox/initializers/device_roles.yml")
if device_roles is not None:
for params in device_roles:
if device_roles is None:
sys.exit()
if 'color' in params:
color = params.pop('color')
for params in device_roles:
for color_tpl in COLOR_CHOICES:
if color in color_tpl:
params['color'] = color_tpl[0]
if "color" in params:
color = params.pop("color")
device_role, created = DeviceRole.objects.get_or_create(**params)
for color_tpl in ColorChoices:
if color in color_tpl:
params["color"] = color_tpl[0]
if created:
device_role, created = DeviceRole.objects.get_or_create(**params)
if created:
print("🎨 Created device role", device_role.name)

View File

@ -1,32 +1,27 @@
from dcim.models import Manufacturer, Platform
from ruamel.yaml import YAML
from pathlib import Path
import sys
file = Path('/opt/netbox/initializers/platforms.yml')
if not file.is_file():
sys.exit()
from dcim.models import Manufacturer, Platform
from startup_script_utils import load_yaml
with file.open('r') as stream:
yaml = YAML(typ='safe')
platforms = yaml.load(stream)
platforms = load_yaml("/opt/netbox/initializers/platforms.yml")
optional_assocs = {
'manufacturer': (Manufacturer, 'name'),
}
if platforms is None:
sys.exit()
if platforms is not None:
for params in platforms:
optional_assocs = {
"manufacturer": (Manufacturer, "name"),
}
for assoc, details in optional_assocs.items():
for params in platforms:
for assoc, details in optional_assocs.items():
if assoc in params:
model, field = details
query = { field: params.pop(assoc) }
model, field = details
query = {field: params.pop(assoc)}
params[assoc] = model.objects.get(**query)
params[assoc] = model.objects.get(**query)
platform, created = Platform.objects.get_or_create(**params)
platform, created = Platform.objects.get_or_create(**params)
if created:
if created:
print("💾 Created platform", platform.name)

View File

@ -1,19 +0,0 @@
from tenancy.models import TenantGroup
from ruamel.yaml import YAML
from pathlib import Path
import sys
file = Path('/opt/netbox/initializers/tenant_groups.yml')
if not file.is_file():
sys.exit()
with file.open('r') as stream:
yaml = YAML(typ='safe')
tenant_groups = yaml.load(stream)
if tenant_groups is not None:
for params in tenant_groups:
tenant_group, created = TenantGroup.objects.get_or_create(**params)
if created:
print("🔳 Created Tenant Group", tenant_group.name)

View File

@ -1,45 +0,0 @@
from tenancy.models import Tenant, TenantGroup
from extras.models import CustomField, CustomFieldValue
from ruamel.yaml import YAML
from pathlib import Path
import sys
file = Path('/opt/netbox/initializers/tenants.yml')
if not file.is_file():
sys.exit()
with file.open('r') as stream:
yaml = YAML(typ='safe')
tenants = yaml.load(stream)
optional_assocs = {
'group': (TenantGroup, 'name')
}
if tenants is not None:
for params in tenants:
custom_fields = params.pop('custom_fields', None)
for assoc, details in optional_assocs.items():
if assoc in params:
model, field = details
query = { field: params.pop(assoc) }
params[assoc] = model.objects.get(**query)
tenant, created = Tenant.objects.get_or_create(**params)
if created:
if custom_fields is not None:
for cf_name, cf_value in custom_fields.items():
custom_field = CustomField.objects.get(name=cf_name)
custom_field_value = CustomFieldValue.objects.create(
field=custom_field,
obj=tenant,
value=cf_value
)
tenant.custom_field_values.add(custom_field_value)
print("👩‍💻 Created Tenant", tenant.name)

View File

@ -0,0 +1,15 @@
import sys
from startup_script_utils import load_yaml
from virtualization.models import ClusterType
cluster_types = load_yaml("/opt/netbox/initializers/cluster_types.yml")
if cluster_types is None:
sys.exit()
for params in cluster_types:
cluster_type, created = ClusterType.objects.get_or_create(**params)
if created:
print("🧰 Created Cluster Type", cluster_type.name)

View File

@ -1,65 +0,0 @@
from dcim.models import Site, Rack, DeviceRole, DeviceType, Device, Platform
from ipam.models import IPAddress
from virtualization.models import Cluster
from tenancy.models import Tenant
from extras.models import CustomField, CustomFieldValue
from ruamel.yaml import YAML
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)
required_assocs = {
'device_role': (DeviceRole, 'name'),
'device_type': (DeviceType, 'model'),
'site': (Site, 'name')
}
optional_assocs = {
'tenant': (Tenant, 'name'),
'platform': (Platform, 'name'),
'rack': (Rack, 'name'),
'cluster': (Cluster, 'name'),
'primary_ip4': (IPAddress, 'address'),
'primary_ip6': (IPAddress, 'address')
}
if devices is not None:
for params in devices:
custom_fields = params.pop('custom_fields', None)
for assoc, details in required_assocs.items():
model, field = details
query = { field: params.pop(assoc) }
params[assoc] = model.objects.get(**query)
for assoc, details in optional_assocs.items():
if assoc in params:
model, field = details
query = { field: params.pop(assoc) }
params[assoc] = model.objects.get(**query)
device, created = Device.objects.get_or_create(**params)
if created:
if custom_fields is not None:
for cf_name, cf_value in custom_fields.items():
custom_field = CustomField.objects.get(name=cf_name)
custom_field_value = CustomFieldValue.objects.create(
field=custom_field,
obj=device,
value=cf_value
)
device.custom_field_values.add(custom_field_value)
print("🖥️ Created device", device.name)

View File

@ -0,0 +1,15 @@
import sys
from startup_script_utils import load_yaml
from virtualization.models import ClusterGroup
cluster_groups = load_yaml("/opt/netbox/initializers/cluster_groups.yml")
if cluster_groups is None:
sys.exit()
for params in cluster_groups:
cluster_group, created = ClusterGroup.objects.get_or_create(**params)
if created:
print("🗄️ Created Cluster Group", cluster_group.name)

View File

@ -0,0 +1,42 @@
import sys
from dcim.models import Site
from startup_script_utils import load_yaml, pop_custom_fields, set_custom_fields_values
from tenancy.models import Tenant
from virtualization.models import Cluster, ClusterGroup, ClusterType
clusters = load_yaml("/opt/netbox/initializers/clusters.yml")
if clusters is None:
sys.exit()
required_assocs = {"type": (ClusterType, "name")}
optional_assocs = {
"site": (Site, "name"),
"group": (ClusterGroup, "name"),
"tenant": (Tenant, "name"),
}
for params in clusters:
custom_field_data = pop_custom_fields(params)
for assoc, details in required_assocs.items():
model, field = details
query = {field: params.pop(assoc)}
params[assoc] = model.objects.get(**query)
for assoc, details in optional_assocs.items():
if assoc in params:
model, field = details
query = {field: params.pop(assoc)}
params[assoc] = model.objects.get(**query)
cluster, created = Cluster.objects.get_or_create(**params)
if created:
set_custom_fields_values(cluster, custom_field_data)
print("🗄️ Created cluster", cluster.name)

View File

@ -1,19 +0,0 @@
from virtualization.models import ClusterType
from ruamel.yaml import YAML
from pathlib import Path
import sys
file = Path('/opt/netbox/initializers/cluster_types.yml')
if not file.is_file():
sys.exit()
with file.open('r') as stream:
yaml = YAML(typ='safe')
cluster_types = yaml.load(stream)
if cluster_types is not None:
for params in cluster_types:
cluster_type, created = ClusterType.objects.get_or_create(**params)
if created:
print("🧰 Created Cluster Type", cluster_type.name)

Some files were not shown because too many files have changed in this diff Show More