Compare commits
636 Commits
Author | SHA1 | Date | |
---|---|---|---|
f64ae49f18 | |||
4f645769df | |||
db7acaf647 | |||
90909d4181 | |||
bdbcf7bf4a | |||
477decd80a | |||
b845efe1ad | |||
56defa3f82 | |||
7078ab7519 | |||
fcd5b4e66b | |||
2efacf39ca | |||
a4ce13be19 | |||
fa08388175 | |||
fd9b41a5d1 | |||
83ec1c2656 | |||
0fe49f87d7 | |||
83f87b4ad2 | |||
82d9d8ae49 | |||
f1864f8f20 | |||
8431b77422 | |||
19e167ec19 | |||
8f7c21749e | |||
ec9a3e80da | |||
61eaffaf2e | |||
fef49f447e | |||
5ded00b6fb | |||
67ddeb6735 | |||
8179a4344b | |||
688d8901b7 | |||
687b8384bc | |||
1c3017323c | |||
c8bd177a93 | |||
c31ed9a79a | |||
139c158d8a | |||
e5400e345b | |||
017098a587 | |||
bb8f2fd17c | |||
d9da3fa35b | |||
0f7e72fc0d | |||
d9f72e94fa | |||
1c8cdfa6dd | |||
b6a30bf989 | |||
4eb0d6a368 | |||
849f8bef07 | |||
9eee74ba61 | |||
34c26bbd30 | |||
caa3d3324f | |||
25b022203a | |||
e61496688d | |||
29bef7450a | |||
6edc921a79 | |||
0f0ce521d6 | |||
c3f119bedc | |||
1701399b82 | |||
0b70f722f9 | |||
cecfd627e4 | |||
fb7213a1d2 | |||
1aa742342c | |||
230cd09cb5 | |||
d67ed0c2df | |||
b1d6e3caaa | |||
542538bf5c | |||
76404d01bf | |||
ab948e467c | |||
0d221e684d | |||
5332504c5a | |||
0082261007 | |||
052b17d5c1 | |||
7516e5d00d | |||
1bd16cec68 | |||
0d1637bd71 | |||
60db7e6c90 | |||
607ae32450 | |||
64bf745dce | |||
0ec4c5d795 | |||
afc10aaf26 | |||
e48a1b685b | |||
d129ade861 | |||
f394400b2b | |||
b56c45b4ee | |||
a48b86b5d4 | |||
6e74993d99 | |||
6fd2681449 | |||
a194302a41 | |||
bd9bdd0635 | |||
11615dfd7b | |||
1a70f971c0 | |||
69e997f0ea | |||
878b3b6abb | |||
d08e8b8d9b | |||
49d80c9109 | |||
5a61886e1d | |||
0c0c468386 | |||
f5d5a04b1c | |||
c416a054ae | |||
ad139decb3 | |||
404b4bcffe | |||
0e1c589541 | |||
d8ac6f828c | |||
bf0cecc7fd | |||
1ed3b1d849 | |||
dcc8a624ba | |||
7ccd618c58 | |||
afd18c6f39 | |||
d573274e21 | |||
50721989bf | |||
06232f64bb | |||
8fcbc5c294 | |||
14612526e0 | |||
8cd5ea456e | |||
8453eab8dd | |||
cc6a35b636 | |||
48f6e6cc04 | |||
bffdc6d822 | |||
3982207d91 | |||
409cfeb337 | |||
5354b142cb | |||
d3ce916073 | |||
db34a0ae2b | |||
27bf52cf3e | |||
5dea11c4d4 | |||
35c19d0fc8 | |||
cd42632628 | |||
09c897aa22 | |||
656b118826 | |||
f134a44bc7 | |||
5add31ee7a | |||
2d5c453350 | |||
942f978ed2 | |||
52f38a3771 | |||
a24c19c503 | |||
f13a6bf5e4 | |||
52f80cc7ca | |||
a7ebc148e8 | |||
636495e062 | |||
6e735fd431 | |||
ab2a7bc8e5 | |||
09ba1d3f4e | |||
f3a78bfd10 | |||
b81d4fba64 | |||
2c26000304 | |||
671f5e9411 | |||
d9ff19fd30 | |||
cb1bc4bde6 | |||
a75db6add9 | |||
279a54bef0 | |||
3f5f4ff8bb | |||
59922f3423 | |||
d0f72b5fd3 | |||
838a56c96f | |||
6ee26d62e8 | |||
542300056c | |||
3c7f90cab8 | |||
2a15689e5f | |||
9c6b063408 | |||
3134057f87 | |||
56bda20a67 | |||
51372eed32 | |||
e33ff85b08 | |||
279873d20e | |||
681876681d | |||
29e66a0a01 | |||
5d9aa096fd | |||
84132e4b59 | |||
da4c1a54a9 | |||
53418e7d19 | |||
368d1bca75 | |||
bb9a7fe542 | |||
15da2f0642 | |||
ee2d1dea17 | |||
402ea6e8d4 | |||
8017bb72b9 | |||
33d5230859 | |||
f0b3a0701c | |||
1a2957238c | |||
ac496a16ee | |||
e4315245b0 | |||
d4e94017b4 | |||
21cf7b498d | |||
2bbb2d16e1 | |||
9d04f2a7a5 | |||
b29f7fd446 | |||
6a3ba4409e | |||
570bb311e2 | |||
5e492c63c6 | |||
26b15f9ff1 | |||
3c8449fbec | |||
c51747a163 | |||
75fa7e7e99 | |||
9de583553d | |||
daa8b40c34 | |||
af6306db25 | |||
730743139e | |||
94e242179a | |||
8c691f1308 | |||
b74688309a | |||
60e9cfd458 | |||
1d69e6f233 | |||
918952a2a5 | |||
c22996d7d7 | |||
0c99ff8b56 | |||
1265d2277a | |||
620ca96d64 | |||
2561055265 | |||
53ac2ff81b | |||
b6492b2e6b | |||
6d25a54d49 | |||
36f409a16b | |||
9d247f5530 | |||
7a42faaabc | |||
f5a3e3f955 | |||
6307a58c4a | |||
1e78c386a5 | |||
40f24105e6 | |||
1a4ef09a16 | |||
3d6b6c2a67 | |||
f1787b4775 | |||
a7cb1a4651 | |||
8fb42b3213 | |||
b7d99c9c69 | |||
d52ef4445e | |||
e1335a1194 | |||
c9d8f55ea1 | |||
347b943b75 | |||
f15dec52ae | |||
e024427428 | |||
5f57cb2774 | |||
5873885edc | |||
e141d9f16d | |||
eb59ace74c | |||
2ee4acba21 | |||
2a582304b3 | |||
5309673f95 | |||
3c07538719 | |||
3df807faa0 | |||
4c0ee77bd0 | |||
6c01ada882 | |||
b6e5486b48 | |||
46f628e91b | |||
9f009c5907 | |||
73ce1f9b7a | |||
f443d4ac53 | |||
1b9bb2a25e | |||
d2d7948021 | |||
31a4da297a | |||
8e278c3c8e | |||
24eaba7f9b | |||
99b906c4f1 | |||
37733049da | |||
4da3f75c14 | |||
607ccd10bf | |||
f27148634a | |||
46edaa1d22 | |||
064b713489 | |||
9169fc7684 | |||
b8a7ffdb7b | |||
8450ba2f74 | |||
291ba760f1 | |||
2fbb5dd0b0 | |||
ea81db4789 | |||
249e589096 | |||
f1ca9ab7eb | |||
dfa1904a82 | |||
b5c12a82d2 | |||
7e1750d3a3 | |||
651bbc49ba | |||
d72facf182 | |||
d7866d5f6e | |||
33430fda08 | |||
e020b46f6a | |||
51049781b4 | |||
1e681f30b3 | |||
4680e59a07 | |||
aaaa628585 | |||
e8fa63d18b | |||
17b9569094 | |||
1a3ace957a | |||
96799369fe | |||
f1de85d975 | |||
830d498094 | |||
714a132566 | |||
d0fbb37d66 | |||
87159b56be | |||
252ab33560 | |||
0603f1ebe9 | |||
164b01319c | |||
e6fedf16fe | |||
0594d2c3ae | |||
8b8447f5c6 | |||
f42e78ece2 | |||
c473fcc44a | |||
bcafc4328c | |||
fe27ebc907 | |||
364555eef6 | |||
451337750a | |||
bc6e4f81b0 | |||
e452004526 | |||
caba1b335d | |||
c798e881b0 | |||
b47e85ab3f | |||
28553202a4 | |||
69c5580a3e | |||
4d54bb172b | |||
44d0f47fb5 | |||
12af4233bd | |||
f703bba5e1 | |||
dd0c0b795d | |||
be7af2ea4c | |||
75690ac7dd | |||
ec603633ea | |||
c99172661c | |||
9bdd074ad7 | |||
d69dacef09 | |||
ebc5900206 | |||
8208dedb19 | |||
0d748ed392 | |||
23d5865e3d | |||
2037e42e45 | |||
055538cc21 | |||
5408cf5af0 | |||
22486fefb5 | |||
96bda7fa4f | |||
c085287e64 | |||
b4a6be37ec | |||
02a926431b | |||
3978b14c7f | |||
7532508aab | |||
858611ad67 | |||
155e90c99f | |||
cb524c32ed | |||
cb4dcc0488 | |||
ddcc8b5131 | |||
3286faa94c | |||
788cd03a35 | |||
0911c2251d | |||
c698496e36 | |||
23a262d72f | |||
5273e17d89 | |||
e44f0398fb | |||
7c2e012523 | |||
5a29364bca | |||
5d5b01f6b5 | |||
5d6e733bce | |||
87a9808bc2 | |||
7bf9e1af5a | |||
1e588431e2 | |||
41fd4e5d67 | |||
17f1bb0af0 | |||
9cc58918ab | |||
831867499b | |||
d5dde45bec | |||
6576c18a9c | |||
efd6e6a3c2 | |||
47a7eee16a | |||
5eac65b8f6 | |||
2ba441124e | |||
f2d070fc49 | |||
97ee353b00 | |||
c001b88a81 | |||
b131b07af8 | |||
311629ade4 | |||
256f23b4ad | |||
29e37a31d7 | |||
93017f150e | |||
ac8cb022ae | |||
480cabaefe | |||
ab7e19df55 | |||
4ce89f9209 | |||
3e2bf7ec93 | |||
4bad061bc4 | |||
f9abdf2390 | |||
cc95a67df0 | |||
fb5bacc4b4 | |||
ed309a15b4 | |||
5f8a09536c | |||
d3a30e1172 | |||
e60a746eee | |||
879c700bb8 | |||
6f70b88972 | |||
7a9aef3791 | |||
3071c500da | |||
350747c1cb | |||
250b1fb093 | |||
eef45c8197 | |||
f549b93b9d | |||
f2b0375d5b | |||
3202fb9446 | |||
ff373bd60d | |||
bd07a7a5a2 | |||
41d80d66b1 | |||
015e131d99 | |||
ff37e17eeb | |||
1403f52d04 | |||
7e0a8fee82 | |||
0c1b69ded0 | |||
06e0815c70 | |||
8f2820626c | |||
b6faad36cb | |||
73f479d5db | |||
89ad7588f0 | |||
a4d986011d | |||
f2bb1198dd | |||
39c7de4af4 | |||
238f95c5ce | |||
751a131b78 | |||
5e2158da24 | |||
4a530947f8 | |||
bdb4396275 | |||
80d87bdf1b | |||
6d465e6f81 | |||
b72084290a | |||
aa3357817a | |||
9441be459c | |||
1779ba790d | |||
22cb2d5812 | |||
6020f4503a | |||
a4f494db14 | |||
0cac6f51a9 | |||
dd01e3c227 | |||
925f41b97f | |||
7d871778eb | |||
8b16b16e45 | |||
c5f91ad359 | |||
35a94cb7e5 | |||
1835d3cafd | |||
df8f406432 | |||
b8b1c8fc63 | |||
41ff541225 | |||
26399e224d | |||
951c12132a | |||
a3680b22dd | |||
d96e8f1dfd | |||
c21a29b383 | |||
f9f1533332 | |||
4f45df571f | |||
cd5015642e | |||
d385cd2aa9 | |||
7f285af7b4 | |||
c8c360da99 | |||
53dcdc7bfc | |||
3f1e45f636 | |||
e38c1d3c85 | |||
e48ab084ce | |||
5ea3008f82 | |||
1418808930 | |||
da412e3bdb | |||
98add8f83a | |||
6f1d46d765 | |||
ada2bd6501 | |||
8707cef55a | |||
dc45dfc383 | |||
691ad94498 | |||
535fefe12f | |||
db982814a1 | |||
ebda4660de | |||
f44e377e29 | |||
0a6d4c998d | |||
bd9733d929 | |||
9ae3282dcf | |||
e62fedbd5e | |||
c53ae2afa0 | |||
45e7f6a30c | |||
8fbedf2886 | |||
c0063a6573 | |||
c9795a8213 | |||
8aec402ea2 | |||
adc2079b17 | |||
cee1b5b079 | |||
13d66f2ae7 | |||
901ac05e99 | |||
2bdaed1e6f | |||
b45934cd9e | |||
fceb6e0e13 | |||
f05a9c67ae | |||
f2d1e62204 | |||
8f704f220a | |||
d5093201ee | |||
401777adff | |||
5ff292ba5f | |||
f80cc70d76 | |||
5b8bf780df | |||
bce52596a5 | |||
c3c94b0a63 | |||
14c30fb81c | |||
1130ff6c6d | |||
993c93b34a | |||
dcf0bdb950 | |||
9e2f4313fb | |||
df41020cb8 | |||
1332df4857 | |||
3f23419bb7 | |||
184ff72912 | |||
55ee95df78 | |||
78fe47aaba | |||
1370596f27 | |||
606e56d78f | |||
51226c8e50 | |||
6c9d4aebac | |||
ed8b42fbde | |||
aa56f645e9 | |||
9a1bb788d2 | |||
7d32f79379 | |||
0410cf2fd2 | |||
c9f5e34c0d | |||
047f2abdb5 | |||
f13a6573a8 | |||
596bb6953c | |||
d482e623df | |||
bf910dea02 | |||
57da852af6 | |||
4c21344e8b | |||
302c0fed59 | |||
0e7afe466d | |||
2c757af250 | |||
27f28935d7 | |||
12753dd7d4 | |||
dd8dce1b49 | |||
19280c2bb0 | |||
5c4a1cc082 | |||
a63af05bec | |||
9be7b0e109 | |||
d5b1d9ce39 | |||
a6eb4fef00 | |||
d1c69e8fe5 | |||
81d9e4f560 | |||
61a3afbb3b | |||
91ab616cc5 | |||
43d62f1284 | |||
d61470d6ef | |||
091d23d537 | |||
2f24902436 | |||
36d47b9b88 | |||
2c20771682 | |||
a9cdec6d87 | |||
f1efccea6b | |||
226d8438de | |||
b6d6f85dc0 | |||
49ed10bbee | |||
3afdd3bf13 | |||
0170ed7d6f | |||
dad2e93572 | |||
d726426611 | |||
b31d99b936 | |||
8860d32f97 | |||
b9dff0d22e | |||
297aab1fd3 | |||
54bf7a3819 | |||
52876be723 | |||
ff20e4f49c | |||
ee47ba04bc | |||
688374d13f | |||
22c4212438 | |||
26dcb2f2e0 | |||
46afa266fa | |||
b2d26d9dce | |||
0b622361f3 | |||
ed48909f96 | |||
60d191bb2a | |||
4f482e484f | |||
58a1579832 | |||
6d5cf7a815 | |||
2e92554423 | |||
2456a642b7 | |||
b5108625ff | |||
9ab54f27b1 | |||
4b7037bbe6 | |||
f183603bc0 | |||
544a58325d | |||
9557bdf209 | |||
4890a8510d | |||
66f77b5eb1 | |||
661b6b07a3 | |||
ce8db1065d | |||
9a0e1115ed | |||
2b4c058af8 | |||
a206ad6811 | |||
a1dabcb758 | |||
940c1bb50c | |||
6c49d4fef5 | |||
621df33df9 | |||
7e86ba002f | |||
6f12cb36af | |||
4ef35aadb6 | |||
d4081c15e1 | |||
6e870b4d0b | |||
1e78ccd204 | |||
84e9b63524 | |||
4cc7f13b6e | |||
fc2d0d1852 | |||
ef98ad54fa | |||
4785e09945 | |||
d4f9bb6da3 | |||
ab41eaa5d9 | |||
02794f368b | |||
9c66cc4c32 | |||
68401caf1c | |||
4f466bb5a1 | |||
daaea77144 | |||
faa1cb52dd | |||
57ac14f295 | |||
d0f4820baa | |||
b0261e8cc6 | |||
30a7aa0e9c | |||
5f0b7467d1 | |||
24363b653f | |||
21a3048b96 | |||
5679ab435f | |||
c9b3edd0f1 | |||
31e6e42a30 | |||
1a868c6847 | |||
a9d6f1fefe | |||
dbfcd5b58c | |||
6a52a48b71 | |||
e31492a9b4 | |||
f2dbc4f717 | |||
1d040ad64d | |||
8703749292 | |||
d432a84c42 | |||
c00492cad0 | |||
c4d545a256 | |||
d0c429c8a1 | |||
a8b6883183 | |||
5590b32c93 | |||
97e7022121 | |||
2926d1a11d | |||
58debafa8a | |||
e021390568 | |||
389e68f6ba | |||
7eeb2ea7e6 | |||
954bddeb64 | |||
9255afd060 | |||
a0a32b930e | |||
fc4b78f74a | |||
9e063a6e6f | |||
54823b41e1 | |||
03a1793208 |
@ -1,10 +1,13 @@
|
||||
.git
|
||||
.github
|
||||
.travis.yml
|
||||
.git*
|
||||
*.md
|
||||
env
|
||||
build*
|
||||
docker-compose.override.yml
|
||||
docker-compose*
|
||||
env
|
||||
test-configuration
|
||||
.netbox/.git*
|
||||
.netbox/.travis.yml
|
||||
.netbox/.pre-commit-config.yaml
|
||||
.netbox/.readthedocs.yaml
|
||||
.netbox/.tx
|
||||
.netbox/contrib
|
||||
.netbox/scripts
|
||||
.netbox/upgrade.sh
|
||||
|
@ -9,3 +9,6 @@ indent_size = 2
|
||||
|
||||
[*.py]
|
||||
indent_size = 4
|
||||
|
||||
[VERSION]
|
||||
insert_final_newline = false
|
||||
|
@ -2,17 +2,12 @@
|
||||
"Verbose": false,
|
||||
"Debug": false,
|
||||
"IgnoreDefaults": false,
|
||||
"SpacesAftertabs": false,
|
||||
"SpacesAfterTabs": false,
|
||||
"NoColor": false,
|
||||
"Exclude": [
|
||||
"LICENSE",
|
||||
"\\.initializers",
|
||||
"\\.vscode"
|
||||
],
|
||||
"Exclude": ["LICENSE", "\\.initializers", "\\.vscode"],
|
||||
"AllowedContentTypes": [],
|
||||
"PassedFiles": [],
|
||||
"Disable": {
|
||||
// set these options to true to disable specific checks
|
||||
"EndOfLine": false,
|
||||
"Indentation": false,
|
||||
"InsertFinalNewline": false,
|
4
.github/FUNDING.yml
vendored
4
.github/FUNDING.yml
vendored
@ -1,8 +1,8 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
||||
- cimnine
|
||||
- tobiasge
|
||||
- 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
|
||||
|
86
.github/ISSUE_TEMPLATE/bug_report.md
vendored
86
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@ -1,86 +0,0 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report about a malfunction of the Docker setup
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
<!--
|
||||
|
||||
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.
|
||||
|
||||
-->
|
||||
|
||||
## 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 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 `cat docker-compose.override.yml`:
|
||||
<!--
|
||||
If this file is very long, create a Gist instead and post the link to it: https://gist.github.com
|
||||
-->
|
||||
|
||||
```text
|
||||
LOG LOG LOG
|
||||
```
|
147
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
147
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
@ -0,0 +1,147 @@
|
||||
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` (or `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: |
|
||||
services:
|
||||
netbox:
|
||||
ports:
|
||||
- '8080:8080'
|
||||
validations:
|
||||
required: true
|
2
.github/ISSUE_TEMPLATE/config.yml
vendored
2
.github/ISSUE_TEMPLATE/config.yml
vendored
@ -6,7 +6,7 @@ contact_links:
|
||||
|
||||
- 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.'
|
||||
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
|
||||
|
68
.github/ISSUE_TEMPLATE/feature_request.md
vendored
68
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@ -1,68 +0,0 @@
|
||||
---
|
||||
name: Feature or Change Request
|
||||
about: Request a new feature or a change of the current behavior
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
<!--
|
||||
|
||||
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.
|
||||
|
||||
-->
|
||||
|
||||
## 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.
|
||||
-->
|
||||
|
||||
|
68
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
Normal file
68
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
Normal 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
|
6
.github/pull_request_template.md
vendored
6
.github/pull_request_template.md
vendored
@ -80,6 +80,6 @@ into the release notes.
|
||||
Please put an x into the brackets (like `[x]`) if you've completed that task.
|
||||
-->
|
||||
|
||||
* [ ] I have read the comments and followed the PR template.
|
||||
* [ ] I have explained my PR according to the information in the comments.
|
||||
* [ ] My PR targets the `develop` branch.
|
||||
- [ ] I have read the comments and followed the PR template.
|
||||
- [ ] I have explained my PR according to the information in the comments.
|
||||
- [ ] My PR targets the `develop` branch.
|
||||
|
124
.github/workflows/push.yml
vendored
124
.github/workflows/push.yml
vendored
@ -1,66 +1,100 @@
|
||||
---
|
||||
name: push
|
||||
|
||||
on:
|
||||
push:
|
||||
branches-ignore:
|
||||
- release
|
||||
- renovate/**
|
||||
pull_request:
|
||||
branches-ignore:
|
||||
- release
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-24.04
|
||||
name: Checks syntax of our code
|
||||
permissions:
|
||||
contents: read
|
||||
packages: read
|
||||
statuses: write
|
||||
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
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
# Full git history is needed to get a proper
|
||||
# list of changed files within `super-linter`
|
||||
fetch-depth: 0
|
||||
- name: Lint Code Base
|
||||
uses: super-linter/super-linter@v7
|
||||
env:
|
||||
DEFAULT_BRANCH: develop
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
SUPPRESS_POSSUM: true
|
||||
LINTER_RULES_PATH: /
|
||||
VALIDATE_ALL_CODEBASE: false
|
||||
VALIDATE_CHECKOV: false
|
||||
VALIDATE_DOCKERFILE: false
|
||||
VALIDATE_GITLEAKS: false
|
||||
VALIDATE_JSCPD: false
|
||||
FILTER_REGEX_EXCLUDE: (.*/)?(LICENSE|configuration/.*)
|
||||
EDITORCONFIG_FILE_NAME: .editorconfig-checker.json
|
||||
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
|
||||
YAML_CONFIG_FILE: .yamllint.yaml
|
||||
build:
|
||||
continue-on-error: ${{ matrix.docker_from == 'alpine:edge' }}
|
||||
continue-on-error: ${{ matrix.build_cmd != './build-latest.sh' }}
|
||||
strategy:
|
||||
matrix:
|
||||
build_cmd:
|
||||
- ./build-latest.sh
|
||||
- PRERELEASE=true ./build-latest.sh
|
||||
- ./build.sh feature
|
||||
- ./build.sh develop
|
||||
docker_from:
|
||||
- '' # use the default of the build script
|
||||
- alpine:edge
|
||||
- ./build-latest.sh
|
||||
- PRERELEASE=true ./build-latest.sh
|
||||
- ./build.sh feature
|
||||
- ./build.sh main
|
||||
os:
|
||||
- ubuntu-24.04
|
||||
- ubuntu-24.04-arm
|
||||
fail-fast: false
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
GH_ACTION: enable
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
IMAGE_NAMES: docker.io/netboxcommunity/netbox
|
||||
runs-on: ${{ matrix.os }}
|
||||
name: Builds new NetBox Docker Images
|
||||
steps:
|
||||
- id: git-checkout
|
||||
name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
- id: docker-build
|
||||
name: Build the image from '${{ matrix.docker_from }}' with '${{ matrix.build_cmd }}'
|
||||
run: ${{ matrix.build_cmd }}
|
||||
env:
|
||||
DOCKER_FROM: ${{ matrix.docker_from }}
|
||||
GH_ACTION: enable
|
||||
- id: docker-test
|
||||
name: Test the image
|
||||
run: IMAGE="${FINAL_DOCKER_TAG}" ./test.sh
|
||||
if: steps.docker-build.outputs.skipped != 'true'
|
||||
- id: git-checkout
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- id: buildx-setup
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
- id: arm-install-skopeo
|
||||
name: Install 'skopeo' on ARM64
|
||||
if: matrix.os == 'ubuntu-24.04-arm'
|
||||
run: |
|
||||
sudo apt-get install -y skopeo
|
||||
- id: arm-buildx-platform
|
||||
name: Set BUILDX_PLATFORM to ARM64
|
||||
if: matrix.os == 'ubuntu-24.04-arm'
|
||||
run: |
|
||||
echo "BUILDX_PLATFORM=linux/arm64" >>"${GITHUB_ENV}"
|
||||
- id: docker-build
|
||||
name: Build the image for '${{ matrix.os }}' with '${{ matrix.build_cmd }}'
|
||||
run: ${{ matrix.build_cmd }}
|
||||
env:
|
||||
BUILDX_BUILDER_NAME: ${{ steps.buildx-setup.outputs.name }}
|
||||
- id: arm-time-limit
|
||||
name: Set Netbox container start_period higher on ARM64
|
||||
if: matrix.os == 'ubuntu-24.04-arm'
|
||||
run: |
|
||||
echo "NETBOX_START_PERIOD=240s" >>"${GITHUB_ENV}"
|
||||
- id: docker-test
|
||||
name: Test the image
|
||||
run: IMAGE="${FINAL_DOCKER_TAG}" ./test.sh
|
||||
if: steps.docker-build.outputs.skipped != 'true'
|
||||
|
147
.github/workflows/release.yml
vendored
147
.github/workflows/release.yml
vendored
@ -1,83 +1,88 @@
|
||||
---
|
||||
name: release
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- release
|
||||
release:
|
||||
types:
|
||||
- published
|
||||
schedule:
|
||||
- cron: '45 5 * * *'
|
||||
- cron: "45 5 * * *"
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
build_cmd:
|
||||
- ./build-latest.sh
|
||||
- PRERELEASE=true ./build-latest.sh
|
||||
- ./build.sh feature
|
||||
- ./build.sh develop
|
||||
build:
|
||||
- { "cmd": "./build-latest.sh", "branch": "release" }
|
||||
- { "cmd": "./build.sh main", "branch": "release" }
|
||||
# Build pre release images from our develop branch
|
||||
# This is used to test the latest changes before they are merged into the main branch
|
||||
- { "cmd": "PRERELEASE=true ./build-latest.sh", "branch": "develop" }
|
||||
- { "cmd": "./build.sh feature", "branch": "develop" }
|
||||
platform:
|
||||
- linux/amd64,linux/arm64
|
||||
fail-fast: false
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-24.04
|
||||
name: Builds new NetBox Docker Images
|
||||
env:
|
||||
GH_ACTION: enable
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
IMAGE_NAMES: docker.io/netboxcommunity/netbox quay.io/netboxcommunity/netbox ghcr.io/netbox-community/netbox
|
||||
steps:
|
||||
- id: git-checkout
|
||||
name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
- id: docker-build
|
||||
name: Build the image with '${{ matrix.build_cmd }}'
|
||||
run: ${{ matrix.build_cmd }}
|
||||
env:
|
||||
GH_ACTION: enable
|
||||
- id: docker-test
|
||||
name: Test the image
|
||||
run: IMAGE="${FINAL_DOCKER_TAG}" ./test.sh
|
||||
if: steps.docker-build.outputs.skipped != 'true'
|
||||
- id: registry-login
|
||||
name: Login to the Docker Registry
|
||||
run: |
|
||||
echo "::add-mask::$DOCKERHUB_USERNAME"
|
||||
echo "::add-mask::$DOCKERHUB_PASSWORD"
|
||||
docker login -u "$DOCKERHUB_USERNAME" --password "${DOCKERHUB_PASSWORD}" "${DOCKER_REGISTRY}"
|
||||
env:
|
||||
DOCKERHUB_USERNAME: ${{ secrets.dockerhub_username }}
|
||||
DOCKERHUB_PASSWORD: ${{ secrets.dockerhub_password }}
|
||||
if: steps.docker-build.outputs.skipped != 'true'
|
||||
- id: registry-push
|
||||
name: Push the image
|
||||
run: ${{ matrix.build_cmd }} --push-only
|
||||
if: steps.docker-build.outputs.skipped != 'true'
|
||||
- id: registry-logout
|
||||
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'
|
||||
- id: source-checkout
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ matrix.build.branch }}
|
||||
- id: set-netbox-docker-version
|
||||
name: Get Version of NetBox Docker
|
||||
run: echo "version=$(cat VERSION)" >>"$GITHUB_OUTPUT"
|
||||
shell: bash
|
||||
- id: check-build-needed
|
||||
name: Check if the build is needed for '${{ matrix.build.cmd }}'
|
||||
env:
|
||||
CHECK_ONLY: "true"
|
||||
run: ${{ matrix.build.cmd }}
|
||||
# docker.io
|
||||
- id: docker-io-login
|
||||
name: Login to docker.io
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: docker.io
|
||||
username: ${{ secrets.dockerhub_username }}
|
||||
password: ${{ secrets.dockerhub_password }}
|
||||
if: steps.check-build-needed.outputs.skipped != 'true'
|
||||
- id: buildx-setup
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
with:
|
||||
version: "lab:latest"
|
||||
driver: cloud
|
||||
endpoint: "netboxcommunity/netbox-default"
|
||||
if: steps.check-build-needed.outputs.skipped != 'true'
|
||||
# quay.io
|
||||
- id: quay-io-login
|
||||
name: Login to Quay.io
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: quay.io
|
||||
username: ${{ secrets.quayio_username }}
|
||||
password: ${{ secrets.quayio_password }}
|
||||
if: steps.check-build-needed.outputs.skipped != 'true'
|
||||
# ghcr.io
|
||||
- id: ghcr-io-login
|
||||
name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
if: steps.check-build-needed.outputs.skipped != 'true'
|
||||
- id: build-and-push
|
||||
name: Push the image
|
||||
run: ${{ matrix.build.cmd }} --push
|
||||
if: steps.check-build-needed.outputs.skipped != 'true'
|
||||
env:
|
||||
BUILDX_PLATFORM: ${{ matrix.platform }}
|
||||
BUILDX_BUILDER_NAME: ${{ steps.buildx-setup.outputs.name }}
|
||||
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,6 +1,6 @@
|
||||
*.sql.gz
|
||||
.netbox
|
||||
.initializers
|
||||
.python-version
|
||||
docker-compose.override.yml
|
||||
*.pem
|
||||
configuration/*
|
||||
@ -11,5 +11,4 @@ configuration/ldap/*
|
||||
!configuration/ldap/ldap_config.py
|
||||
!configuration/logging.py
|
||||
!configuration/plugins.py
|
||||
prometheus.yml
|
||||
super-linter.log
|
||||
|
@ -1,3 +1,4 @@
|
||||
ignored:
|
||||
- DL3006
|
||||
- DL3018
|
||||
- DL3008
|
||||
- DL3003
|
||||
|
4
.yamllint.yaml
Normal file
4
.yamllint.yaml
Normal file
@ -0,0 +1,4 @@
|
||||
---
|
||||
rules:
|
||||
line-length:
|
||||
max: 160
|
140
Dockerfile
140
Dockerfile
@ -1,32 +1,41 @@
|
||||
ARG FROM
|
||||
FROM ${FROM} as builder
|
||||
FROM ${FROM} AS builder
|
||||
|
||||
RUN apk add --no-cache \
|
||||
bash \
|
||||
build-base \
|
||||
cargo \
|
||||
COPY --from=ghcr.io/astral-sh/uv:0.7 /uv /usr/local/bin/
|
||||
RUN export DEBIAN_FRONTEND=noninteractive \
|
||||
&& apt-get update -qq \
|
||||
&& apt-get upgrade \
|
||||
--yes -qq --no-install-recommends \
|
||||
&& apt-get install \
|
||||
--yes -qq --no-install-recommends \
|
||||
build-essential \
|
||||
ca-certificates \
|
||||
cyrus-sasl-dev \
|
||||
graphviz \
|
||||
jpeg-dev \
|
||||
libevent-dev \
|
||||
libffi-dev \
|
||||
openssl-dev \
|
||||
libldap-dev \
|
||||
libpq-dev \
|
||||
libsasl2-dev \
|
||||
libssl-dev \
|
||||
libxml2-dev \
|
||||
libxmlsec1 \
|
||||
libxmlsec1-dev \
|
||||
libxmlsec1-openssl \
|
||||
libxslt-dev \
|
||||
musl-dev \
|
||||
openldap-dev \
|
||||
postgresql-dev \
|
||||
py3-pip \
|
||||
pkg-config \
|
||||
python3-dev \
|
||||
&& python3 -m venv /opt/netbox/venv \
|
||||
&& /opt/netbox/venv/bin/python3 -m pip install --upgrade \
|
||||
pip \
|
||||
setuptools \
|
||||
wheel
|
||||
&& /usr/local/bin/uv venv /opt/netbox/venv
|
||||
|
||||
ARG NETBOX_PATH
|
||||
COPY ${NETBOX_PATH}/requirements.txt requirements-container.txt /
|
||||
RUN /opt/netbox/venv/bin/pip install \
|
||||
ENV VIRTUAL_ENV=/opt/netbox/venv
|
||||
RUN \
|
||||
# Gunicorn is not needed because we use Nginx Unit
|
||||
sed -i -e '/gunicorn/d' /requirements.txt && \
|
||||
# We need 'social-auth-core[all]' in the Docker image. But if we put it in our own requirements-container.txt
|
||||
# we have potential version conflicts and the build will fail.
|
||||
# That's why we just replace it in the original requirements.txt.
|
||||
sed -i -e 's/social-auth-core/social-auth-core\[all\]/g' /requirements.txt && \
|
||||
# The same is true for 'django-storages'
|
||||
sed -i -e 's/django-storages/django-storages\[azure,boto3,dropbox,google,libcloud,sftp\]/g' /requirements.txt && \
|
||||
/usr/local/bin/uv pip install \
|
||||
-r /requirements.txt \
|
||||
-r /requirements-container.txt
|
||||
|
||||
@ -35,69 +44,69 @@ RUN /opt/netbox/venv/bin/pip install \
|
||||
###
|
||||
|
||||
ARG FROM
|
||||
FROM ${FROM} as main
|
||||
FROM ${FROM} AS main
|
||||
|
||||
RUN apk add --no-cache \
|
||||
bash \
|
||||
COPY docker/unit.list /etc/apt/sources.list.d/unit.list
|
||||
ADD --chmod=444 --chown=0:0 https://unit.nginx.org/keys/nginx-keyring.gpg /usr/share/keyrings/nginx-keyring.gpg
|
||||
RUN export DEBIAN_FRONTEND=noninteractive \
|
||||
&& apt-get update -qq \
|
||||
&& apt-get upgrade \
|
||||
--yes -qq --no-install-recommends \
|
||||
&& apt-get install \
|
||||
--yes -qq --no-install-recommends \
|
||||
bzip2 \
|
||||
ca-certificates \
|
||||
curl \
|
||||
graphviz \
|
||||
libevent \
|
||||
libffi \
|
||||
libjpeg-turbo \
|
||||
libldap-common \
|
||||
libpq5 \
|
||||
libxmlsec1-openssl \
|
||||
openssh-client \
|
||||
openssl \
|
||||
libxslt \
|
||||
postgresql-libs \
|
||||
python3 \
|
||||
py3-pip \
|
||||
unit \
|
||||
unit-python3
|
||||
|
||||
WORKDIR /opt
|
||||
tini \
|
||||
unit-python3.12=1.34.2-1~noble \
|
||||
unit=1.34.2-1~noble \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Copy the modified 'requirements*.txt' files, to have the files actually used during installation
|
||||
COPY --from=builder /requirements.txt /requirements-container.txt /opt/netbox/
|
||||
COPY --from=builder /usr/local/bin/uv /usr/local/bin/
|
||||
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 docker/ldap_config.docker.py /opt/netbox/netbox/netbox/ldap_config.py
|
||||
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/ /etc/netbox/config/
|
||||
COPY docker/nginx-unit.json /etc/unit/
|
||||
COPY VERSION /opt/netbox/VERSION
|
||||
|
||||
WORKDIR /opt/netbox/netbox
|
||||
|
||||
# Must set permissions for '/opt/netbox/netbox/media' directory
|
||||
# to g+w so that pictures can be uploaded to netbox.
|
||||
RUN mkdir -p static /opt/unit/state/ /opt/unit/tmp/ \
|
||||
&& chmod -R g+w media /opt/unit/ \
|
||||
&& cd /opt/netbox/ && /opt/netbox/venv/bin/python -m mkdocs build \
|
||||
&& chown -R unit:root /opt/unit/ media reports scripts \
|
||||
&& chmod -R g+w /opt/unit/ media reports scripts \
|
||||
&& cd /opt/netbox/ && SECRET_KEY="dummyKeyWithMinimumLength-------------------------" /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
|
||||
&& DEBUG="true" SECRET_KEY="dummyKeyWithMinimumLength-------------------------" /opt/netbox/venv/bin/python /opt/netbox/netbox/manage.py collectstatic --no-input \
|
||||
&& mkdir /opt/netbox/netbox/local \
|
||||
&& echo "build: Docker-$(cat /opt/netbox/VERSION)" > /opt/netbox/netbox/local/release.yaml
|
||||
|
||||
ENTRYPOINT [ "/opt/netbox/docker-entrypoint.sh" ]
|
||||
ENV LANG=C.utf8 PATH=/opt/netbox/venv/bin:$PATH VIRTUAL_ENV=/opt/netbox/venv UV_NO_CACHE=1
|
||||
ENTRYPOINT [ "/usr/bin/tini", "--" ]
|
||||
|
||||
CMD [ "/opt/netbox/launch-netbox.sh" ]
|
||||
CMD [ "/opt/netbox/docker-entrypoint.sh", "/opt/netbox/launch-netbox.sh" ]
|
||||
|
||||
LABEL ORIGINAL_TAG="" \
|
||||
NETBOX_GIT_BRANCH="" \
|
||||
NETBOX_GIT_REF="" \
|
||||
NETBOX_GIT_URL="" \
|
||||
# See http://label-schema.org/rc1/#build-time-labels
|
||||
# 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.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" \
|
||||
org.label-schema.vcs-url="https://github.com/netbox-community/netbox-docker.git" \
|
||||
org.label-schema.vcs-ref="" \
|
||||
org.label-schema.version="snapshot" \
|
||||
LABEL netbox.original-tag="" \
|
||||
netbox.git-branch="" \
|
||||
netbox.git-ref="" \
|
||||
netbox.git-url="" \
|
||||
# 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" \
|
||||
@ -109,17 +118,4 @@ LABEL ORIGINAL_TAG="" \
|
||||
org.opencontainers.image.documentation="https://github.com/netbox-community/netbox-docker/wiki" \
|
||||
org.opencontainers.image.source="https://github.com/netbox-community/netbox-docker.git" \
|
||||
org.opencontainers.image.revision="" \
|
||||
org.opencontainers.image.version="snapshot"
|
||||
|
||||
#####
|
||||
## LDAP specific configuration
|
||||
#####
|
||||
|
||||
FROM main as ldap
|
||||
|
||||
RUN apk add --no-cache \
|
||||
libsasl \
|
||||
libldap \
|
||||
util-linux
|
||||
|
||||
COPY docker/ldap_config.docker.py /opt/netbox/netbox/netbox/ldap_config.py
|
||||
org.opencontainers.image.version=""
|
||||
|
19
MAINTAINERS.md
Normal file
19
MAINTAINERS.md
Normal file
@ -0,0 +1,19 @@
|
||||
# Maintainers of _NetBox Docker_
|
||||
|
||||
This file lists all currently recognized maintainers of the _NetBox Docker_ project in alphabetical order:
|
||||
|
||||
- @cimnine
|
||||
- @tobiasge
|
||||
|
||||
## Stepping Down
|
||||
|
||||
Every maintainer is a volunteer and may step down as maintainer at any time without providing any reason.
|
||||
To make this explicit, the maintainer is asked to update this file.
|
||||
|
||||
The last maintainer stepping down is asked to archive the project on GitHub to indicate that the project is no longer maintained.
|
||||
|
||||
## Signing up
|
||||
|
||||
Everyone is welcome to sign up as maintainer by creating a PR and add their own username to the list.
|
||||
The current maintainers shall discuss the application.
|
||||
They may turn down an application if they don't feel confident that the new maintainer is a positive addition.
|
71
PRINCIPALS.md
Normal file
71
PRINCIPALS.md
Normal file
@ -0,0 +1,71 @@
|
||||
# Development, Maintenance and Community Principals for _NetBox Docker_
|
||||
|
||||
These principals shall guide the development and the maintenance of _NetBox Docker_.
|
||||
|
||||
## Basic principals
|
||||
|
||||
This project is maintained on voluntary basis.
|
||||
Everyone is asked to respect that.
|
||||
|
||||
This means, that …
|
||||
|
||||
- … sometimes features are not implemented as fast as one might like -- or not at all.
|
||||
- … sometimes nobody is looking at bugs, or they are not fixed as fast as one might like -- or not at all.
|
||||
- … sometimes PRs are not reviewed for an extended period.
|
||||
|
||||
Everyone is welcome to provide improvements and bugfixes to the benefit of everyone else.
|
||||
|
||||
## Development Principals
|
||||
|
||||
The goal of the _NetBox Docker_ project is to provide a container to run the basic NetBox project.
|
||||
The container should feel like a native container -- as if it were provided by NetBox itself:
|
||||
|
||||
- Configuration via environment variables where feasible.
|
||||
- Except: Whenever a complex type such as a `dict` is required as value of a configuration setting,
|
||||
then it shall not be provided through an environment variable.
|
||||
- Configuration of secrets via secret files.
|
||||
- Log output to standard out (STDOUT/`&1`) / standard error (STDERR/`&2`).
|
||||
- Volumes for data and cache directories.
|
||||
- Otherwise, no mounts shall be necessary.
|
||||
- Runs a non-root user by default.
|
||||
- One process / role for each instance.
|
||||
|
||||
The container generally does not provide more features than the basic NetBox project itself provides.
|
||||
It may provide additional Python dependencies than the upstream project,
|
||||
so that all configurable features of NetBox can be used in the container without further modification.
|
||||
The container may provide helpers, so that it feels and behaves like a native container.
|
||||
|
||||
The container does not bundle any community plugins.
|
||||
|
||||
## Maintenance Principals
|
||||
|
||||
The main goals of maintaining _NetBox Docker_ are:
|
||||
|
||||
- Keeping the project at a high quality level.
|
||||
- Keeping the maintenance effort minimal.
|
||||
- Coordinating development efforts.
|
||||
|
||||
The following guidelines help us to achieve these goals:
|
||||
|
||||
- As many maintenance tasks as possible shall be automated or scripted.
|
||||
- All manual tasks must be documented.
|
||||
- All changes are reviewed by at least one maintainer.
|
||||
- Changes of maintainers are reviewed by at least one other maintainer.
|
||||
(Except if there's only one maintainer left.)
|
||||
- The infrastructure beyond what GitHub provides shall be kept to a minimum.
|
||||
- On request, every maintainer shall get access to infrastructure that is beyond GitHub
|
||||
(at the time of writing that's _Docker Hub_ and _Quay_ in particular).
|
||||
|
||||
## Community Principals
|
||||
|
||||
This project is developed by the NetBox community for the NetBox community.
|
||||
We welcome contributions, as long as they are in line with the principals above.
|
||||
|
||||
The maintainers of NetBox Docker are not the support team.
|
||||
The community is expected to help each other out.
|
||||
|
||||
Always remember:
|
||||
Behind every screen (or screen-reader) on the other end is a fellow human.
|
||||
Be nice and respectful, thankful for help,
|
||||
and value ideas and contributions,
|
||||
even when they don't fit the goals.
|
138
README.md
138
README.md
@ -3,92 +3,117 @@
|
||||
[][github-release]
|
||||
[][github-stargazers]
|
||||

|
||||

|
||||

|
||||

|
||||
[][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] and [Quay.io][netbox-quayio] once a day.
|
||||
[The GitHub repository][netbox-docker-github] houses the components needed to build NetBox as a container.
|
||||
Images are built regularly using the code in that repository
|
||||
and are pushed to [Docker Hub][netbox-dockerhub],
|
||||
[Quay.io][netbox-quayio] and [GitHub Container Registry][netbox-ghcr].
|
||||
_NetBox Docker_ is a project developed and maintained by the _NetBox_ community.
|
||||
|
||||
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.
|
||||
Before opening an issue on GitHub,
|
||||
please join [our Slack][netbox-docker-slack]
|
||||
and ask for help in the [`#netbox-docker`][netbox-docker-slack-channel] channel,
|
||||
or start a new [GitHub Discussion][github-discussions].
|
||||
|
||||
[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/
|
||||
[netbox-quayio]: https://quay.io/repository/netboxcommunity/netbox
|
||||
[netbox-ghcr]: https://github.com/netbox-community/netbox-docker/pkgs/container/netbox
|
||||
[netbox-docker-github]: https://github.com/netbox-community/netbox-docker/
|
||||
[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`: 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 tags:
|
||||
|
||||
* `-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
|
||||
[netbox-branches]: https://github.com/netbox-community/netbox/branches
|
||||
[netbox-docker-ldap]: https://github.com/netbox-community/netbox-docker/wiki/LDAP
|
||||
[github-discussions]: https://github.com/netbox-community/netbox-docker/discussions
|
||||
|
||||
## Quickstart
|
||||
|
||||
To get NetBox Docker up and running run the following commands.
|
||||
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
|
||||
docker compose pull
|
||||
docker compose up
|
||||
```
|
||||
|
||||
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**
|
||||
To create the first admin user run this command:
|
||||
|
||||
```bash
|
||||
docker compose exec netbox /opt/netbox/netbox/manage.py createsuperuser
|
||||
```
|
||||
|
||||
If you need to restart Netbox from an empty database often,
|
||||
you can also set the `SUPERUSER_*` variables in your `docker-compose.override.yml`.
|
||||
|
||||
[wiki-getting-started]: https://github.com/netbox-community/netbox-docker/wiki/Getting-Started
|
||||
[docker-reception]: https://github.com/nxt-engineering/reception
|
||||
|
||||
## Container Image Tags
|
||||
|
||||
New container images are built and published automatically every ~24h.
|
||||
|
||||
> We recommend to use either the `vX.Y.Z-a.b.c` tags or the `vX.Y-a.b.c` tags in production!
|
||||
|
||||
- `vX.Y.Z-a.b.c`, `vX.Y-a.b.c`:
|
||||
These are release builds containing _NetBox version_ `vX.Y.Z`.
|
||||
They contain the support files of _NetBox Docker version_ `a.b.c`.
|
||||
You must use _NetBox Docker version_ `a.b.c` to guarantee the compatibility.
|
||||
These images are automatically built from [the corresponding releases of NetBox][netbox-releases].
|
||||
- `latest-a.b.c`:
|
||||
These are release builds, containing the latest stable version of NetBox.
|
||||
They contain the support files of _NetBox Docker version_ `a.b.c`.
|
||||
You must use _NetBox Docker version_ `a.b.c` to guarantee the compatibility.
|
||||
- `snapshot-a.b.c`:
|
||||
These are prerelease builds.
|
||||
They contain the support files of _NetBox Docker version_ `a.b.c`.
|
||||
You must use _NetBox Docker version_ `a.b.c` to guarantee the compatibility.
|
||||
These images are automatically built from the [`main` branch of NetBox][netbox-main].
|
||||
|
||||
For each of the above tag, there is an extra tag:
|
||||
|
||||
- `vX.Y.Z`, `vX.Y`:
|
||||
This is the same version as `vX.Y.Z-a.b.c` (or `vX.Y-a.b.c`, respectively).
|
||||
- `latest`
|
||||
This is the same version as `latest-a.b.c`.
|
||||
It always points to the latest version of _NetBox Docker_.
|
||||
- `snapshot`
|
||||
This is the same version as `snapshot-a.b.c`.
|
||||
It always points to the latest version of _NetBox Docker_.
|
||||
|
||||
[netbox-releases]: https://github.com/netbox-community/netbox/releases
|
||||
[netbox-main]: https://github.com/netbox-community/netbox/tree/main
|
||||
|
||||
## 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.
|
||||
Please refer [to our wiki on GitHub][netbox-docker-wiki] for further information on how to use the NetBox Docker image properly.
|
||||
The wiki covers advanced topics such as using files for secrets, configuring TLS, deployment to Kubernetes, monitoring and configuring LDAP.
|
||||
|
||||
Our wiki is a community effort.
|
||||
Feel free to correct errors, update outdated information or provide additional guides and insights.
|
||||
|
||||
[netbox-docker-wiki]: https://github.com/netbox-community/netbox-docker/wiki/
|
||||
|
||||
## Getting Help
|
||||
|
||||
Feel free to ask questions in our [Github Community][netbox-community]
|
||||
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.
|
||||
which is free to use and where there are almost always people online that can help you.
|
||||
|
||||
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.
|
||||
@ -97,29 +122,28 @@ you may find [the `#netbox` channel][netbox-slack-channel] on the same Slack ins
|
||||
|
||||
## Dependencies
|
||||
|
||||
This project relies only on *Docker* and *docker-compose* meeting these requirements:
|
||||
This project relies only on _Docker_ and _docker-compose_ meeting these requirements:
|
||||
|
||||
* The *Docker version* must be at least `19.03`.
|
||||
* The *docker-compose version* must be at least `1.28.0`.
|
||||
- The _Docker version_ must be at least `20.10.10`.
|
||||
- The _containerd version_ must be at least `1.5.6`.
|
||||
- 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`.
|
||||
To check the version installed on your system run `docker --version` and `docker compose version`.
|
||||
|
||||
## Breaking Changes
|
||||
|
||||
From time to time it might become necessary to re-engineer the structure of this setup.
|
||||
Things like the `docker-compose.yml` file or your Kubernetes or OpenShift configurations have to be adjusted as a consequence.
|
||||
|
||||
Since November 2019 each image built from this repo contains a `org.opencontainers.image.version` label.
|
||||
(The images contained labels since April 2018, although in November 2019 the labels' names changed.)
|
||||
You can check the label of your local image by running `docker inspect netboxcommunity/netbox:v2.7.1 --format "{{json .Config.Labels}}"`.
|
||||
## Updating
|
||||
|
||||
Please read [the release notes][releases] carefully when updating to a new image version.
|
||||
Note that the version of the NetBox Docker container image must stay in sync with the version of the Git repository.
|
||||
|
||||
If you update for the first time, be sure [to follow our _How To Update NetBox Docker_ guide in the wiki][netbox-docker-wiki-updating].
|
||||
|
||||
[releases]: https://github.com/netbox-community/netbox-docker/releases
|
||||
[netbox-docker-wiki-updating]: https://github.com/netbox-community/netbox-docker/wiki/Updating
|
||||
|
||||
## Rebuilding the Image
|
||||
|
||||
`./build.sh` can be used to rebuild the Docker image. See `./build.sh --help` for more information.
|
||||
`./build.sh` can be used to rebuild the container image.
|
||||
See `./build.sh --help` for more information or `./build-latest.sh` for an example.
|
||||
|
||||
For more details on custom builds [consult our wiki][netbox-docker-wiki-build].
|
||||
|
||||
@ -128,13 +152,15 @@ For more details on custom builds [consult our wiki][netbox-docker-wiki-build].
|
||||
## 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 NetBox starts:
|
||||
|
||||
```bash
|
||||
IMAGE=netboxcommunity/netbox:latest ./test.sh
|
||||
IMAGE=docker.io/netboxcommunity/netbox:latest ./test.sh
|
||||
```
|
||||
|
||||
## Support
|
||||
|
||||
This repository is currently maintained by the community.
|
||||
The community is expected to help each other.
|
||||
|
||||
Please consider sponsoring the maintainers of this project.
|
||||
|
5
actionlint.yml
Normal file
5
actionlint.yml
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
paths:
|
||||
.github/workflows/**/*.{yml,yaml}:
|
||||
ignore:
|
||||
- ".*ubuntu-24.04-arm.*"
|
9
build-functions/check-commands.sh
Normal file
9
build-functions/check-commands.sh
Normal file
@ -0,0 +1,9 @@
|
||||
#!/bin/bash
|
||||
|
||||
NEEDED_COMMANDS="curl jq docker skopeo"
|
||||
for c in $NEEDED_COMMANDS; do
|
||||
if ! command -v "$c" &>/dev/null; then
|
||||
echo "⚠️ '$c' is not installed. Can't proceed with build."
|
||||
exit 1
|
||||
fi
|
||||
done
|
@ -1,8 +0,0 @@
|
||||
#!/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}'."
|
||||
}
|
@ -1,82 +1,18 @@
|
||||
#!/bin/bash
|
||||
# Retrieves image configuration from public images in DockerHub
|
||||
# Functions from https://gist.github.com/cirocosta/17ea17be7ac11594cb0f290b0a3ac0d1
|
||||
# Optimised for our use case
|
||||
|
||||
check_if_tags_exists() {
|
||||
local image=$1
|
||||
local tag=$2
|
||||
skopeo list-tags "docker://$image" | jq -r ".Tags | contains([\"$tag\"])"
|
||||
}
|
||||
|
||||
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"
|
||||
skopeo inspect "docker://$image" | jq -r ".Labels[\"$label\"]"
|
||||
}
|
||||
|
||||
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'
|
||||
skopeo inspect "docker://$image" | jq -r ".Layers | last"
|
||||
}
|
||||
|
32
build-functions/gh-functions.sh
Normal file
32
build-functions/gh-functions.sh
Normal file
@ -0,0 +1,32 @@
|
||||
#!/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
|
||||
}
|
||||
|
||||
###
|
||||
# Prints the output to the file defined in ${GITHUB_OUTPUT}.
|
||||
# Only executes if ${GH_ACTION} is defined.
|
||||
# Example Usage: gh_env "FOO_VAR=bar_value"
|
||||
###
|
||||
gh_out() {
|
||||
if [ -n "${GH_ACTION}" ]; then
|
||||
echo "${@}" >>"$GITHUB_OUTPUT"
|
||||
fi
|
||||
}
|
@ -1,18 +1,27 @@
|
||||
#!/bin/bash
|
||||
# Builds the latest released version
|
||||
|
||||
# Check if we have everything needed for the build
|
||||
source ./build-functions/check-commands.sh
|
||||
|
||||
source ./build-functions/gh-functions.sh
|
||||
|
||||
echo "▶️ $0 $*"
|
||||
|
||||
CURL_ARGS=(
|
||||
--silent
|
||||
)
|
||||
|
||||
###
|
||||
# Checking for the presence of GITHUB_OAUTH_CLIENT_ID
|
||||
# and GITHUB_OAUTH_CLIENT_SECRET
|
||||
# Checking for the presence of GITHUB_TOKEN
|
||||
###
|
||||
if [ -n "${GITHUB_OAUTH_CLIENT_ID}" ] && [ -n "${GITHUB_OAUTH_CLIENT_SECRET}" ]; then
|
||||
if [ -n "${GITHUB_TOKEN}" ]; then
|
||||
echo "🗝 Performing authenticated Github API calls."
|
||||
GITHUB_OAUTH_PARAMS="client_id=${GITHUB_OAUTH_CLIENT_ID}&client_secret=${GITHUB_OAUTH_CLIENT_SECRET}"
|
||||
CURL_ARGS+=(
|
||||
--header "Authorization: Bearer ${GITHUB_TOKEN}"
|
||||
)
|
||||
else
|
||||
echo "🕶 Performing unauthenticated Github API calls. This might result in lower Github rate limits!"
|
||||
GITHUB_OAUTH_PARAMS=""
|
||||
fi
|
||||
|
||||
###
|
||||
@ -34,31 +43,27 @@ fi
|
||||
###
|
||||
ORIGINAL_GITHUB_REPO="netbox-community/netbox"
|
||||
GITHUB_REPO="${GITHUB_REPO-$ORIGINAL_GITHUB_REPO}"
|
||||
URL_RELEASES="https://api.github.com/repos/${GITHUB_REPO}/releases?${GITHUB_OAUTH_PARAMS}"
|
||||
URL_RELEASES="https://api.github.com/repos/${GITHUB_REPO}/releases"
|
||||
|
||||
# Composing the JQ commans to extract the most recent version number
|
||||
JQ_LATEST="group_by(.prerelease) | .[] | sort_by(.published_at) | reverse | .[0] | select(.prerelease==${PRERELEASE-false}) | .tag_name"
|
||||
|
||||
CURL="curl -sS"
|
||||
CURL="curl"
|
||||
|
||||
# Querying the Github API to fetch the most recent version number
|
||||
VERSION=$($CURL "${URL_RELEASES}" | jq -r "${JQ_LATEST}")
|
||||
VERSION=$($CURL "${CURL_ARGS[@]}" "${URL_RELEASES}" | jq -r "${JQ_LATEST}" 2>/dev/null)
|
||||
|
||||
###
|
||||
# Check if the prerelease version is actually higher than stable version
|
||||
###
|
||||
if [ "${PRERELEASE}" == "true" ]; then
|
||||
JQ_STABLE="group_by(.prerelease) | .[] | sort_by(.published_at) | reverse | .[0] | select(.prerelease==false) | .tag_name"
|
||||
STABLE_VERSION=$($CURL "${URL_RELEASES}" | jq -r "${JQ_STABLE}")
|
||||
STABLE_VERSION=$($CURL "${CURL_ARGS[@]}" "${URL_RELEASES}" | jq -r "${JQ_STABLE}" 2>/dev/null)
|
||||
|
||||
# shellcheck disable=SC2003
|
||||
MAJOR_STABLE=$(expr match "${STABLE_VERSION}" 'v\([0-9]\+\)')
|
||||
# shellcheck disable=SC2003
|
||||
MINOR_STABLE=$(expr match "${STABLE_VERSION}" 'v[0-9]\+\.\([0-9]\+\)')
|
||||
# shellcheck disable=SC2003
|
||||
MAJOR_UNSTABLE=$(expr match "${VERSION}" 'v\([0-9]\+\)')
|
||||
# shellcheck disable=SC2003
|
||||
MINOR_UNSTABLE=$(expr match "${VERSION}" 'v[0-9]\+\.\([0-9]\+\)')
|
||||
MAJOR_STABLE=$(expr "${STABLE_VERSION}" : 'v\([0-9]\+\)')
|
||||
MINOR_STABLE=$(expr "${STABLE_VERSION}" : 'v[0-9]\+\.\([0-9]\+\)')
|
||||
MAJOR_UNSTABLE=$(expr "${VERSION}" : 'v\([0-9]\+\)')
|
||||
MINOR_UNSTABLE=$(expr "${VERSION}" : 'v[0-9]\+\.\([0-9]\+\)')
|
||||
|
||||
if {
|
||||
[ "${MAJOR_STABLE}" -eq "${MAJOR_UNSTABLE}" ] &&
|
||||
@ -67,10 +72,7 @@ if [ "${PRERELEASE}" == "true" ]; then
|
||||
|
||||
echo "❎ Latest unstable version '${VERSION}' is not higher than the latest stable version '$STABLE_VERSION'."
|
||||
if [ -z "$DEBUG" ]; then
|
||||
if [ -n "${GH_ACTION}" ]; then
|
||||
echo "::set-output name=skipped::true"
|
||||
fi
|
||||
|
||||
gh_out "skipped=true"
|
||||
exit 0
|
||||
else
|
||||
echo "⚠️ Would exit here with code '0', but DEBUG is enabled."
|
||||
|
587
build.sh
587
build.sh
@ -6,87 +6,127 @@ echo "▶️ $0 $*"
|
||||
set -e
|
||||
|
||||
if [ "${1}x" == "x" ] || [ "${1}" == "--help" ] || [ "${1}" == "-h" ]; then
|
||||
echo "Usage: ${0} <branch> [--push|--push-only]"
|
||||
echo " branch The branch or tag to build. Required."
|
||||
echo " --push Pushes the built Docker image to the registry."
|
||||
echo " --push-only Only pushes the Docker image to the registry, but does not build it."
|
||||
echo ""
|
||||
echo "You can use the following ENV variables to customize the build:"
|
||||
echo " SRC_ORG Which fork of netbox to use (i.e. github.com/\${SRC_ORG}/\${SRC_REPO})."
|
||||
echo " Default: netbox-community"
|
||||
echo " SRC_REPO The name of the repository to use (i.e. github.com/\${SRC_ORG}/\${SRC_REPO})."
|
||||
echo " Default: netbox"
|
||||
echo " URL Where to fetch the code from."
|
||||
echo " Must be a git repository. Can be private."
|
||||
echo " Default: https://github.com/\${SRC_ORG}/\${SRC_REPO}.git"
|
||||
echo " NETBOX_PATH The path where netbox will be checkout out."
|
||||
echo " Must not be outside of the netbox-docker repository (because of Docker)!"
|
||||
echo " Default: .netbox"
|
||||
echo " SKIP_GIT If defined, git is not invoked and \${NETBOX_PATH} will not be altered."
|
||||
echo " This may be useful, if you are manually managing the NETBOX_PATH."
|
||||
echo " Default: undefined"
|
||||
echo " TAG The version part of the docker tag."
|
||||
echo " Default:"
|
||||
echo " When <branch>=master: latest"
|
||||
echo " When <branch>=develop: snapshot"
|
||||
echo " Else: same as <branch>"
|
||||
echo " DOCKER_REGISTRY The Docker repository's registry (i.e. '\${DOCKER_REGISTRY}/\${DOCKER_ORG}/\${DOCKER_REPO}'')"
|
||||
echo " Used for tagging the image."
|
||||
echo " Default: docker.io"
|
||||
echo " DOCKER_ORG The Docker repository's organisation (i.e. '\${DOCKER_REGISTRY}/\${DOCKER_ORG}/\${DOCKER_REPO}'')"
|
||||
echo " Used for tagging the image."
|
||||
echo " Default: netboxcommunity"
|
||||
echo " DOCKER_REPO The Docker repository's name (i.e. '\${DOCKER_REGISTRY}/\${DOCKER_ORG}/\${DOCKER_REPO}'')"
|
||||
echo " Used for tagging the image."
|
||||
echo " Default: netbox"
|
||||
echo " DOCKER_TAG The name of the tag which is applied to the image."
|
||||
echo " Useful for pushing into another registry than hub.docker.com."
|
||||
echo " Default: \${DOCKER_REGISTRY}/\${DOCKER_ORG}/\${DOCKER_REPO}:\${TAG}"
|
||||
echo " DOCKER_SHORT_TAG The name of the short tag which is applied to the"
|
||||
echo " image. This is used to tag all patch releases to their"
|
||||
echo " containing version e.g. v2.5.1 -> v2.5"
|
||||
echo " Default: \${DOCKER_REGISTRY}/\${DOCKER_ORG}/\${DOCKER_REPO}:<MAJOR>.<MINOR>"
|
||||
echo " DOCKERFILE The name of Dockerfile to use."
|
||||
echo " Default: Dockerfile"
|
||||
echo " DOCKER_FROM The base image to use."
|
||||
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"
|
||||
echo " HTTP_PROXY The proxy to use for http requests."
|
||||
echo " Example: http://proxy.domain.tld:3128"
|
||||
echo " Default: undefined"
|
||||
echo " NO_PROXY Comma-separated list of domain extensions proxy should not be used for."
|
||||
echo " Example: .domain1.tld,.domain2.tld"
|
||||
echo " Default: undefined"
|
||||
echo " DEBUG If defined, the script does not stop when certain checks are unsatisfied."
|
||||
echo " Default: undefined"
|
||||
echo " DRY_RUN Prints all build statements instead of running them."
|
||||
echo " Default: undefined"
|
||||
echo " GH_ACTION If defined, special 'echo' statements are enabled that set the"
|
||||
echo " following environment variables in Github Actions:"
|
||||
echo " - FINAL_DOCKER_TAG: The final value of the DOCKER_TAG env variable"
|
||||
echo " Default: undefined"
|
||||
echo ""
|
||||
echo "Examples:"
|
||||
echo " ${0} master"
|
||||
echo " This will fetch the latest 'master' branch, build a Docker Image and tag it"
|
||||
echo " 'netboxcommunity/netbox:latest'."
|
||||
echo " ${0} develop"
|
||||
echo " This will fetch the latest 'develop' branch, build a Docker Image and tag it"
|
||||
echo " 'netboxcommunity/netbox:snapshot'."
|
||||
echo " ${0} v2.6.6"
|
||||
echo " This will fetch the 'v2.6.6' tag, build a Docker Image and tag it"
|
||||
echo " 'netboxcommunity/netbox:v2.6.6' and 'netboxcommunity/netbox:v2.6'."
|
||||
echo " ${0} develop-2.7"
|
||||
echo " This will fetch the 'develop-2.7' branch, build a Docker Image and tag it"
|
||||
echo " 'netboxcommunity/netbox:develop-2.7'."
|
||||
echo " SRC_ORG=cimnine ${0} feature-x"
|
||||
echo " This will fetch the 'feature-x' branch from https://github.com/cimnine/netbox.git,"
|
||||
echo " build a Docker Image and tag it 'netboxcommunity/netbox:feature-x'."
|
||||
echo " SRC_ORG=cimnine DOCKER_ORG=cimnine ${0} feature-x"
|
||||
echo " This will fetch the 'feature-x' branch from https://github.com/cimnine/netbox.git,"
|
||||
echo " build a Docker Image and tag it 'cimnine/netbox:feature-x'."
|
||||
_BOLD=$(tput bold)
|
||||
_GREEN=$(tput setaf 2)
|
||||
_CYAN=$(tput setaf 6)
|
||||
_CLEAR=$(tput sgr0)
|
||||
|
||||
cat <<END_OF_HELP
|
||||
${_BOLD}Usage:${_CLEAR} ${0} <branch> [--push]
|
||||
|
||||
branch The branch or tag to build. Required.
|
||||
--push Pushes the built container image to the registry.
|
||||
|
||||
${_BOLD}You can use the following ENV variables to customize the build:${_CLEAR}
|
||||
|
||||
SRC_ORG Which fork of netbox to use (i.e. github.com/\${SRC_ORG}/\${SRC_REPO}).
|
||||
${_GREEN}Default:${_CLEAR} netbox-community
|
||||
|
||||
SRC_REPO The name of the repository to use (i.e. github.com/\${SRC_ORG}/\${SRC_REPO}).
|
||||
${_GREEN}Default:${_CLEAR} netbox
|
||||
|
||||
URL Where to fetch the code from.
|
||||
Must be a git repository. Can be private.
|
||||
${_GREEN}Default:${_CLEAR} https://github.com/\${SRC_ORG}/\${SRC_REPO}.git
|
||||
|
||||
NETBOX_PATH The path where netbox will be checkout out.
|
||||
Must not be outside of the netbox-docker repository (because of Docker)!
|
||||
${_GREEN}Default:${_CLEAR} .netbox
|
||||
|
||||
SKIP_GIT If defined, git is not invoked and \${NETBOX_PATH} will not be altered.
|
||||
This may be useful, if you are manually managing the NETBOX_PATH.
|
||||
${_GREEN}Default:${_CLEAR} undefined
|
||||
|
||||
TAG The version part of the image tag.
|
||||
${_GREEN}Default:${_CLEAR}
|
||||
When <branch>=main: snapshot
|
||||
Else: same as <branch>
|
||||
|
||||
IMAGE_NAMES The names used for the image including the registry
|
||||
Used for tagging the image.
|
||||
${_GREEN}Default:${_CLEAR} docker.io/netboxcommunity/netbox
|
||||
${_CYAN}Example:${_CLEAR} 'docker.io/netboxcommunity/netbox quay.io/netboxcommunity/netbox'
|
||||
|
||||
DOCKER_TAG The name of the tag which is applied to the image.
|
||||
Useful for pushing into another registry than hub.docker.com.
|
||||
${_GREEN}Default:${_CLEAR} \${DOCKER_REGISTRY}/\${DOCKER_ORG}/\${DOCKER_REPO}:\${TAG}
|
||||
|
||||
DOCKER_SHORT_TAG The name of the short tag which is applied to the
|
||||
image. This is used to tag all patch releases to their
|
||||
containing version e.g. v2.5.1 -> v2.5
|
||||
${_GREEN}Default:${_CLEAR} \${DOCKER_REGISTRY}/\${DOCKER_ORG}/\${DOCKER_REPO}:<MAJOR>.<MINOR>
|
||||
|
||||
DOCKERFILE The name of Dockerfile to use.
|
||||
${_GREEN}Default:${_CLEAR} Dockerfile
|
||||
|
||||
DOCKER_FROM The base image to use.
|
||||
${_GREEN}Default:${_CLEAR} 'ubuntu:24.04'
|
||||
|
||||
BUILDX_PLATFORMS
|
||||
Specifies the platform(s) to build the image for.
|
||||
${_CYAN}Example:${_CLEAR} 'linux/amd64,linux/arm64'
|
||||
${_GREEN}Default:${_CLEAR} 'linux/amd64'
|
||||
|
||||
BUILDX_BUILDER_NAME
|
||||
If defined, the image build will be assigned to the given builder.
|
||||
If you specify this variable, make sure that the builder exists.
|
||||
If this value is not defined, a new builx builder with the directory name of the
|
||||
current directory (i.e. '$(basename "${PWD}")') is created."
|
||||
${_CYAN}Example:${_CLEAR} 'clever_lovelace'
|
||||
${_GREEN}Default:${_CLEAR} undefined
|
||||
|
||||
BUILDX_REMOVE_BUILDER
|
||||
If defined (and only if BUILDX_BUILDER_NAME is undefined),
|
||||
then the buildx builder created by this script will be removed after use.
|
||||
This is useful if you build NetBox Docker on an automated system that does
|
||||
not manage the builders for you.
|
||||
${_CYAN}Example:${_CLEAR} 'on'
|
||||
${_GREEN}Default:${_CLEAR} undefined
|
||||
|
||||
HTTP_PROXY The proxy to use for http requests.
|
||||
${_CYAN}Example:${_CLEAR} http://proxy.domain.tld:3128
|
||||
${_GREEN}Default:${_CLEAR} undefined
|
||||
|
||||
NO_PROXY Comma-separated list of domain extensions proxy should not be used for.
|
||||
${_CYAN}Example:${_CLEAR} .domain1.tld,.domain2.tld
|
||||
${_GREEN}Default:${_CLEAR} undefined
|
||||
|
||||
DEBUG If defined, the script does not stop when certain checks are unsatisfied.
|
||||
${_GREEN}Default:${_CLEAR} undefined
|
||||
|
||||
DRY_RUN Prints all build statements instead of running them.
|
||||
${_GREEN}Default:${_CLEAR} undefined
|
||||
|
||||
GH_ACTION If defined, special 'echo' statements are enabled that set the
|
||||
following environment variables in Github Actions:
|
||||
- FINAL_DOCKER_TAG: The final value of the DOCKER_TAG env variable
|
||||
${_GREEN}Default:${_CLEAR} undefined
|
||||
|
||||
CHECK_ONLY Only checks if the build is needed and sets the GH Action output.
|
||||
${_GREEN}Default:${_CLEAR} undefined
|
||||
|
||||
${_BOLD}Examples:${_CLEAR}
|
||||
|
||||
${0} main
|
||||
This will fetch the latest 'main' branch, build a Docker Image and tag it
|
||||
'netboxcommunity/netbox:snapshot'.
|
||||
|
||||
${0} v4.2.0
|
||||
This will fetch the 'v4.2.0' tag, build a Docker Image and tag it
|
||||
'netboxcommunity/netbox:v4.2.0' and 'netboxcommunity/netbox:v4.2'.
|
||||
|
||||
${0} feature
|
||||
This will fetch the 'feature' branch, build a Docker Image and tag it
|
||||
'netboxcommunity/netbox:feature'.
|
||||
|
||||
SRC_ORG=cimnine ${0} feature-x
|
||||
This will fetch the 'feature-x' branch from https://github.com/cimnine/netbox.git,
|
||||
build a Docker Image and tag it 'netboxcommunity/netbox:feature-x'.
|
||||
|
||||
SRC_ORG=cimnine DOCKER_ORG=cimnine ${0} feature-x
|
||||
This will fetch the 'feature-x' branch from https://github.com/cimnine/netbox.git,
|
||||
build a Docker Image and tag it 'cimnine/netbox:feature-x'.
|
||||
END_OF_HELP
|
||||
|
||||
if [ "${1}x" == "x" ]; then
|
||||
exit 1
|
||||
@ -95,6 +135,15 @@ if [ "${1}x" == "x" ] || [ "${1}" == "--help" ] || [ "${1}" == "-h" ]; then
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check if we have everything needed for the build
|
||||
source ./build-functions/check-commands.sh
|
||||
# Load all build functions
|
||||
source ./build-functions/get-public-image-config.sh
|
||||
source ./build-functions/gh-functions.sh
|
||||
|
||||
IMAGE_NAMES="${IMAGE_NAMES-docker.io/netboxcommunity/netbox}"
|
||||
IFS=' ' read -ra IMAGE_NAMES <<<"${IMAGE_NAMES}"
|
||||
|
||||
###
|
||||
# Enabling dry-run mode
|
||||
###
|
||||
@ -105,6 +154,8 @@ else
|
||||
DRY="echo"
|
||||
fi
|
||||
|
||||
gh_echo "::group::⤵️ Fetching the NetBox source code"
|
||||
|
||||
###
|
||||
# Variables for fetching the NetBox source
|
||||
###
|
||||
@ -118,6 +169,12 @@ NETBOX_PATH="${NETBOX_PATH-.netbox}"
|
||||
# Fetching the NetBox source
|
||||
###
|
||||
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_out "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}"
|
||||
@ -138,6 +195,9 @@ if [ "${2}" != "--push-only" ] && [ -z "${SKIP_GIT}" ]; then
|
||||
echo "✅ Checked out NetBox"
|
||||
fi
|
||||
|
||||
gh_echo "::endgroup::"
|
||||
gh_echo "::group::🧮 Calculating Values"
|
||||
|
||||
###
|
||||
# Determining the value for DOCKERFILE
|
||||
# and checking whether it exists
|
||||
@ -157,7 +217,7 @@ fi
|
||||
# Determining the value for DOCKER_FROM
|
||||
###
|
||||
if [ -z "$DOCKER_FROM" ]; then
|
||||
DOCKER_FROM="alpine:3.14"
|
||||
DOCKER_FROM="docker.io/ubuntu:24.04"
|
||||
fi
|
||||
|
||||
###
|
||||
@ -165,7 +225,7 @@ fi
|
||||
###
|
||||
BUILD_DATE="$(date -u '+%Y-%m-%dT%H:%M+00:00')"
|
||||
|
||||
if [ -d ".git" ]; then
|
||||
if [ -d ".git" ] && [ -z "${SKIP_GIT}" ]; then
|
||||
GIT_REF="$(git rev-parse HEAD)"
|
||||
fi
|
||||
|
||||
@ -173,7 +233,7 @@ fi
|
||||
PROJECT_VERSION="${PROJECT_VERSION-$(sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//' VERSION)}"
|
||||
|
||||
# Get the Git information from the netbox directory
|
||||
if [ -d "${NETBOX_PATH}/.git" ]; then
|
||||
if [ -d "${NETBOX_PATH}/.git" ] && [ -z "${SKIP_GIT}" ]; then
|
||||
NETBOX_GIT_REF=$(
|
||||
cd "${NETBOX_PATH}"
|
||||
git rev-parse HEAD
|
||||
@ -195,10 +255,7 @@ 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)
|
||||
main)
|
||||
TAG="${TAG-snapshot}"
|
||||
;;
|
||||
*)
|
||||
@ -207,179 +264,195 @@ develop)
|
||||
esac
|
||||
|
||||
###
|
||||
# Determine targets to build
|
||||
# composing the final TARGET_DOCKER_TAG
|
||||
###
|
||||
DEFAULT_DOCKER_TARGETS=("main" "ldap")
|
||||
DOCKER_TARGETS=("${DOCKER_TARGET:-"${DEFAULT_DOCKER_TARGETS[@]}"}")
|
||||
echo "🏭 Building the following targets:" "${DOCKER_TARGETS[@]}"
|
||||
TARGET_DOCKER_TAG="${DOCKER_TAG-${TAG}}"
|
||||
TARGET_DOCKER_TAG_PROJECT="${TARGET_DOCKER_TAG}-${PROJECT_VERSION}"
|
||||
|
||||
###
|
||||
# Build each target
|
||||
# composing the additional DOCKER_SHORT_TAG,
|
||||
# i.e. "v4.2.0" becomes "v4.2",
|
||||
# which is only relevant for version tags
|
||||
# Also let "latest" follow the highest version
|
||||
###
|
||||
export DOCKER_BUILDKIT=${DOCKER_BUILDKIT-1}
|
||||
for DOCKER_TARGET in "${DOCKER_TARGETS[@]}"; do
|
||||
echo "🏗 Building the target '${DOCKER_TARGET}'"
|
||||
if [[ "${TAG}" =~ ^v([0-9]+)\.([0-9]+)\.[0-9]+$ ]]; then
|
||||
MAJOR=${BASH_REMATCH[1]}
|
||||
MINOR=${BASH_REMATCH[2]}
|
||||
|
||||
###
|
||||
# composing the final TARGET_DOCKER_TAG
|
||||
###
|
||||
TARGET_DOCKER_TAG="${DOCKER_TAG-${DOCKER_REGISTRY}/${DOCKER_ORG}/${DOCKER_REPO}:${TAG}}"
|
||||
if [ "${DOCKER_TARGET}" != "main" ]; then
|
||||
TARGET_DOCKER_TAG="${TARGET_DOCKER_TAG}-${DOCKER_TARGET}"
|
||||
fi
|
||||
if [ -n "${GH_ACTION}" ]; then
|
||||
echo "FINAL_DOCKER_TAG=${TARGET_DOCKER_TAG}" >>"$GITHUB_ENV"
|
||||
echo "::set-output name=skipped::false"
|
||||
fi
|
||||
TARGET_DOCKER_SHORT_TAG="${DOCKER_SHORT_TAG-v${MAJOR}.${MINOR}}"
|
||||
TARGET_DOCKER_LATEST_TAG="latest"
|
||||
TARGET_DOCKER_SHORT_TAG_PROJECT="${TARGET_DOCKER_SHORT_TAG}-${PROJECT_VERSION}"
|
||||
TARGET_DOCKER_LATEST_TAG_PROJECT="${TARGET_DOCKER_LATEST_TAG}-${PROJECT_VERSION}"
|
||||
fi
|
||||
|
||||
###
|
||||
# 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
|
||||
fi
|
||||
|
||||
###
|
||||
# Proceeding to buils stage, except if `--push-only` is passed
|
||||
###
|
||||
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`
|
||||
###
|
||||
DOCKER_BUILD_ARGS=(
|
||||
--pull
|
||||
--target "${DOCKER_TARGET}"
|
||||
-f "${DOCKERFILE}"
|
||||
-t "${TARGET_DOCKER_TAG}"
|
||||
)
|
||||
if [ -n "${TARGET_DOCKER_SHORT_TAG}" ]; then
|
||||
DOCKER_BUILD_ARGS+=(-t "${TARGET_DOCKER_SHORT_TAG}")
|
||||
DOCKER_BUILD_ARGS+=(-t "${TARGET_DOCKER_LATEST_TAG}")
|
||||
fi
|
||||
|
||||
# --label
|
||||
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}"
|
||||
)
|
||||
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
|
||||
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}")
|
||||
|
||||
if [ -n "${DOCKER_FROM}" ]; then
|
||||
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}")
|
||||
fi
|
||||
if [ -n "${NO_PROXY}" ]; then
|
||||
DOCKER_BUILD_ARGS+=(--build-arg "no_proxy=${NO_PROXY}")
|
||||
fi
|
||||
|
||||
###
|
||||
# Building the docker image
|
||||
###
|
||||
if [ "${SHOULD_BUILD}" == "true" ]; then
|
||||
echo "🐳 Building the Docker image '${TARGET_DOCKER_TAG}'."
|
||||
echo " Build reason set to: ${BUILD_REASON}"
|
||||
$DRY docker build "${DOCKER_BUILD_ARGS[@]}" .
|
||||
echo "✅ Finished building the Docker images '${TARGET_DOCKER_TAG}'"
|
||||
echo "🔎 Inspecting labels on '${TARGET_DOCKER_TAG}'"
|
||||
$DRY docker inspect "${TARGET_DOCKER_TAG}" --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
|
||||
source ./build-functions/docker-functions.sh
|
||||
push_image_to_registry "${TARGET_DOCKER_TAG}"
|
||||
|
||||
if [ -n "${TARGET_DOCKER_SHORT_TAG}" ]; then
|
||||
push_image_to_registry "${TARGET_DOCKER_SHORT_TAG}"
|
||||
push_image_to_registry "${TARGET_DOCKER_LATEST_TAG}"
|
||||
fi
|
||||
fi
|
||||
IMAGE_NAME_TAGS=()
|
||||
for IMAGE_NAME in "${IMAGE_NAMES[@]}"; do
|
||||
IMAGE_NAME_TAGS+=("${IMAGE_NAME}:${TARGET_DOCKER_TAG}")
|
||||
IMAGE_NAME_TAGS+=("${IMAGE_NAME}:${TARGET_DOCKER_TAG_PROJECT}")
|
||||
done
|
||||
if [ -n "${TARGET_DOCKER_SHORT_TAG}" ]; then
|
||||
for IMAGE_NAME in "${IMAGE_NAMES[@]}"; do
|
||||
IMAGE_NAME_TAGS+=("${IMAGE_NAME}:${TARGET_DOCKER_SHORT_TAG}")
|
||||
IMAGE_NAME_TAGS+=("${IMAGE_NAME}:${TARGET_DOCKER_SHORT_TAG_PROJECT}")
|
||||
IMAGE_NAME_TAGS+=("${IMAGE_NAME}:${TARGET_DOCKER_LATEST_TAG}")
|
||||
IMAGE_NAME_TAGS+=("${IMAGE_NAME}:${TARGET_DOCKER_LATEST_TAG_PROJECT}")
|
||||
done
|
||||
fi
|
||||
|
||||
FINAL_DOCKER_TAG="${IMAGE_NAME_TAGS[0]}"
|
||||
gh_env "FINAL_DOCKER_TAG=${IMAGE_NAME_TAGS[0]}"
|
||||
|
||||
###
|
||||
# Checking if the build is necessary,
|
||||
# meaning build only if one of those values changed:
|
||||
# - a new tag is beeing created
|
||||
# - base image digest
|
||||
# - netbox git ref (Label: netbox.git-ref)
|
||||
# - netbox-docker git ref (Label: org.opencontainers.image.revision)
|
||||
###
|
||||
# Load information from registry (only for first registry in "IMAGE_NAMES")
|
||||
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 [ "false" == "$(check_if_tags_exists "${IMAGE_NAMES[0]}" "$TARGET_DOCKER_TAG")" ]; then
|
||||
SHOULD_BUILD="true"
|
||||
BUILD_REASON="${BUILD_REASON} newtag"
|
||||
else
|
||||
echo "Checking labels for '${FINAL_DOCKER_TAG}'"
|
||||
BASE_LAST_LAYER=$(get_image_last_layer "${DOCKER_FROM}")
|
||||
OLD_BASE_LAST_LAYER=$(get_image_label netbox.last-base-image-layer "${FINAL_DOCKER_TAG}")
|
||||
NETBOX_GIT_REF_OLD=$(get_image_label netbox.git-ref "${FINAL_DOCKER_TAG}")
|
||||
GIT_REF_OLD=$(get_image_label org.opencontainers.image.revision "${FINAL_DOCKER_TAG}")
|
||||
|
||||
if [ "${BASE_LAST_LAYER}" != "${OLD_BASE_LAST_LAYER}" ]; then
|
||||
SHOULD_BUILD="true"
|
||||
BUILD_REASON="${BUILD_REASON} ubuntu"
|
||||
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
|
||||
fi
|
||||
|
||||
if [ "${SHOULD_BUILD}" != "true" ]; then
|
||||
echo "Build skipped because sources didn't change"
|
||||
gh_out "skipped=true"
|
||||
exit 0 # Nothing to do -> exit
|
||||
else
|
||||
gh_out "skipped=false"
|
||||
fi
|
||||
gh_echo "::endgroup::"
|
||||
|
||||
if [ "${CHECK_ONLY}" = "true" ]; then
|
||||
echo "Only check if build needed was requested. Exiting"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
###
|
||||
# Build the image
|
||||
###
|
||||
gh_echo "::group::🏗 Building the image"
|
||||
###
|
||||
# Composing all arguments for `docker build`
|
||||
###
|
||||
DOCKER_BUILD_ARGS=(
|
||||
--pull
|
||||
--target main
|
||||
-f "${DOCKERFILE}"
|
||||
)
|
||||
for IMAGE_NAME in "${IMAGE_NAME_TAGS[@]}"; do
|
||||
DOCKER_BUILD_ARGS+=(-t "${IMAGE_NAME}")
|
||||
done
|
||||
|
||||
# --label
|
||||
DOCKER_BUILD_ARGS+=(
|
||||
--label "netbox.original-tag=${TARGET_DOCKER_TAG_PROJECT}"
|
||||
--label "org.opencontainers.image.created=${BUILD_DATE}"
|
||||
--label "org.opencontainers.image.version=${PROJECT_VERSION}"
|
||||
)
|
||||
if [ -d ".git" ] && [ -z "${SKIP_GIT}" ]; then
|
||||
DOCKER_BUILD_ARGS+=(
|
||||
--label "org.opencontainers.image.revision=${GIT_REF}"
|
||||
)
|
||||
fi
|
||||
if [ -d "${NETBOX_PATH}/.git" ] && [ -z "${SKIP_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 "netbox.build-reason=${BUILD_REASON}")
|
||||
DOCKER_BUILD_ARGS+=(--label "netbox.last-base-image-layer=${BASE_LAST_LAYER}")
|
||||
fi
|
||||
|
||||
# --build-arg
|
||||
DOCKER_BUILD_ARGS+=(--build-arg "NETBOX_PATH=${NETBOX_PATH}")
|
||||
|
||||
if [ -n "${DOCKER_FROM}" ]; then
|
||||
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}")
|
||||
fi
|
||||
if [ -n "${NO_PROXY}" ]; then
|
||||
DOCKER_BUILD_ARGS+=(--build-arg "no_proxy=${NO_PROXY}")
|
||||
fi
|
||||
|
||||
DOCKER_BUILD_ARGS+=(--platform "${BUILDX_PLATFORM-linux/amd64}")
|
||||
if [ "${2}" == "--push" ]; then
|
||||
# output type=docker does not work with pushing
|
||||
DOCKER_BUILD_ARGS+=(
|
||||
--output=type=image
|
||||
--push
|
||||
)
|
||||
else
|
||||
DOCKER_BUILD_ARGS+=(
|
||||
--output=type=docker
|
||||
)
|
||||
fi
|
||||
|
||||
###
|
||||
# Building the docker image
|
||||
###
|
||||
if [ -z "${BUILDX_BUILDER_NAME}" ]; then
|
||||
BUILDX_BUILDER_NAME="$(basename "${PWD}")"
|
||||
fi
|
||||
if ! docker buildx ls | grep --quiet --word-regexp "${BUILDX_BUILDER_NAME}"; then
|
||||
echo "👷 Creating new Buildx Builder '${BUILDX_BUILDER_NAME}'"
|
||||
$DRY docker buildx create --name "${BUILDX_BUILDER_NAME}"
|
||||
BUILDX_BUILDER_CREATED="yes"
|
||||
fi
|
||||
|
||||
echo "🐳 Building the Docker image '${TARGET_DOCKER_TAG_PROJECT}'."
|
||||
echo " Build reason set to: ${BUILD_REASON}"
|
||||
$DRY docker buildx \
|
||||
--builder "${BUILDX_BUILDER_NAME}" \
|
||||
build \
|
||||
"${DOCKER_BUILD_ARGS[@]}" \
|
||||
.
|
||||
echo "✅ Finished building the Docker images"
|
||||
gh_echo "::endgroup::" # End group for Build
|
||||
|
||||
gh_echo "::group::🏗 Image Labels"
|
||||
echo "🔎 Inspecting labels on '${IMAGE_NAME_TAGS[0]}'"
|
||||
$DRY docker inspect "${IMAGE_NAME_TAGS[0]}" --format "{{json .Config.Labels}}" | jq
|
||||
gh_echo "::endgroup::"
|
||||
|
||||
gh_echo "::group::🏗 Clean up"
|
||||
if [ -n "${BUILDX_REMOVE_BUILDER}" ] && [ "${BUILDX_BUILDER_CREATED}" == "yes" ]; then
|
||||
echo "👷 Removing Buildx Builder '${BUILDX_BUILDER_NAME}'"
|
||||
$DRY docker buildx rm "${BUILDX_BUILDER_NAME}"
|
||||
fi
|
||||
gh_echo "::endgroup::"
|
||||
|
@ -7,12 +7,17 @@
|
||||
import re
|
||||
from os import environ
|
||||
from os.path import abspath, dirname, join
|
||||
from typing import Any, Callable, Tuple
|
||||
|
||||
# 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
|
||||
# For reference see https://docs.netbox.dev/en/stable/configuration/
|
||||
# Based on https://github.com/netbox-community/netbox/blob/develop/netbox/netbox/configuration_example.py
|
||||
|
||||
###
|
||||
# NetBox-Docker Helper functions
|
||||
###
|
||||
|
||||
# Read secret from file
|
||||
def _read_secret(secret_name, default = None):
|
||||
def _read_secret(secret_name: str, default: str | None = None) -> str | None:
|
||||
try:
|
||||
f = open('/run/secrets/' + secret_name, 'r', encoding='utf-8')
|
||||
except EnvironmentError:
|
||||
@ -21,6 +26,25 @@ def _read_secret(secret_name, default = None):
|
||||
with f:
|
||||
return f.readline().strip()
|
||||
|
||||
# If the `map_fn` isn't defined, then the value that is read from the environment (or the default value if not found) is returned.
|
||||
# If the `map_fn` is defined, then `map_fn` is invoked and the value (that was read from the environment or the default value if not found)
|
||||
# is passed to it as a parameter. The value returned from `map_fn` is then the return value of this function.
|
||||
# The `map_fn` is not invoked, if the value (that was read from the environment or the default value if not found) is None.
|
||||
def _environ_get_and_map(variable_name: str, default: str | None = None, map_fn: Callable[[str], Any | None] = None) -> Any | None:
|
||||
env_value = environ.get(variable_name, default)
|
||||
|
||||
if env_value == None:
|
||||
return env_value
|
||||
|
||||
if not map_fn:
|
||||
return env_value
|
||||
|
||||
return map_fn(env_value)
|
||||
|
||||
_AS_BOOL = lambda value : value.lower() == 'true'
|
||||
_AS_INT = lambda value : int(value)
|
||||
_AS_LIST = lambda value : list(filter(None, value.split(' ')))
|
||||
|
||||
_BASE_DIR = dirname(dirname(abspath(__file__)))
|
||||
|
||||
#########################
|
||||
@ -34,6 +58,9 @@ _BASE_DIR = dirname(dirname(abspath(__file__)))
|
||||
#
|
||||
# Example: ALLOWED_HOSTS = ['netbox.example.com', 'netbox.internal.local']
|
||||
ALLOWED_HOSTS = environ.get('ALLOWED_HOSTS', '*').split(' ')
|
||||
# ensure that '*' or 'localhost' is always in ALLOWED_HOSTS (needed for health checks)
|
||||
if '*' not in ALLOWED_HOSTS and 'localhost' not in ALLOWED_HOSTS:
|
||||
ALLOWED_HOSTS.append('localhost')
|
||||
|
||||
# PostgreSQL database configuration. See the Django documentation for a complete list of available parameters:
|
||||
# https://docs.djangoproject.com/en/stable/ref/settings/#databases
|
||||
@ -46,9 +73,9 @@ DATABASE = {
|
||||
'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')),
|
||||
'CONN_MAX_AGE': _environ_get_and_map('DB_CONN_MAX_AGE', '300', _AS_INT),
|
||||
# Max database connection age
|
||||
'DISABLE_SERVER_SIDE_CURSORS': environ.get('DB_DISABLE_SERVER_SIDE_CURSORS', 'False').lower() == 'true',
|
||||
'DISABLE_SERVER_SIDE_CURSORS': _environ_get_and_map('DB_DISABLE_SERVER_SIDE_CURSORS', 'False', _AS_BOOL),
|
||||
# Disable the use of server-side cursors transaction pooling
|
||||
}
|
||||
|
||||
@ -58,17 +85,26 @@ DATABASE = {
|
||||
REDIS = {
|
||||
'tasks': {
|
||||
'HOST': environ.get('REDIS_HOST', 'localhost'),
|
||||
'PORT': int(environ.get('REDIS_PORT', 6379)),
|
||||
'PORT': _environ_get_and_map('REDIS_PORT', 6379, _AS_INT),
|
||||
'SENTINELS': [tuple(uri.split(':')) for uri in _environ_get_and_map('REDIS_SENTINELS', '', _AS_LIST) if uri != ''],
|
||||
'SENTINEL_SERVICE': environ.get('REDIS_SENTINEL_SERVICE', 'default'),
|
||||
'SENTINEL_TIMEOUT': _environ_get_and_map('REDIS_SENTINEL_TIMEOUT', 10, _AS_INT),
|
||||
'USERNAME': environ.get('REDIS_USERNAME', ''),
|
||||
'PASSWORD': _read_secret('redis_password', environ.get('REDIS_PASSWORD', '')),
|
||||
'DATABASE': int(environ.get('REDIS_DATABASE', 0)),
|
||||
'SSL': environ.get('REDIS_SSL', 'False').lower() == 'true',
|
||||
'DATABASE': _environ_get_and_map('REDIS_DATABASE', 0, _AS_INT),
|
||||
'SSL': _environ_get_and_map('REDIS_SSL', 'False', _AS_BOOL),
|
||||
'INSECURE_SKIP_TLS_VERIFY': _environ_get_and_map('REDIS_INSECURE_SKIP_TLS_VERIFY', 'False', _AS_BOOL),
|
||||
},
|
||||
'caching': {
|
||||
'HOST': environ.get('REDIS_CACHE_HOST', environ.get('REDIS_HOST', 'localhost')),
|
||||
'PORT': int(environ.get('REDIS_CACHE_PORT', environ.get('REDIS_PORT', 6379))),
|
||||
'PORT': _environ_get_and_map('REDIS_CACHE_PORT', environ.get('REDIS_PORT', '6379'), _AS_INT),
|
||||
'SENTINELS': [tuple(uri.split(':')) for uri in _environ_get_and_map('REDIS_CACHE_SENTINELS', '', _AS_LIST) if uri != ''],
|
||||
'SENTINEL_SERVICE': environ.get('REDIS_CACHE_SENTINEL_SERVICE', environ.get('REDIS_SENTINEL_SERVICE', 'default')),
|
||||
'USERNAME': environ.get('REDIS_CACHE_USERNAME', environ.get('REDIS_USERNAME', '')),
|
||||
'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',
|
||||
'DATABASE': _environ_get_and_map('REDIS_CACHE_DATABASE', '1', _AS_INT),
|
||||
'SSL': _environ_get_and_map('REDIS_CACHE_SSL', environ.get('REDIS_SSL', 'False'), _AS_BOOL),
|
||||
'INSECURE_SKIP_TLS_VERIFY': _environ_get_and_map('REDIS_CACHE_INSECURE_SKIP_TLS_VERIFY', environ.get('REDIS_INSECURE_SKIP_TLS_VERIFY', 'False'), _AS_BOOL),
|
||||
},
|
||||
}
|
||||
|
||||
@ -85,159 +121,232 @@ SECRET_KEY = _read_secret('secret_key', environ.get('SECRET_KEY', ''))
|
||||
# #
|
||||
#########################
|
||||
|
||||
# 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'],
|
||||
]
|
||||
# # 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',
|
||||
)
|
||||
if 'ALLOWED_URL_SCHEMES' in environ:
|
||||
ALLOWED_URL_SCHEMES = _environ_get_and_map('ALLOWED_URL_SCHEMES', None, _AS_LIST)
|
||||
|
||||
# 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 = environ.get('BANNER_TOP', '')
|
||||
BANNER_BOTTOM = environ.get('BANNER_BOTTOM', '')
|
||||
if 'BANNER_TOP' in environ:
|
||||
BANNER_TOP = environ.get('BANNER_TOP', None)
|
||||
if 'BANNER_BOTTOM' in environ:
|
||||
BANNER_BOTTOM = environ.get('BANNER_BOTTOM', None)
|
||||
|
||||
# Text to include on the login page above the login form. HTML is allowed.
|
||||
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 = environ.get('BASE_PATH', '')
|
||||
if 'BANNER_LOGIN' in environ:
|
||||
BANNER_LOGIN = environ.get('BANNER_LOGIN', None)
|
||||
|
||||
# Maximum number of days to retain logged changes. Set to 0 to retain changes indefinitely. (Default: 90)
|
||||
CHANGELOG_RETENTION = int(environ.get('CHANGELOG_RETENTION', 90))
|
||||
if 'CHANGELOG_RETENTION' in environ:
|
||||
CHANGELOG_RETENTION = _environ_get_and_map('CHANGELOG_RETENTION', None, _AS_INT)
|
||||
|
||||
# Maximum number of days to retain job results (scripts and reports). Set to 0 to retain job results in the database indefinitely. (Default: 90)
|
||||
if 'JOB_RETENTION' in environ:
|
||||
JOB_RETENTION = _environ_get_and_map('JOB_RETENTION', None, _AS_INT)
|
||||
# JOBRESULT_RETENTION was renamed to JOB_RETENTION in the v3.5.0 release of NetBox. For backwards compatibility, map JOBRESULT_RETENTION to JOB_RETENTION
|
||||
elif 'JOBRESULT_RETENTION' in environ:
|
||||
JOB_RETENTION = _environ_get_and_map('JOBRESULT_RETENTION', None, _AS_INT)
|
||||
|
||||
# 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 = 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(' ')))]
|
||||
CORS_ORIGIN_ALLOW_ALL = _environ_get_and_map('CORS_ORIGIN_ALLOW_ALL', 'False', _AS_BOOL)
|
||||
CORS_ORIGIN_WHITELIST = _environ_get_and_map('CORS_ORIGIN_WHITELIST', 'https://localhost', _AS_LIST)
|
||||
CORS_ORIGIN_REGEX_WHITELIST = [re.compile(r) for r in _environ_get_and_map('CORS_ORIGIN_REGEX_WHITELIST', '', _AS_LIST)]
|
||||
|
||||
# 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 = environ.get('DEBUG', 'False').lower() == 'true'
|
||||
# sensitive information about your installation. Only enable debugging while performing testing.
|
||||
# Never enable debugging on a production system.
|
||||
DEBUG = _environ_get_and_map('DEBUG', 'False', _AS_BOOL)
|
||||
|
||||
# This parameter serves as a safeguard to prevent some potentially dangerous behavior,
|
||||
# such as generating new database schema migrations.
|
||||
# Set this to True only if you are actively developing the NetBox code base.
|
||||
DEVELOPER = _environ_get_and_map('DEVELOPER', 'False', _AS_BOOL)
|
||||
|
||||
# Email settings
|
||||
EMAIL = {
|
||||
'SERVER': environ.get('EMAIL_SERVER', 'localhost'),
|
||||
'PORT': int(environ.get('EMAIL_PORT', 25)),
|
||||
'PORT': _environ_get_and_map('EMAIL_PORT', 25, _AS_INT),
|
||||
'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',
|
||||
'USE_SSL': _environ_get_and_map('EMAIL_USE_SSL', 'False', _AS_BOOL),
|
||||
'USE_TLS': _environ_get_and_map('EMAIL_USE_TLS', 'False', _AS_BOOL),
|
||||
'SSL_CERTFILE': environ.get('EMAIL_SSL_CERTFILE', ''),
|
||||
'SSL_KEYFILE': environ.get('EMAIL_SSL_KEYFILE', ''),
|
||||
'TIMEOUT': int(environ.get('EMAIL_TIMEOUT', 10)), # seconds
|
||||
'TIMEOUT': _environ_get_and_map('EMAIL_TIMEOUT', 10, _AS_INT), # 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 = environ.get('ENFORCE_GLOBAL_UNIQUE', 'False').lower() == 'true'
|
||||
if 'ENFORCE_GLOBAL_UNIQUE' in environ:
|
||||
ENFORCE_GLOBAL_UNIQUE = _environ_get_and_map('ENFORCE_GLOBAL_UNIQUE', None, _AS_BOOL)
|
||||
|
||||
# By default, netbox sends census reporting data using a single HTTP request each time a worker starts.
|
||||
# This data enables the project maintainers to estimate how many NetBox deployments exist and track the adoption of new versions over time.
|
||||
# The only data reported by this function are the NetBox version, Python version, and a pseudorandom unique identifier.
|
||||
# To opt out of census reporting, set CENSUS_REPORTING_ENABLED to False.
|
||||
if 'CENSUS_REPORTING_ENABLED' in environ:
|
||||
CENSUS_REPORTING_ENABLED = _environ_get_and_map('CENSUS_REPORTING_ENABLED', None, _AS_BOOL)
|
||||
|
||||
# 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, environ.get('EXEMPT_VIEW_PERMISSIONS', '').split(' ')))
|
||||
EXEMPT_VIEW_PERMISSIONS = _environ_get_and_map('EXEMPT_VIEW_PERMISSIONS', '', _AS_LIST)
|
||||
|
||||
# Enable custom logging. Please see the Django documentation for detailed guidance on configuring custom logs:
|
||||
# https://docs.djangoproject.com/en/stable/topics/logging/
|
||||
LOGGING = {}
|
||||
# HTTP proxies NetBox should use when sending outbound HTTP requests (e.g. for webhooks).
|
||||
HTTP_PROXIES = {
|
||||
'http': environ.get('HTTP_PROXY', None),
|
||||
'https': environ.get('HTTPS_PROXY', None),
|
||||
}
|
||||
|
||||
# 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 = environ.get('LOGIN_REQUIRED', 'False').lower() == 'true'
|
||||
# IP addresses recognized as internal to the system. The debugging toolbar will be available only to clients accessing
|
||||
# NetBox from an internal IP.
|
||||
INTERNAL_IPS = _environ_get_and_map('INTERNAL_IPS', '127.0.0.1 ::1', _AS_LIST)
|
||||
|
||||
# Enable GraphQL API.
|
||||
if 'GRAPHQL_ENABLED' in environ:
|
||||
GRAPHQL_ENABLED = _environ_get_and_map('GRAPHQL_ENABLED', None, _AS_BOOL)
|
||||
|
||||
# # Enable custom logging. Please see the Django documentation for detailed guidance on configuring custom logs:
|
||||
# # https://docs.djangoproject.com/en/stable/topics/logging/
|
||||
# LOGGING = {}
|
||||
|
||||
# Automatically reset the lifetime of a valid session upon each authenticated request. Enables users to remain
|
||||
# authenticated to NetBox indefinitely.
|
||||
LOGIN_PERSISTENCE = _environ_get_and_map('LOGIN_PERSISTENCE', 'False', _AS_BOOL)
|
||||
|
||||
# When enabled, only authenticated users are permitted to access any part of NetBox.
|
||||
# Disabling this will allow unauthenticated users to access most areas of NetBox (but not make any changes).
|
||||
LOGIN_REQUIRED = _environ_get_and_map('LOGIN_REQUIRED', 'True', _AS_BOOL)
|
||||
|
||||
# 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))
|
||||
LOGIN_TIMEOUT = _environ_get_and_map('LOGIN_TIMEOUT', 1209600, _AS_INT)
|
||||
|
||||
# Setting this to True will display a "maintenance mode" banner at the top of every page.
|
||||
MAINTENANCE_MODE = environ.get('MAINTENANCE_MODE', 'False').lower() == 'true'
|
||||
if 'MAINTENANCE_MODE' in environ:
|
||||
MAINTENANCE_MODE = _environ_get_and_map('MAINTENANCE_MODE', None, _AS_BOOL)
|
||||
|
||||
# Maps provider
|
||||
if 'MAPS_URL' in environ:
|
||||
MAPS_URL = environ.get('MAPS_URL', None)
|
||||
|
||||
# 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(environ.get('MAX_PAGE_SIZE', 1000))
|
||||
if 'MAX_PAGE_SIZE' in environ:
|
||||
MAX_PAGE_SIZE = _environ_get_and_map('MAX_PAGE_SIZE', None, _AS_INT)
|
||||
|
||||
# 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 = environ.get('MEDIA_ROOT', join(_BASE_DIR, 'media'))
|
||||
|
||||
# Expose Prometheus monitoring metrics at the HTTP endpoint '/metrics'
|
||||
METRICS_ENABLED = environ.get('METRICS_ENABLED', 'False').lower() == 'true'
|
||||
|
||||
# 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(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 = {}
|
||||
METRICS_ENABLED = _environ_get_and_map('METRICS_ENABLED', 'False', _AS_BOOL)
|
||||
|
||||
# Determine how many objects to display per page within a list. (Default: 50)
|
||||
PAGINATE_COUNT = int(environ.get('PAGINATE_COUNT', 50))
|
||||
if 'PAGINATE_COUNT' in environ:
|
||||
PAGINATE_COUNT = _environ_get_and_map('PAGINATE_COUNT', None, _AS_INT)
|
||||
|
||||
# Enable installed plugins. Add the name of each plugin to the list.
|
||||
PLUGINS = []
|
||||
# # 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 = {
|
||||
}
|
||||
# # 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 = environ.get('PREFER_IPV4', 'False').lower() == 'true'
|
||||
if 'PREFER_IPV4' in environ:
|
||||
PREFER_IPV4 = _environ_get_and_map('PREFER_IPV4', None, _AS_BOOL)
|
||||
|
||||
# The default value for the amperage field when creating new power feeds.
|
||||
if 'POWERFEED_DEFAULT_AMPERAGE' in environ:
|
||||
POWERFEED_DEFAULT_AMPERAGE = _environ_get_and_map('POWERFEED_DEFAULT_AMPERAGE', None, _AS_INT)
|
||||
|
||||
# The default value (percentage) for the max_utilization field when creating new power feeds.
|
||||
if 'POWERFEED_DEFAULT_MAX_UTILIZATION' in environ:
|
||||
POWERFEED_DEFAULT_MAX_UTILIZATION = _environ_get_and_map('POWERFEED_DEFAULT_MAX_UTILIZATION', None, _AS_INT)
|
||||
|
||||
# The default value for the voltage field when creating new power feeds.
|
||||
if 'POWERFEED_DEFAULT_VOLTAGE' in environ:
|
||||
POWERFEED_DEFAULT_VOLTAGE = _environ_get_and_map('POWERFEED_DEFAULT_VOLTAGE', None, _AS_INT)
|
||||
|
||||
# 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))
|
||||
if 'RACK_ELEVATION_DEFAULT_UNIT_HEIGHT' in environ:
|
||||
RACK_ELEVATION_DEFAULT_UNIT_HEIGHT = _environ_get_and_map('RACK_ELEVATION_DEFAULT_UNIT_HEIGHT', None, _AS_INT)
|
||||
if 'RACK_ELEVATION_DEFAULT_UNIT_WIDTH' in environ:
|
||||
RACK_ELEVATION_DEFAULT_UNIT_WIDTH = _environ_get_and_map('RACK_ELEVATION_DEFAULT_UNIT_WIDTH', None, _AS_INT)
|
||||
|
||||
# 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_AUTO_CREATE_GROUPS = _environ_get_and_map('REMOTE_AUTH_AUTO_CREATE_GROUPS', 'False', _AS_BOOL)
|
||||
REMOTE_AUTH_AUTO_CREATE_USER = _environ_get_and_map('REMOTE_AUTH_AUTO_CREATE_USER', 'False', _AS_BOOL)
|
||||
REMOTE_AUTH_BACKEND = _environ_get_and_map('REMOTE_AUTH_BACKEND', 'netbox.authentication.RemoteUserBackend', _AS_LIST)
|
||||
REMOTE_AUTH_DEFAULT_GROUPS = _environ_get_and_map('REMOTE_AUTH_DEFAULT_GROUPS', '', _AS_LIST)
|
||||
# REMOTE_AUTH_DEFAULT_PERMISSIONS = {} # dicts can't be configured via environment variables. See extra.py instead.
|
||||
REMOTE_AUTH_ENABLED = _environ_get_and_map('REMOTE_AUTH_ENABLED', 'False', _AS_BOOL)
|
||||
REMOTE_AUTH_GROUP_HEADER = _environ_get_and_map('REMOTE_AUTH_GROUP_HEADER', 'HTTP_REMOTE_USER_GROUP')
|
||||
REMOTE_AUTH_GROUP_SEPARATOR = _environ_get_and_map('REMOTE_AUTH_GROUP_SEPARATOR', '|')
|
||||
REMOTE_AUTH_GROUP_SYNC_ENABLED = _environ_get_and_map('REMOTE_AUTH_GROUP_SYNC_ENABLED', 'False', _AS_BOOL)
|
||||
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(' ')))
|
||||
REMOTE_AUTH_USER_EMAIL = environ.get('REMOTE_AUTH_USER_EMAIL', 'HTTP_REMOTE_USER_EMAIL')
|
||||
REMOTE_AUTH_USER_FIRST_NAME = environ.get('REMOTE_AUTH_USER_FIRST_NAME', 'HTTP_REMOTE_USER_FIRST_NAME')
|
||||
REMOTE_AUTH_USER_LAST_NAME = environ.get('REMOTE_AUTH_USER_LAST_NAME', 'HTTP_REMOTE_USER_LAST_NAME')
|
||||
REMOTE_AUTH_SUPERUSER_GROUPS = _environ_get_and_map('REMOTE_AUTH_SUPERUSER_GROUPS', '', _AS_LIST)
|
||||
REMOTE_AUTH_SUPERUSERS = _environ_get_and_map('REMOTE_AUTH_SUPERUSERS', '', _AS_LIST)
|
||||
REMOTE_AUTH_STAFF_GROUPS = _environ_get_and_map('REMOTE_AUTH_STAFF_GROUPS', '', _AS_LIST)
|
||||
REMOTE_AUTH_STAFF_USERS = _environ_get_and_map('REMOTE_AUTH_STAFF_USERS', '', _AS_LIST)
|
||||
|
||||
# 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 = environ.get('REPORTS_ROOT', '/etc/netbox/reports')
|
||||
# RELEASE_CHECK_URL = 'https://api.github.com/repos/netbox-community/netbox/releases'
|
||||
|
||||
# Maximum execution time for background tasks, in seconds.
|
||||
RQ_DEFAULT_TIMEOUT = int(environ.get('RQ_DEFAULT_TIMEOUT', 300))
|
||||
RQ_DEFAULT_TIMEOUT = _environ_get_and_map('RQ_DEFAULT_TIMEOUT', 300, _AS_INT)
|
||||
|
||||
# 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 = environ.get('SCRIPTS_ROOT', '/etc/netbox/scripts')
|
||||
# The name to use for the csrf token cookie.
|
||||
CSRF_COOKIE_NAME = environ.get('CSRF_COOKIE_NAME', 'csrftoken')
|
||||
|
||||
# Cross-Site-Request-Forgery-Attack settings. If Netbox is sitting behind a reverse proxy, you might need to set the CSRF_TRUSTED_ORIGINS flag.
|
||||
# Django 4.0 requires to specify the URL Scheme in this setting. An example environment variable could be specified like:
|
||||
# CSRF_TRUSTED_ORIGINS=https://demo.netbox.dev http://demo.netbox.dev
|
||||
CSRF_TRUSTED_ORIGINS = _environ_get_and_map('CSRF_TRUSTED_ORIGINS', '', _AS_LIST)
|
||||
|
||||
# The name to use for the session cookie.
|
||||
SESSION_COOKIE_NAME = environ.get('SESSION_COOKIE_NAME', 'sessionid')
|
||||
|
||||
# If true, the `includeSubDomains` directive will be included in the HTTP Strict Transport Security (HSTS) header.
|
||||
# This directive instructs the browser to apply the HSTS policy to all subdomains of the current domain.
|
||||
SECURE_HSTS_INCLUDE_SUBDOMAINS = _environ_get_and_map('SECURE_HSTS_INCLUDE_SUBDOMAINS', 'False', _AS_BOOL)
|
||||
|
||||
# If true, the `preload` directive will be included in the HTTP Strict Transport Security (HSTS) header.
|
||||
# This directive instructs the browser to preload the site in HTTPS. Browsers that use the HSTS preload list will force the
|
||||
# site to be accessed via HTTPS even if the user types HTTP in the address bar.
|
||||
SECURE_HSTS_PRELOAD = _environ_get_and_map('SECURE_HSTS_PRELOAD', 'False', _AS_BOOL)
|
||||
|
||||
# If set to a non-zero integer value, the SecurityMiddleware sets the HTTP Strict Transport Security (HSTS) header on all
|
||||
# responses that do not already have it. This will instruct the browser that the website must be accessed via HTTPS,
|
||||
# blocking any HTTP request.
|
||||
SECURE_HSTS_SECONDS = _environ_get_and_map('SECURE_HSTS_SECONDS', 0, _AS_INT)
|
||||
|
||||
# If true, all non-HTTPS requests will be automatically redirected to use HTTPS.
|
||||
SECURE_SSL_REDIRECT = _environ_get_and_map('SECURE_SSL_REDIRECT', 'False', _AS_BOOL)
|
||||
|
||||
# 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)
|
||||
SESSION_FILE_PATH = environ.get('SESSION_FILE_PATH', environ.get('SESSIONS_ROOT', None))
|
||||
|
||||
# Time zone (default: UTC)
|
||||
TIME_ZONE = environ.get('TIME_ZONE', 'UTC')
|
||||
|
||||
# Date/time formatting. See the following link for supported formats:
|
||||
# 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')
|
||||
# If true disables miscellaneous functionality which depends on access to the Internet.
|
||||
ISOLATED_DEPLOYMENT = _environ_get_and_map('ISOLATED_DEPLOYMENT', 'False', _AS_BOOL)
|
||||
|
@ -15,12 +15,6 @@
|
||||
# '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')
|
||||
|
@ -31,9 +31,12 @@ 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', ''))
|
||||
AUTH_LDAP_BIND_AS_AUTHENTICATING_USER = environ.get('AUTH_LDAP_BIND_AS_AUTHENTICATING_USER', 'False').lower() == 'true'
|
||||
|
||||
# Set the DN and password for the NetBox service account if needed.
|
||||
if not AUTH_LDAP_BIND_AS_AUTHENTICATING_USER:
|
||||
AUTH_LDAP_BIND_DN = environ.get('AUTH_LDAP_BIND_DN', '')
|
||||
AUTH_LDAP_BIND_PASSWORD = _read_secret('auth_ldap_bind_password', environ.get('AUTH_LDAP_BIND_PASSWORD', ''))
|
||||
|
||||
# Set a string template that describes any user’s distinguished name based on the username.
|
||||
AUTH_LDAP_USER_DN_TEMPLATE = environ.get('AUTH_LDAP_USER_DN_TEMPLATE', None)
|
||||
@ -46,20 +49,38 @@ AUTH_LDAP_START_TLS = environ.get('AUTH_LDAP_START_TLS', 'False').lower() == 'tr
|
||||
# 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'
|
||||
|
||||
# Include this setting if you want to validate the LDAP server certificates against a CA certificate directory on your server
|
||||
# Note that this is a NetBox-specific setting which sets:
|
||||
# ldap.set_option(ldap.OPT_X_TLS_CACERTDIR, LDAP_CA_CERT_DIR)
|
||||
LDAP_CA_CERT_DIR = environ.get('LDAP_CA_CERT_DIR', None)
|
||||
|
||||
# Include this setting if you want to validate the LDAP server certificates against your own CA.
|
||||
# Note that this is a NetBox-specific setting which sets:
|
||||
# ldap.set_option(ldap.OPT_X_TLS_CACERTFILE, LDAP_CA_CERT_FILE)
|
||||
LDAP_CA_CERT_FILE = environ.get('LDAP_CA_CERT_FILE', None)
|
||||
|
||||
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_FILTER: str = environ.get(
|
||||
'AUTH_LDAP_USER_SEARCH_FILTER', f'({AUTH_LDAP_USER_SEARCH_ATTR}=%(user)s)'
|
||||
)
|
||||
|
||||
AUTH_LDAP_USER_SEARCH = LDAPSearch(
|
||||
AUTH_LDAP_USER_SEARCH_BASEDN,
|
||||
ldap.SCOPE_SUBTREE,
|
||||
"(" + AUTH_LDAP_USER_SEARCH_ATTR + "=%(user)s)"
|
||||
AUTH_LDAP_USER_SEARCH_BASEDN, ldap.SCOPE_SUBTREE, AUTH_LDAP_USER_SEARCH_FILTER
|
||||
)
|
||||
|
||||
# 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_SEARCH_FILTER: str = environ.get(
|
||||
'AUTH_LDAP_GROUP_SEARCH_FILTER', f'(objectclass={AUTH_LDAP_GROUP_SEARCH_CLASS})'
|
||||
)
|
||||
AUTH_LDAP_GROUP_SEARCH = LDAPSearch(
|
||||
AUTH_LDAP_GROUP_SEARCH_BASEDN, ldap.SCOPE_SUBTREE, AUTH_LDAP_GROUP_SEARCH_FILTER
|
||||
)
|
||||
AUTH_LDAP_GROUP_TYPE = _import_group_type(environ.get('AUTH_LDAP_GROUP_TYPE', 'GroupOfNamesType'))
|
||||
|
||||
# Define a group required to login.
|
||||
|
@ -1,5 +1,22 @@
|
||||
version: '3.4'
|
||||
services:
|
||||
netbox:
|
||||
ports:
|
||||
- 8000:8080
|
||||
- "8000:8080"
|
||||
# If you want the Nginx unit status page visible from the
|
||||
# outside of the container add the following port mapping:
|
||||
# - "8001:8081"
|
||||
# healthcheck:
|
||||
# Time for which the health check can fail after the container is started.
|
||||
# This depends mostly on the performance of your database. On the first start,
|
||||
# when all tables need to be created the start_period should be higher than on
|
||||
# subsequent starts. For the first start after major version upgrades of NetBox
|
||||
# the start_period might also need to be set higher.
|
||||
# Default value in our docker-compose.yml is 60s
|
||||
# start_period: 90s
|
||||
# environment:
|
||||
# SKIP_SUPERUSER: "false"
|
||||
# SUPERUSER_API_TOKEN: ""
|
||||
# SUPERUSER_EMAIL: ""
|
||||
# SUPERUSER_NAME: ""
|
||||
# SUPERUSER_PASSWORD: ""
|
||||
|
||||
|
5
docker-compose.test.override.yml
Normal file
5
docker-compose.test.override.yml
Normal file
@ -0,0 +1,5 @@
|
||||
services:
|
||||
netbox:
|
||||
ports:
|
||||
- "127.0.0.1:8000:8080"
|
||||
|
@ -1,41 +1,70 @@
|
||||
version: '3.4'
|
||||
services:
|
||||
netbox:
|
||||
image: ${IMAGE-netboxcommunity/netbox:latest}
|
||||
netbox: &netbox
|
||||
image: ${IMAGE-docker.io/netboxcommunity/netbox:latest}
|
||||
depends_on:
|
||||
- postgres
|
||||
- redis
|
||||
- redis-cache
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_healthy
|
||||
redis-cache:
|
||||
condition: service_healthy
|
||||
env_file: env/netbox.env
|
||||
environment:
|
||||
SKIP_STARTUP_SCRIPTS: ${SKIP_STARTUP_SCRIPTS-false}
|
||||
user: '101'
|
||||
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-media-files:/opt/netbox/netbox/media:z
|
||||
ports:
|
||||
- 8080
|
||||
- ./test-configuration/test_config.py:/etc/netbox/config/test_config.py:z,ro
|
||||
healthcheck:
|
||||
test: curl -f http://localhost:8080/login/ || exit 1
|
||||
start_period: ${NETBOX_START_PERIOD-120s}
|
||||
timeout: 3s
|
||||
interval: 15s
|
||||
netbox-worker:
|
||||
<<: *netbox
|
||||
command:
|
||||
- /opt/netbox/venv/bin/python
|
||||
- /opt/netbox/netbox/manage.py
|
||||
- rqworker
|
||||
healthcheck:
|
||||
test: ps -aux | grep -v grep | grep -q rqworker || exit 1
|
||||
start_period: 40s
|
||||
timeout: 3s
|
||||
interval: 15s
|
||||
netbox-housekeeping:
|
||||
<<: *netbox
|
||||
command:
|
||||
- /opt/netbox/housekeeping.sh
|
||||
healthcheck:
|
||||
test: ps -aux | grep -v grep | grep -q housekeeping || exit 1
|
||||
start_period: 40s
|
||||
timeout: 3s
|
||||
interval: 15s
|
||||
|
||||
postgres:
|
||||
image: postgres:13-alpine
|
||||
image: docker.io/postgres:17-alpine
|
||||
env_file: env/postgres.env
|
||||
redis:
|
||||
image: redis:6-alpine
|
||||
healthcheck:
|
||||
test: pg_isready -q -t 2 -d $$POSTGRES_DB -U $$POSTGRES_USER ## $$ because of docker-compose
|
||||
start_period: 20s
|
||||
interval: 1s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
redis: &redis
|
||||
image: docker.io/valkey/valkey:8.1-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
|
||||
- sh
|
||||
- -c # this is to evaluate the $REDIS_PASSWORD from the env
|
||||
- valkey-server --save "" --appendonly no --requirepass $$REDIS_PASSWORD ## $$ because of docker-compose
|
||||
env_file: env/redis.env
|
||||
healthcheck:
|
||||
test: '[ $$(valkey-cli --pass "$${REDIS_PASSWORD}" ping) = ''PONG'' ]'
|
||||
start_period: 5s
|
||||
timeout: 3s
|
||||
interval: 1s
|
||||
retries: 5
|
||||
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
|
||||
<<: *redis
|
||||
env_file: env/redis-cache.env
|
||||
|
||||
volumes:
|
||||
netbox-media-files:
|
||||
driver: local
|
||||
|
@ -1,61 +1,83 @@
|
||||
version: '3.4'
|
||||
services:
|
||||
netbox: &netbox
|
||||
image: netboxcommunity/netbox:${VERSION-v3.0}
|
||||
image: docker.io/netboxcommunity/netbox:${VERSION-v4.3-3.3.0}
|
||||
depends_on:
|
||||
- postgres
|
||||
- redis
|
||||
- redis-cache
|
||||
- netbox-worker
|
||||
- redis
|
||||
- redis-cache
|
||||
env_file: env/netbox.env
|
||||
user: '101'
|
||||
user: "unit:root"
|
||||
healthcheck:
|
||||
test: curl -f http://localhost:8080/login/ || exit 1
|
||||
start_period: 90s
|
||||
timeout: 3s
|
||||
interval: 15s
|
||||
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-media-files:/opt/netbox/netbox/media:z
|
||||
- ./configuration:/etc/netbox/config:z,ro
|
||||
- netbox-media-files:/opt/netbox/netbox/media:rw
|
||||
- netbox-reports-files:/opt/netbox/netbox/reports:rw
|
||||
- netbox-scripts-files:/opt/netbox/netbox/scripts:rw
|
||||
netbox-worker:
|
||||
<<: *netbox
|
||||
depends_on:
|
||||
- redis
|
||||
entrypoint:
|
||||
- /opt/netbox/venv/bin/python
|
||||
- /opt/netbox/netbox/manage.py
|
||||
netbox:
|
||||
condition: service_healthy
|
||||
command:
|
||||
- rqworker
|
||||
ports: []
|
||||
|
||||
# postgres
|
||||
postgres:
|
||||
image: postgres:13-alpine
|
||||
env_file: env/postgres.env
|
||||
volumes:
|
||||
- netbox-postgres-data:/var/lib/postgresql/data
|
||||
- /opt/netbox/venv/bin/python
|
||||
- /opt/netbox/netbox/manage.py
|
||||
- rqworker
|
||||
healthcheck:
|
||||
test: ps -aux | grep -v grep | grep -q rqworker || exit 1
|
||||
start_period: 20s
|
||||
timeout: 3s
|
||||
interval: 15s
|
||||
netbox-housekeeping:
|
||||
<<: *netbox
|
||||
depends_on:
|
||||
netbox:
|
||||
condition: service_healthy
|
||||
command:
|
||||
- /opt/netbox/housekeeping.sh
|
||||
healthcheck:
|
||||
test: ps -aux | grep -v grep | grep -q housekeeping || exit 1
|
||||
start_period: 20s
|
||||
timeout: 3s
|
||||
interval: 15s
|
||||
|
||||
# redis
|
||||
redis:
|
||||
image: redis:6-alpine
|
||||
image: docker.io/valkey/valkey:8.1-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
|
||||
- sh
|
||||
- -c # this is to evaluate the $REDIS_PASSWORD from the env
|
||||
- valkey-server --appendonly yes --requirepass $$REDIS_PASSWORD ## $$ because of docker-compose
|
||||
healthcheck: &redis-healthcheck
|
||||
test: '[ $$(valkey-cli --pass "$${REDIS_PASSWORD}" ping) = ''PONG'' ]'
|
||||
start_period: 5s
|
||||
timeout: 3s
|
||||
interval: 1s
|
||||
retries: 5
|
||||
env_file: env/redis.env
|
||||
volumes:
|
||||
- netbox-redis-data:/data
|
||||
- netbox-redis-data:/data
|
||||
redis-cache:
|
||||
image: redis:6-alpine
|
||||
image: docker.io/valkey/valkey:8.1-alpine
|
||||
command:
|
||||
- sh
|
||||
- -c # this is to evaluate the $REDIS_PASSWORD from the env
|
||||
- redis-server --requirepass $$REDIS_PASSWORD ## $$ because of docker-compose
|
||||
- sh
|
||||
- -c # this is to evaluate the $REDIS_PASSWORD from the env
|
||||
- valkey-server --requirepass $$REDIS_PASSWORD ## $$ because of docker-compose
|
||||
healthcheck: *redis-healthcheck
|
||||
env_file: env/redis-cache.env
|
||||
volumes:
|
||||
- netbox-redis-cache-data:/data
|
||||
|
||||
volumes:
|
||||
netbox-media-files:
|
||||
driver: local
|
||||
netbox-postgres-data:
|
||||
netbox-redis-cache-data:
|
||||
driver: local
|
||||
netbox-redis-data:
|
||||
driver: local
|
||||
netbox-reports-files:
|
||||
driver: local
|
||||
netbox-scripts-files:
|
||||
driver: local
|
||||
|
@ -82,3 +82,10 @@ def __getattr__(name):
|
||||
except:
|
||||
pass
|
||||
raise AttributeError
|
||||
|
||||
|
||||
def __dir__():
|
||||
names = []
|
||||
for config in _loaded_configurations:
|
||||
names.extend(config.__dir__())
|
||||
return names
|
||||
|
@ -15,7 +15,19 @@ source /opt/netbox/venv/bin/activate
|
||||
DB_WAIT_TIMEOUT=${DB_WAIT_TIMEOUT-3}
|
||||
MAX_DB_WAIT_TIME=${MAX_DB_WAIT_TIME-30}
|
||||
CUR_DB_WAIT_TIME=0
|
||||
while ! ./manage.py showmigrations >/dev/null 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))
|
||||
@ -34,6 +46,8 @@ if ! ./manage.py migrate --check >/dev/null 2>&1; then
|
||||
./manage.py remove_stale_contenttypes --no-input
|
||||
echo "⚙️ Removing expired user sessions"
|
||||
./manage.py clearsessions
|
||||
echo "⚙️ Building search index (lazy)"
|
||||
./manage.py reindex --lazy
|
||||
fi
|
||||
|
||||
# Create Superuser if required
|
||||
@ -58,22 +72,24 @@ else
|
||||
fi
|
||||
|
||||
./manage.py shell --interface python <<END
|
||||
from django.contrib.auth.models import User
|
||||
from users.models import Token
|
||||
from users.models import Token, User
|
||||
if not User.objects.filter(username='${SUPERUSER_NAME}'):
|
||||
u=User.objects.create_superuser('${SUPERUSER_NAME}', '${SUPERUSER_EMAIL}', '${SUPERUSER_PASSWORD}')
|
||||
u = User.objects.create_superuser('${SUPERUSER_NAME}', '${SUPERUSER_EMAIL}', '${SUPERUSER_PASSWORD}')
|
||||
Token.objects.create(user=u, key='${SUPERUSER_API_TOKEN}')
|
||||
END
|
||||
|
||||
echo "💡 Superuser Username: ${SUPERUSER_NAME}, E-Mail: ${SUPERUSER_EMAIL}"
|
||||
fi
|
||||
|
||||
# Run the startup scripts (and initializers)
|
||||
if [ "$SKIP_STARTUP_SCRIPTS" == "true" ]; then
|
||||
echo "↩️ Skipping startup scripts"
|
||||
else
|
||||
echo "import runpy; runpy.run_path('../startup_scripts')" | ./manage.py shell --interface python
|
||||
fi
|
||||
./manage.py shell --interface python <<END
|
||||
from users.models import Token
|
||||
try:
|
||||
old_default_token = Token.objects.get(key="0123456789abcdef0123456789abcdef01234567")
|
||||
if old_default_token:
|
||||
print("⚠️ Warning: You have the old default admin API token in your database. This token is widely known; please remove it. Log in as your superuser and check API Tokens in your user menu.")
|
||||
except Token.DoesNotExist:
|
||||
pass
|
||||
END
|
||||
|
||||
echo "✅ Initialisation is done."
|
||||
|
||||
|
8
docker/housekeeping.sh
Executable file
8
docker/housekeeping.sh
Executable file
@ -0,0 +1,8 @@
|
||||
#!/bin/bash
|
||||
SLEEP_SECONDS=${HOUSEKEEPING_INTERVAL:=86400}
|
||||
echo "Interval set to ${SLEEP_SECONDS} seconds"
|
||||
while true; do
|
||||
date
|
||||
/opt/netbox/venv/bin/python /opt/netbox/netbox/manage.py housekeeping
|
||||
sleep "${SLEEP_SECONDS}s"
|
||||
done
|
@ -1,6 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
UNIT_CONFIG="${UNIT_CONFIG-/etc/unit/nginx-unit.json}"
|
||||
# Also used in "nginx-unit.json"
|
||||
UNIT_SOCKET="/opt/unit/unit.sock"
|
||||
|
||||
load_configuration() {
|
||||
@ -50,5 +51,7 @@ exec unitd \
|
||||
--control unix:$UNIT_SOCKET \
|
||||
--pid /opt/unit/unit.pid \
|
||||
--log /dev/stdout \
|
||||
--state /opt/unit/state/ \
|
||||
--tmp /opt/unit/tmp/
|
||||
--statedir /opt/unit/state/ \
|
||||
--tmpdir /opt/unit/tmp/ \
|
||||
--user unit \
|
||||
--group root
|
||||
|
@ -1,27 +1,65 @@
|
||||
{
|
||||
"listeners": {
|
||||
"*:8080": {
|
||||
"pass": "routes"
|
||||
}
|
||||
},
|
||||
|
||||
"routes": [
|
||||
{
|
||||
"match": {
|
||||
"uri": "/static/*"
|
||||
},
|
||||
"action": {
|
||||
"share": "/opt/netbox/netbox"
|
||||
"0.0.0.0:8080": {
|
||||
"pass": "routes/main",
|
||||
"forwarded": {
|
||||
"client_ip": "X-Forwarded-For",
|
||||
"protocol": "X-Forwarded-Proto",
|
||||
"source": ["10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"action": {
|
||||
"pass": "applications/netbox"
|
||||
"0.0.0.0:8081": {
|
||||
"pass": "routes/status",
|
||||
"forwarded": {
|
||||
"client_ip": "X-Forwarded-For",
|
||||
"protocol": "X-Forwarded-Proto",
|
||||
"source": ["10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"]
|
||||
}
|
||||
},
|
||||
"[::]:8080": {
|
||||
"pass": "routes/main",
|
||||
"forwarded": {
|
||||
"client_ip": "X-Forwarded-For",
|
||||
"protocol": "X-Forwarded-Proto",
|
||||
"source": ["fc00::/7", "fe80::/10"]
|
||||
}
|
||||
},
|
||||
"[::]:8081": {
|
||||
"pass": "routes/status",
|
||||
"forwarded": {
|
||||
"client_ip": "X-Forwarded-For",
|
||||
"protocol": "X-Forwarded-Proto",
|
||||
"source": ["fc00::/7", "fe80::/10"]
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
},
|
||||
"routes": {
|
||||
"main": [
|
||||
{
|
||||
"match": {
|
||||
"uri": "/static/*"
|
||||
},
|
||||
"action": {
|
||||
"share": "/opt/netbox/netbox${uri}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"pass": "applications/netbox"
|
||||
}
|
||||
}
|
||||
],
|
||||
"status": [
|
||||
{
|
||||
"match": {
|
||||
"uri": "/status/*"
|
||||
},
|
||||
"action": {
|
||||
"proxy": "http://unix:/opt/unit/unit.sock"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"applications": {
|
||||
"netbox": {
|
||||
"type": "python 3",
|
||||
@ -35,6 +73,5 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"access_log": "/dev/stdout"
|
||||
}
|
||||
|
1
docker/unit.list
Normal file
1
docker/unit.list
Normal file
@ -0,0 +1 @@
|
||||
deb [signed-by=/usr/share/keyrings/nginx-keyring.gpg] http://packages.nginx.org/unit/ubuntu/ noble unit
|
24
env/docker-compose.override.yml
vendored
Normal file
24
env/docker-compose.override.yml
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
version: '3.4'
|
||||
services:
|
||||
netbox:
|
||||
ports:
|
||||
- 8085:8080
|
||||
volumes:
|
||||
- /media/nfs/netbox/config:/etc/netbox/config:z,ro
|
||||
- /media/nfs/netbox/media:/opt/netbox/netbox/media:z,rw
|
||||
- /media/nfs/netbox/reports:/opt/netbox/netbox/reports:z,rw
|
||||
- /media/nfs/netbox/scripts:/opt/netbox/netbox/scripts:z,rw
|
||||
healthcheck:
|
||||
retries: 15
|
||||
netbox-worker:
|
||||
volumes:
|
||||
- /media/nfs/netbox/config:/etc/netbox/config:z,ro
|
||||
- /media/nfs/netbox/media:/opt/netbox/netbox/media:z,rw
|
||||
- /media/nfs/netbox/reports:/opt/netbox/netbox/reports:z,rw
|
||||
- /media/nfs/netbox/scripts:/opt/netbox/netbox/scripts:z,rw
|
||||
netbox-housekeeping:
|
||||
volumes:
|
||||
- /media/nfs/netbox/config:/etc/netbox/config:z,ro
|
||||
- /media/nfs/netbox/media:/opt/netbox/netbox/media:z,rw
|
||||
- /media/nfs/netbox/reports:/opt/netbox/netbox/reports:z,rw
|
||||
- /media/nfs/netbox/scripts:/opt/netbox/netbox/scripts:z,rw
|
19
env/netbox.env
vendored
19
env/netbox.env
vendored
@ -1,7 +1,7 @@
|
||||
CORS_ORIGIN_ALLOW_ALL=True
|
||||
DB_HOST=postgres
|
||||
DB_HOST=192.168.0.52
|
||||
DB_NAME=netbox
|
||||
DB_PASSWORD=J5brHrAXFLQSif0K
|
||||
DB_PASSWORD=netbox
|
||||
DB_USER=netbox
|
||||
EMAIL_FROM=netbox@bar.com
|
||||
EMAIL_PASSWORD=
|
||||
@ -14,26 +14,21 @@ 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
|
||||
MAX_PAGE_SIZE=1000
|
||||
GRAPHQL_ENABLED=true
|
||||
HOUSEKEEPING_INTERVAL=86400
|
||||
MEDIA_ROOT=/opt/netbox/netbox/media
|
||||
METRICS_ENABLED=false
|
||||
NAPALM_PASSWORD=
|
||||
NAPALM_TIMEOUT=10
|
||||
NAPALM_USERNAME=
|
||||
REDIS_CACHE_DATABASE=1
|
||||
REDIS_CACHE_HOST=redis-cache
|
||||
REDIS_CACHE_INSECURE_SKIP_TLS_VERIFY=false
|
||||
REDIS_CACHE_PASSWORD=t4Ph722qJ5QHeQ1qfu36
|
||||
REDIS_CACHE_SSL=false
|
||||
REDIS_DATABASE=0
|
||||
REDIS_HOST=redis
|
||||
REDIS_INSECURE_SKIP_TLS_VERIFY=false
|
||||
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
|
||||
SECRET_KEY='r(m)9nLGnz$(_q3N4z1k(EFsMCjjjzx08x9VhNVcfd%6RF#r!6DE@+V5Zk2X'
|
||||
SKIP_SUPERUSER=false
|
||||
SUPERUSER_API_TOKEN=0123456789abcdef0123456789abcdef01234567
|
||||
SUPERUSER_EMAIL=admin@example.com
|
||||
SUPERUSER_NAME=admin
|
||||
SUPERUSER_PASSWORD=admin
|
||||
WEBHOOKS_ENABLED=true
|
||||
|
@ -1,7 +0,0 @@
|
||||
# - prefix: 10.0.0.0/16
|
||||
# rir: RFC1918
|
||||
# tenant: tenant1
|
||||
# - prefix: fd00:ccdd::/32
|
||||
# rir: RFC4193 ULA
|
||||
# - prefix: 2001:db8::/32
|
||||
# rir: RFC3849
|
@ -1,6 +0,0 @@
|
||||
# - name: VPLS
|
||||
# slug: vpls
|
||||
# - name: MPLS
|
||||
# slug: mpls
|
||||
# - name: Internet
|
||||
# slug: internet
|
@ -1,7 +0,0 @@
|
||||
# - cid: Circuit_ID-1
|
||||
# provider: Provider1
|
||||
# type: Internet
|
||||
# tenant: tenant1
|
||||
# - cid: Circuit_ID-2
|
||||
# provider: Provider2
|
||||
# type: MPLS
|
@ -1,4 +0,0 @@
|
||||
# - name: Group 1
|
||||
# slug: group-1
|
||||
# - name: Group 2
|
||||
# slug: group-2
|
@ -1,2 +0,0 @@
|
||||
# - name: Hyper-V
|
||||
# slug: hyper-v
|
@ -1,7 +0,0 @@
|
||||
# - name: cluster1
|
||||
# type: Hyper-V
|
||||
# group: Group 1
|
||||
# tenant: tenant1
|
||||
# - name: cluster2
|
||||
# type: Hyper-V
|
||||
# site: SING 1
|
@ -1,93 +0,0 @@
|
||||
## Possible Choices:
|
||||
## type:
|
||||
## - text
|
||||
## - integer
|
||||
## - boolean
|
||||
## - date
|
||||
## - url
|
||||
## - select
|
||||
## filter_logic:
|
||||
## - disabled
|
||||
## - loose
|
||||
## - exact
|
||||
##
|
||||
## Examples:
|
||||
|
||||
# text_field:
|
||||
# type: text
|
||||
# label: Custom Text
|
||||
# description: Enter text in a text field.
|
||||
# required: false
|
||||
# weight: 0
|
||||
# on_objects:
|
||||
# - dcim.models.Device
|
||||
# - dcim.models.Rack
|
||||
# - dcim.models.Site
|
||||
# - dcim.models.DeviceType
|
||||
# - ipam.models.IPAddress
|
||||
# - ipam.models.Prefix
|
||||
# - tenancy.models.Tenant
|
||||
# - virtualization.models.VirtualMachine
|
||||
# integer_field:
|
||||
# type: integer
|
||||
# label: Custom Number
|
||||
# description: Enter numbers into an integer field.
|
||||
# required: true
|
||||
# filter_logic: loose
|
||||
# weight: 10
|
||||
# on_objects:
|
||||
# - tenancy.models.Tenant
|
||||
# select_field:
|
||||
# type: select
|
||||
# label: Choose between items
|
||||
# required: false
|
||||
# filter_logic: exact
|
||||
# weight: 30
|
||||
# default: First Item
|
||||
# on_objects:
|
||||
# - dcim.models.Device
|
||||
# choices:
|
||||
# - 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: put "false" in quotes!
|
||||
# weight: 90
|
||||
# on_objects:
|
||||
# - dcim.models.Device
|
||||
# url_field:
|
||||
# type: url
|
||||
# label: Hyperlink
|
||||
# description: Link to something nice.
|
||||
# required: true
|
||||
# filter_logic: disabled
|
||||
# on_objects:
|
||||
# - tenancy.models.Tenant
|
||||
# date_field:
|
||||
# type: date
|
||||
# label: Important Date
|
||||
# required: false
|
||||
# filter_logic: disabled
|
||||
# on_objects:
|
||||
# - dcim.models.Device
|
@ -1,21 +0,0 @@
|
||||
## 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
|
@ -1,18 +0,0 @@
|
||||
## Possible Choices:
|
||||
## type:
|
||||
## - virtual
|
||||
## - lag
|
||||
## - 1000base-t
|
||||
## - ... and many more. See for yourself:
|
||||
## https://github.com/netbox-community/netbox/blob/295d4f0394b431351c0cb2c3ecc791df68c6c2fb/netbox/dcim/choices.py#L510
|
||||
##
|
||||
## Examples:
|
||||
|
||||
# - device: server01
|
||||
# enabled: true
|
||||
# type: virtual
|
||||
# name: to-server02
|
||||
# - device: server02
|
||||
# enabled: true
|
||||
# type: virtual
|
||||
# name: to-server01
|
@ -1,15 +0,0 @@
|
||||
# - name: switch
|
||||
# slug: switch
|
||||
# color: Grey
|
||||
# - name: router
|
||||
# slug: router
|
||||
# color: Cyan
|
||||
# - name: load-balancer
|
||||
# slug: load-balancer
|
||||
# color: Red
|
||||
# - name: server
|
||||
# slug: server
|
||||
# color: Blue
|
||||
# - name: patchpanel
|
||||
# slug: patchpanel
|
||||
# color: Black
|
@ -1,23 +0,0 @@
|
||||
# - model: Model 1
|
||||
# manufacturer: Manufacturer 1
|
||||
# slug: model-1
|
||||
# u_height: 2
|
||||
# custom_field_data:
|
||||
# text_field: Description
|
||||
# - model: Model 2
|
||||
# manufacturer: Manufacturer 1
|
||||
# slug: model-2
|
||||
# custom_field_data:
|
||||
# text_field: Description
|
||||
# - model: Model 3
|
||||
# manufacturer: Manufacturer 1
|
||||
# slug: model-3
|
||||
# is_full_depth: false
|
||||
# u_height: 0
|
||||
# custom_field_data:
|
||||
# text_field: Description
|
||||
# - model: Other
|
||||
# manufacturer: No Name
|
||||
# slug: other
|
||||
# custom_field_data:
|
||||
# text_field: Description
|
@ -1,53 +0,0 @@
|
||||
## Possible Choices:
|
||||
## face:
|
||||
## - front
|
||||
## - rear
|
||||
## status:
|
||||
## - offline
|
||||
## - active
|
||||
## - planned
|
||||
## - staged
|
||||
## - failed
|
||||
## - inventory
|
||||
## - decommissioning
|
||||
##
|
||||
## Examples:
|
||||
|
||||
# - name: server01
|
||||
# device_role: server
|
||||
# device_type: Other
|
||||
# site: AMS 1
|
||||
# rack: rack-01
|
||||
# face: front
|
||||
# position: 1
|
||||
# custom_field_data:
|
||||
# text_field: Description
|
||||
# - name: server02
|
||||
# device_role: server
|
||||
# device_type: Other
|
||||
# site: AMS 2
|
||||
# rack: rack-02
|
||||
# face: front
|
||||
# position: 2
|
||||
# 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
|
||||
# device_type: Other
|
||||
# site: SING 1
|
||||
# rack: rack-03
|
||||
# face: front
|
||||
# position: 3
|
||||
# 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
|
@ -1,9 +0,0 @@
|
||||
# applications:
|
||||
# users:
|
||||
# - technical_user
|
||||
# readers:
|
||||
# users:
|
||||
# - reader
|
||||
# writers:
|
||||
# users:
|
||||
# - writer
|
@ -1,44 +0,0 @@
|
||||
## Possible Choices:
|
||||
## status:
|
||||
## - active
|
||||
## - reserved
|
||||
## - deprecated
|
||||
## - dhcp
|
||||
## role:
|
||||
## - loopback
|
||||
## - secondary
|
||||
## - anycast
|
||||
## - vip
|
||||
## - vrrp
|
||||
## - hsrp
|
||||
## - glbp
|
||||
## - carp
|
||||
##
|
||||
## Examples:
|
||||
|
||||
# - address: 10.1.1.1/24
|
||||
# device: server01
|
||||
# interface: to-server02
|
||||
# status: active
|
||||
# vrf: vrf1
|
||||
# - address: 2001:db8:a000:1::1/64
|
||||
# device: server01
|
||||
# interface: to-server02
|
||||
# status: active
|
||||
# vrf: vrf1
|
||||
# - address: 10.1.1.2/24
|
||||
# device: server02
|
||||
# interface: to-server01
|
||||
# status: active
|
||||
# - address: 2001:db8:a000:1::2/64
|
||||
# device: server02
|
||||
# interface: to-server01
|
||||
# status: active
|
||||
# - address: 10.1.1.10/24
|
||||
# description: reserved IP
|
||||
# status: reserved
|
||||
# tenant: tenant1
|
||||
# - address: 2001:db8:a000:1::10/64
|
||||
# description: reserved IP
|
||||
# status: reserved
|
||||
# tenant: tenant1
|
@ -1,3 +0,0 @@
|
||||
# - name: cage 101
|
||||
# slug: cage-101
|
||||
# site: SING 1
|
@ -1,6 +0,0 @@
|
||||
# - name: Manufacturer 1
|
||||
# slug: manufacturer-1
|
||||
# - name: Manufacturer 2
|
||||
# slug: manufacturer-2
|
||||
# - name: No Name
|
||||
# slug: no-name
|
@ -1,48 +0,0 @@
|
||||
# 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
|
@ -1,15 +0,0 @@
|
||||
# - name: Platform 1
|
||||
# slug: platform-1
|
||||
# manufacturer: Manufacturer 1
|
||||
# napalm_driver: driver1
|
||||
# napalm_args: "{'arg1': 'value1', 'arg2': 'value2'}"
|
||||
# - name: Platform 2
|
||||
# slug: platform-2
|
||||
# manufacturer: Manufacturer 2
|
||||
# napalm_driver: driver2
|
||||
# napalm_args: "{'arg1': 'value1', 'arg2': 'value2'}"
|
||||
# - name: Platform 3
|
||||
# slug: platform-3
|
||||
# manufacturer: No Name
|
||||
# napalm_driver: driver3
|
||||
# napalm_args: "{'arg1': 'value1', 'arg2': 'value2'}"
|
@ -1,14 +0,0 @@
|
||||
# - 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
|
@ -1,5 +0,0 @@
|
||||
# - name: power panel AMS 1
|
||||
# site: AMS 1
|
||||
# - name: power panel SING 1
|
||||
# site: SING 1
|
||||
# location: cage 101
|
@ -1,2 +0,0 @@
|
||||
# - name: Main Management
|
||||
# slug: main-management
|
@ -1,29 +0,0 @@
|
||||
## Possible Choices:
|
||||
## status:
|
||||
## - container
|
||||
## - active
|
||||
## - reserved
|
||||
## - deprecated
|
||||
##
|
||||
## Examples:
|
||||
|
||||
# - description: prefix1
|
||||
# prefix: 10.1.1.0/24
|
||||
# site: AMS 1
|
||||
# status: active
|
||||
# tenant: tenant1
|
||||
# vlan: vlan1
|
||||
# - description: prefix2
|
||||
# prefix: 10.1.2.0/24
|
||||
# site: AMS 2
|
||||
# status: active
|
||||
# tenant: tenant2
|
||||
# vlan: vlan2
|
||||
# is_pool: true
|
||||
# vrf: vrf2
|
||||
# - description: ipv6 prefix1
|
||||
# prefix: 2001:db8:a000:1::/64
|
||||
# site: AMS 2
|
||||
# status: active
|
||||
# tenant: tenant2
|
||||
# vlan: vlan2
|
@ -1,6 +0,0 @@
|
||||
# - name: Provider1
|
||||
# slug: provider1
|
||||
# asn: 121
|
||||
# - name: Provider2
|
||||
# slug: provider2
|
||||
# asn: 122
|
@ -1,12 +0,0 @@
|
||||
# - name: Role 1
|
||||
# slug: role-1
|
||||
# color: Pink
|
||||
# - name: Role 2
|
||||
# slug: role-2
|
||||
# color: Cyan
|
||||
# - name: Role 3
|
||||
# slug: role-3
|
||||
# color: Grey
|
||||
# - name: Role 4
|
||||
# slug: role-4
|
||||
# color: Teal
|
@ -1,41 +0,0 @@
|
||||
## Possible Choices:
|
||||
## width:
|
||||
## - 19
|
||||
## - 23
|
||||
## types:
|
||||
## - 2-post-frame
|
||||
## - 4-post-frame
|
||||
## - 4-post-cabinet
|
||||
## - wall-frame
|
||||
## - wall-cabinet
|
||||
## outer_unit:
|
||||
## - mm
|
||||
## - in
|
||||
##
|
||||
## Examples:
|
||||
|
||||
# - site: AMS 1
|
||||
# name: rack-01
|
||||
# role: Role 1
|
||||
# type: 4-post-cabinet
|
||||
# width: 19
|
||||
# u_height: 47
|
||||
# custom_field_data:
|
||||
# text_field: Description
|
||||
# - site: AMS 2
|
||||
# name: rack-02
|
||||
# role: Role 2
|
||||
# type: 4-post-cabinet
|
||||
# width: 19
|
||||
# u_height: 47
|
||||
# custom_field_data:
|
||||
# text_field: Description
|
||||
# - site: SING 1
|
||||
# name: rack-03
|
||||
# location: cage 101
|
||||
# role: Role 3
|
||||
# type: 4-post-cabinet
|
||||
# width: 19
|
||||
# u_height: 47
|
||||
# custom_field_data:
|
||||
# text_field: Description
|
@ -1,10 +0,0 @@
|
||||
# - name: Singapore
|
||||
# slug: singapore
|
||||
# - name: Amsterdam
|
||||
# slug: amsterdam
|
||||
# - name: Downtown
|
||||
# slug: downtown
|
||||
# parent: Amsterdam
|
||||
# - name: Suburbs
|
||||
# slug: suburbs
|
||||
# parent: Amsterdam
|
@ -1,9 +0,0 @@
|
||||
# - is_private: true
|
||||
# name: RFC1918
|
||||
# slug: rfc1918
|
||||
# - is_private: true
|
||||
# name: RFC4193 ULA
|
||||
# slug: rfc4193-ula
|
||||
# - is_private: true
|
||||
# name: RFC3849
|
||||
# slug: rfc3849
|
@ -1,3 +0,0 @@
|
||||
# - name: 65000:1001
|
||||
# tenant: tenant1
|
||||
# - name: 65000:1002
|
@ -1,15 +0,0 @@
|
||||
# - 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
|
@ -1,34 +0,0 @@
|
||||
# - name: AMS 1
|
||||
# slug: ams1
|
||||
# region: Downtown
|
||||
# status: active
|
||||
# facility: Amsterdam 1
|
||||
# asn: 12345
|
||||
# custom_field_data:
|
||||
# text_field: Description for AMS1
|
||||
# - name: AMS 2
|
||||
# slug: ams2
|
||||
# region: Downtown
|
||||
# status: active
|
||||
# facility: Amsterdam 2
|
||||
# asn: 54321
|
||||
# custom_field_data:
|
||||
# text_field: Description for AMS2
|
||||
# - name: AMS 3
|
||||
# slug: ams3
|
||||
# region: Suburbs
|
||||
# status: active
|
||||
# facility: Amsterdam 3
|
||||
# asn: 67890
|
||||
# tenant: tenant1
|
||||
# custom_field_data:
|
||||
# text_field: Description for AMS3
|
||||
# - name: SING 1
|
||||
# slug: sing1
|
||||
# region: Singapore
|
||||
# status: active
|
||||
# facility: Singapore 1
|
||||
# asn: 09876
|
||||
# tenant: tenant2
|
||||
# custom_field_data:
|
||||
# text_field: Description for SING1
|
@ -1,12 +0,0 @@
|
||||
# - 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
|
@ -1,4 +0,0 @@
|
||||
# - name: Tenant Group 1
|
||||
# slug: tenant-group-1
|
||||
# - name: Tenant Group 2
|
||||
# slug: tenant-group-2
|
@ -1,5 +0,0 @@
|
||||
# - name: tenant1
|
||||
# slug: tenant1
|
||||
# - name: tenant2
|
||||
# slug: tenant2
|
||||
# group: Tenant Group 2
|
@ -1,14 +0,0 @@
|
||||
# technical_user:
|
||||
# api_token: 0123456789technicaluser789abcdef01234567 # must be looooong!
|
||||
# reader:
|
||||
# password: reader
|
||||
# writer:
|
||||
# password: writer
|
||||
# jdoe:
|
||||
# first_name: John
|
||||
# last_name: Doe
|
||||
# api_token: 0123456789jdoe789abcdef01234567jdoe
|
||||
# is_active: True
|
||||
# is_superuser: False
|
||||
# is_staff: False
|
||||
# email: john.doe@example.com
|
@ -1,28 +0,0 @@
|
||||
## Possible Choices:
|
||||
## status:
|
||||
## - active
|
||||
## - offline
|
||||
## - staged
|
||||
##
|
||||
## Examples:
|
||||
|
||||
# - cluster: cluster1
|
||||
# comments: VM1
|
||||
# disk: 200
|
||||
# memory: 4096
|
||||
# name: virtual machine 1
|
||||
# platform: Platform 2
|
||||
# status: active
|
||||
# tenant: tenant1
|
||||
# vcpus: 8
|
||||
# - cluster: cluster1
|
||||
# comments: VM2
|
||||
# disk: 100
|
||||
# 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
|
@ -1,12 +0,0 @@
|
||||
# - description: Network Interface 1
|
||||
# enabled: true
|
||||
# mac_address: 00:77:77:77:77:77
|
||||
# mtu: 1500
|
||||
# name: Network Interface 1
|
||||
# virtual_machine: virtual machine 1
|
||||
# - description: Network Interface 2
|
||||
# enabled: true
|
||||
# mac_address: 00:55:55:55:55:55
|
||||
# mtu: 1500
|
||||
# name: Network Interface 2
|
||||
# virtual_machine: virtual machine 1
|
@ -1,24 +0,0 @@
|
||||
# - name: VLAN group 1
|
||||
# scope_type: dcim.region
|
||||
# scope: Amsterdam
|
||||
# slug: vlan-group-1
|
||||
# - name: VLAN group 2
|
||||
# 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
|
@ -1,19 +0,0 @@
|
||||
## Possible Choices:
|
||||
## status:
|
||||
## - active
|
||||
## - reserved
|
||||
## - deprecated
|
||||
##
|
||||
## Examples:
|
||||
|
||||
# - name: vlan1
|
||||
# site: AMS 1
|
||||
# status: active
|
||||
# vid: 5
|
||||
# role: Main Management
|
||||
# description: VLAN 5 for MGMT
|
||||
# - group: VLAN group 2
|
||||
# name: vlan2
|
||||
# site: AMS 1
|
||||
# status: active
|
||||
# vid: 1300
|
@ -1,8 +0,0 @@
|
||||
# - enforce_unique: true
|
||||
# name: vrf1
|
||||
# tenant: tenant1
|
||||
# description: main VRF
|
||||
# - enforce_unique: true
|
||||
# name: vrf2
|
||||
# rd: "6500:6500"
|
||||
# tenant: tenant2
|
@ -1,27 +0,0 @@
|
||||
## 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
|
@ -1,46 +0,0 @@
|
||||
from dcim.choices import DeviceStatusChoices
|
||||
from dcim.models import ConsolePort, Device, PowerPort
|
||||
from extras.reports import Report
|
||||
|
||||
|
||||
class DeviceConnectionsReport(Report):
|
||||
description = "Validate the minimum physical connections for each device"
|
||||
|
||||
def test_console_connection(self):
|
||||
|
||||
# Check that every console port for every active device has a connection defined.
|
||||
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 not console_port.connection_status:
|
||||
self.log_warning(
|
||||
console_port.device,
|
||||
"Console connection for {} marked as planned".format(console_port.name)
|
||||
)
|
||||
else:
|
||||
self.log_success(console_port.device)
|
||||
|
||||
def test_power_connections(self):
|
||||
|
||||
# Check that every active device has at least two connected power supplies.
|
||||
for device in Device.objects.filter(status=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 not power_port.connection_status:
|
||||
self.log_warning(
|
||||
device,
|
||||
"Power connection for {} marked as planned".format(power_port.name)
|
||||
)
|
||||
if connected_ports < 2:
|
||||
self.log_failure(
|
||||
device,
|
||||
"{} connected power supplies found (2 needed)".format(connected_ports)
|
||||
)
|
||||
else:
|
||||
self.log_success(device)
|
@ -1,4 +1,6 @@
|
||||
napalm==3.3.1
|
||||
ruamel.yaml==0.17.16
|
||||
django-auth-ldap==3.0.0
|
||||
django-storages[azure,boto3,dropbox,google,libcloud,sftp]==1.11.1
|
||||
django-auth-ldap==5.1.0
|
||||
dulwich==0.22.8
|
||||
python3-saml==1.16.0
|
||||
--no-binary lxml
|
||||
--no-binary xmlsec
|
||||
sentry-sdk[django]==2.27.0
|
||||
|
@ -1,21 +0,0 @@
|
||||
import sys
|
||||
|
||||
from django.contrib.auth.models import User
|
||||
from startup_script_utils import load_yaml
|
||||
from users.models import Token
|
||||
|
||||
users = load_yaml("/opt/netbox/initializers/users.yml")
|
||||
if users is None:
|
||||
sys.exit()
|
||||
|
||||
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(),
|
||||
)
|
||||
|
||||
print("👤 Created user", username)
|
||||
|
||||
if user_details.get("api_token", 0):
|
||||
Token.objects.create(user=user, key=user_details["api_token"])
|
@ -1,23 +0,0 @@
|
||||
import sys
|
||||
|
||||
from startup_script_utils import load_yaml
|
||||
from users.models import AdminGroup, AdminUser
|
||||
|
||||
groups = load_yaml("/opt/netbox/initializers/groups.yml")
|
||||
if groups is None:
|
||||
sys.exit()
|
||||
|
||||
for groupname, group_details in groups.items():
|
||||
group, created = AdminGroup.objects.get_or_create(name=groupname)
|
||||
|
||||
if created:
|
||||
print("👥 Created group", groupname)
|
||||
|
||||
for username in group_details.get("users", []):
|
||||
user = AdminUser.objects.get(username=username)
|
||||
|
||||
if user:
|
||||
group.user_set.add(user)
|
||||
print(" 👤 Assigned user %s to group %s" % (username, AdminGroup.name))
|
||||
|
||||
group.save()
|
@ -1,60 +0,0 @@
|
||||
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()
|
@ -1,64 +0,0 @@
|
||||
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
|
||||
|
||||
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)
|
||||
|
||||
|
||||
customfields = load_yaml("/opt/netbox/initializers/custom_fields.yml")
|
||||
|
||||
if customfields is None:
|
||||
sys.exit()
|
||||
|
||||
for cf_name, cf_details in customfields.items():
|
||||
custom_field, created = CustomField.objects.get_or_create(name=cf_name)
|
||||
|
||||
if created:
|
||||
if cf_details.get("default", False):
|
||||
custom_field.default = cf_details["default"]
|
||||
|
||||
if cf_details.get("description", False):
|
||||
custom_field.description = cf_details["description"]
|
||||
|
||||
if cf_details.get("label", False):
|
||||
custom_field.label = cf_details["label"]
|
||||
|
||||
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("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()
|
||||
|
||||
print("🔧 Created custom field", cf_name)
|
@ -1,23 +0,0 @@
|
||||
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)
|
@ -1,15 +0,0 @@
|
||||
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)
|
@ -1,25 +0,0 @@
|
||||
import sys
|
||||
|
||||
from dcim.models import Region
|
||||
from startup_script_utils import load_yaml
|
||||
|
||||
regions = load_yaml("/opt/netbox/initializers/regions.yml")
|
||||
|
||||
if regions is None:
|
||||
sys.exit()
|
||||
|
||||
optional_assocs = {"parent": (Region, "name")}
|
||||
|
||||
for params in regions:
|
||||
|
||||
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)
|
||||
|
||||
region, created = Region.objects.get_or_create(**params)
|
||||
|
||||
if created:
|
||||
print("🌐 Created region", region.name)
|
@ -1,28 +0,0 @@
|
||||
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)
|
@ -1,29 +0,0 @@
|
||||
import sys
|
||||
|
||||
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
|
||||
|
||||
sites = load_yaml("/opt/netbox/initializers/sites.yml")
|
||||
|
||||
if sites is None:
|
||||
sys.exit()
|
||||
|
||||
optional_assocs = {"region": (Region, "name"), "tenant": (Tenant, "name")}
|
||||
|
||||
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)}
|
||||
|
||||
params[assoc] = model.objects.get(**query)
|
||||
|
||||
site, created = Site.objects.get_or_create(**params)
|
||||
|
||||
if created:
|
||||
set_custom_fields_values(site, custom_field_data)
|
||||
|
||||
print("📍 Created site", site.name)
|
@ -1,15 +0,0 @@
|
||||
import sys
|
||||
|
||||
from dcim.models import Manufacturer
|
||||
from startup_script_utils import load_yaml
|
||||
|
||||
manufacturers = load_yaml("/opt/netbox/initializers/manufacturers.yml")
|
||||
|
||||
if manufacturers is None:
|
||||
sys.exit()
|
||||
|
||||
for params in manufacturers:
|
||||
manufacturer, created = Manufacturer.objects.get_or_create(**params)
|
||||
|
||||
if created:
|
||||
print("🏭 Created Manufacturer", manufacturer.name)
|
@ -1,37 +0,0 @@
|
||||
import sys
|
||||
|
||||
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
|
||||
|
||||
device_types = load_yaml("/opt/netbox/initializers/device_types.yml")
|
||||
|
||||
if device_types is None:
|
||||
sys.exit()
|
||||
|
||||
required_assocs = {"manufacturer": (Manufacturer, "name")}
|
||||
|
||||
optional_assocs = {"region": (Region, "name"), "tenant": (Tenant, "name")}
|
||||
|
||||
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)}
|
||||
|
||||
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_type, created = DeviceType.objects.get_or_create(**params)
|
||||
|
||||
if created:
|
||||
set_custom_fields_values(device_type, custom_field_data)
|
||||
|
||||
print("🔡 Created device type", device_type.manufacturer, device_type.model)
|
@ -1,23 +0,0 @@
|
||||
import sys
|
||||
|
||||
from dcim.models import RackRole
|
||||
from startup_script_utils import load_yaml
|
||||
from utilities.choices import ColorChoices
|
||||
|
||||
rack_roles = load_yaml("/opt/netbox/initializers/rack_roles.yml")
|
||||
|
||||
if rack_roles is None:
|
||||
sys.exit()
|
||||
|
||||
for params in rack_roles:
|
||||
if "color" in params:
|
||||
color = params.pop("color")
|
||||
|
||||
for color_tpl in ColorChoices:
|
||||
if color in color_tpl:
|
||||
params["color"] = color_tpl[0]
|
||||
|
||||
rack_role, created = RackRole.objects.get_or_create(**params)
|
||||
|
||||
if created:
|
||||
print("🎨 Created rack role", rack_role.name)
|
@ -1,23 +0,0 @@
|
||||
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)
|
@ -1,41 +0,0 @@
|
||||
import sys
|
||||
|
||||
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
|
||||
|
||||
racks = load_yaml("/opt/netbox/initializers/racks.yml")
|
||||
|
||||
if racks is None:
|
||||
sys.exit()
|
||||
|
||||
required_assocs = {"site": (Site, "name")}
|
||||
|
||||
optional_assocs = {
|
||||
"role": (RackRole, "name"),
|
||||
"tenant": (Tenant, "name"),
|
||||
"location": (Location, "name"),
|
||||
}
|
||||
|
||||
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)}
|
||||
|
||||
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)
|
||||
|
||||
rack, created = Rack.objects.get_or_create(**params)
|
||||
|
||||
if created:
|
||||
set_custom_fields_values(rack, custom_field_data)
|
||||
|
||||
print("🔳 Created rack", rack.site, rack.name)
|
@ -1,24 +0,0 @@
|
||||
import sys
|
||||
|
||||
from dcim.models import DeviceRole
|
||||
from startup_script_utils import load_yaml
|
||||
from utilities.choices import ColorChoices
|
||||
|
||||
device_roles = load_yaml("/opt/netbox/initializers/device_roles.yml")
|
||||
|
||||
if device_roles is None:
|
||||
sys.exit()
|
||||
|
||||
for params in device_roles:
|
||||
|
||||
if "color" in params:
|
||||
color = params.pop("color")
|
||||
|
||||
for color_tpl in ColorChoices:
|
||||
if color in color_tpl:
|
||||
params["color"] = color_tpl[0]
|
||||
|
||||
device_role, created = DeviceRole.objects.get_or_create(**params)
|
||||
|
||||
if created:
|
||||
print("🎨 Created device role", device_role.name)
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user