Compare commits

...

45 Commits

Author SHA1 Message Date
5769684c98 Merge pull request #265 from netbox-community/develop
Release 0.23.0
2020-03-30 20:51:22 +02:00
23e2da52f8 Preparation for 0.23.0 2020-03-30 15:15:30 +02:00
edba1a22fc Merge pull request #263 from general-programming/RELEASE_CHECK_URL
Add RELEASE_CHECK_URL to configuration and default env.
2020-03-30 15:13:59 +02:00
f87ffe7c33 Update configuration/configuration.py
Co-Authored-By: Christian Mäder <cimnine@users.noreply.github.com>
2020-03-29 01:40:08 -07:00
8bc77c1bc0 Add RELEASE_CHECK_URL to configuration and default env. 2020-03-27 21:34:51 -07:00
7662d81efe Merge pull request #258 from netbox-community/readme_improvements
Readme improvements
2020-03-17 16:39:43 +01:00
7f489aa11d Improved the README
- adjust the _Quick Start_ section to match the instructions in the _Getting Started_ guide on our wiki
- Adds a new _Getting Help_ section
- Improvements in explaining the tags of the published Docker image
2020-03-17 16:07:15 +01:00
5c3eff0823 Merge pull request #255 from minitriga/issue_253_docs_2
Fix embedded documents for Netbox version v2.7.10 and higher.
2020-03-11 12:16:48 +01:00
5f90ad8c56 inlude docs in container 2020-03-11 10:40:10 +00:00
5f1c241145 Merge pull request #245 from ScanPlusGmbH/fix-configuration-inconsistencies
Fix configuration inconsistencies
2020-03-11 09:53:21 +01:00
20c7461c7b Fixed test failures because of missing cache
When running tests with ´test.sh´ some errors where logged because now
redis-cache instance was running.
2020-02-14 12:38:05 +01:00
b9c44b85cc The Redis cache container was using the wrong env
Our docker-compose.yml pointed the env file for the Redis cache to the
wrong file. Now the Redis cache password between the netbox.env and
redis-cache.env match.
2020-02-14 12:38:05 +01:00
355ebadd10 Fixed configuration inconsistency for Redis cache
In the configuration.py we use database 1 as the default but in the .env
file we used 0. This sets both values to 1 as the default.
2020-02-14 12:38:05 +01:00
880628876f Merge pull request #244 from ScanPlusGmbH/init-perms-function
Permission handling in external function
2020-02-13 08:15:27 +01:00
8d3bd48c7a Permission handling in external function
This move the setting of user and group permissions in the startup
script to its own function.
2020-02-12 09:36:49 +01:00
882f7bcaf2 Merge pull request #238 from ScanPlusGmbH/remove-redundancy
Add function to load YAML files
2020-02-10 19:25:42 +01:00
50ade7bce1 Add function to load YAML files
This commit starts to remove some code redundancy from the startup
scripts for easier maintenance.
2020-02-10 07:47:17 +01:00
80f514fa90 Merge pull request #239 from netbox-community/develop
Release 0.22.0
2020-02-08 10:44:21 +01:00
c5822b9cec Merge pull request #235 from netbox-community/prepare-0.22.0
Prepare v0.22.0
2020-02-08 10:10:51 +01:00
e99a222a70 Prepare v0.22.0 2020-02-03 17:56:14 +01:00
3717b7469a Merge pull request #236 from netbox-community/LBegnaud-master
Permission Wildcards
2020-02-03 17:55:22 +01:00
3d80cc5a72 Tiny code refactoring 2020-02-02 09:48:02 +01:00
69ef7b7827 Removed the eval from the code
... and changed it to make it work with the latest Netbox version.
2020-01-31 11:39:05 +01:00
ba3176f140 Added missing keywords to the yaml
... and moved some documentatory comments to the beginning of the file.
2020-01-31 11:37:05 +01:00
a2c06026d5 Ajdust indents in __main__.py
... so that the match the style of the other python code in this project
2020-01-31 11:35:25 +01:00
f4e243d5ad update example to note yaml restriction 2020-01-31 09:27:34 +01:00
aa0d2a6e01 simplify yml definitions to use wildcard syntax 2020-01-31 09:27:34 +01:00
cce4370d41 add permission example 2020-01-31 09:27:34 +01:00
927a545f41 adjust groups and users startup scripts to allow custom codename filter 2020-01-31 09:27:34 +01:00
0574ffc571 Merge pull request #233 from newlandk/patch-1
update ldap caching configuration
2020-01-31 09:25:45 +01:00
ce74e94cbb Merge pull request #234 from netbox-community/test-pr
Enable push workflow for PRs
2020-01-31 09:18:31 +01:00
778f7546b8 Enable push workflow for PRs 2020-01-30 15:48:01 +01:00
74eaae6bc8 Update ldap_config.py 2020-01-28 17:43:35 -06:00
00986573d9 Update LDAP Caching Options
Update LDAP caching configuration to match changes made to django-auth-ldap in 1.6.0

Django social auth now uses different cache configuration options: https://github.com/django-auth-ldap/django-auth-ldap/blob/master/django_auth_ldap/backend.py#L1041-L1056

NetBox settings.py reference: https://github.com/netbox-community/netbox/blob/master/netbox/netbox/settings.py#L360
2020-01-28 17:36:45 -06:00
b0b20aa6ba Merge pull request #232 from netbox-community/develop
Release 0.21.1
2020-01-23 18:08:29 +01:00
f3a858811a Merge pull request #230 from netbox-community/prepare-0.21.1
Preparation for 0.21.1
2020-01-23 15:50:54 +01:00
1eb40d1774 Preparation for 0.21.1 2020-01-23 15:34:22 +01:00
1f25fba671 Merge pull request #229 from netbox-community/fix_shields
Readme Cleanup
2020-01-23 15:32:41 +01:00
f525351cfe Merge pull request #231 from netbox-community/green_tests
Disable python 3.9 tests once more
2020-01-23 15:31:46 +01:00
0e625a3b5c Disable python 3.9 tests once more 2020-01-23 10:44:02 +01:00
f0b00ee104 Update docker inspect command in bug_report template 2020-01-23 10:40:28 +01:00
1c8d695fc2 Remove references to the old build system 2020-01-23 10:36:13 +01:00
653321994a Fix link 2020-01-23 10:26:21 +01:00
132ab6fcca Fix typo in PR template 2020-01-23 10:09:56 +01:00
9229b45dc2 Fix build status badge 2020-01-23 09:35:30 +01:00
47 changed files with 798 additions and 938 deletions

View File

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

View File

@ -48,7 +48,7 @@ The output of `git rev-parse HEAD`: `XXXXX`
The command you used to start the project: `XXXXX` The command you used to start the project: `XXXXX`
<!-- adjust the `latest` tag to the version you're using --> <!-- adjust the `latest` tag to the version you're using -->
The output of `docker inspect netboxcommunity/netbox:latest --format "{{json .ContainerConfig.Labels}}"`: The output of `docker inspect netboxcommunity/netbox:latest --format "{{json .Config.Labels}}"`:
```json ```json
{ {

View File

@ -1,5 +1,5 @@
<!-- <!--
############################################################################### #########################################################################
Thank you for sharing your work and for opening a PR. Thank you for sharing your work and for opening a PR.
@ -9,11 +9,11 @@ First make sure that you point your PR to the `develop` branch!
Now please read the comments carefully and try to provide information Now please read the comments carefully and try to provide information
on all relevant titles. on all relevant titles.
############################################################################### #########################################################################
--> -->
<!-- <!--
Please don't open an extra issue when submiting a PR. Please don't open an extra issue when submitting a PR.
But if there is already a related issue, please put it's number here. But if there is already a related issue, please put it's number here.
@ -81,5 +81,5 @@ 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 read the comments and followed the PR template.
* [ ] I have provided and explained my PR according to the information in the comments. * [ ] I have explained my PR according to the information in the comments.
* [ ] My PR targets the `develop` branch. * [ ] My PR targets the `develop` branch.

View File

@ -1,7 +1,12 @@
name: push
on: on:
push: push:
branches-ignore: branches-ignore:
- release - release
pull_request:
branches-ignore:
- release
jobs: jobs:
build: build:
@ -15,7 +20,7 @@ jobs:
- '' # use the default of the DOCKERFILE - '' # use the default of the DOCKERFILE
- python:3.7-alpine - python:3.7-alpine
- python:3.8-alpine - python:3.8-alpine
- python:3.9-rc-alpine # - python:3.9-rc-alpine # disable until Netbox's unit tests work
fail-fast: false fail-fast: false
runs-on: ubuntu-latest runs-on: ubuntu-latest
name: Builds new Netbox Docker Images name: Builds new Netbox Docker Images

View File

@ -1,3 +1,5 @@
name: release
on: on:
push: push:
branches: branches:

View File

@ -1,63 +0,0 @@
# cloud.docker.com Configuration
The automatic build is configured in cloud.docker.com.
The following build configuration is expected:
```yaml
Source Repository: github.com/netbox-community/netbox-docker
Build Location: Build on Docker Hub's infrastructure
Autotest: Internal and External Pull Requests
Repository Links: Enable for Base Image
Build Rules:
- Source Type: Branch
Source: release
Docker Tag: branches
Dockerfile location: Dockerfile
Build Context: /
Autobuild: on
Build Caching: on
- Source Type: Branch
Source: release
Docker Tag: prerelease
Dockerfile location: Dockerfile
Build Context: /
Autobuild: on
Build Caching: on
- Source Type: Branch
Source: release
Docker Tag: release
Dockerfile location: Dockerfile
Build Context: /
Autobuild: on
Build Caching: on
Build Environment Variables:
# Create an app on Github and use it's OATH credentials here
- Key: GITHUB_OAUTH_CLIENT_ID
Value: <secret>
- Key: GITHUB_OAUTH_CLIENT_SECRET
Value: <secret>
Build Triggers:
- Name: Cron Trigger
Trigger URL: <generated>
# Use this trigger in combination with e.g. https://cron-job.org in order to regularly schedule builds
```
## Background Knowledge
The build system of cloud.docker.com is not made for this kind of project.
But we found a way to make it work, and this is how:
1. The docker hub build system [allows to overwrite the scripts that get executed
for `build`, `test` and `push`](overwrite). See `/hooks/*`.
2. Shared functionality of the scripts `build`, `test` and `push` is extracted to `/hooks/common`.
3. The `build` script runs `run_build()` from `/hooks/common`.
This triggers either `/build-branches.sh`, `/build-latest.sh` or directly `/build.sh`.
4. The `test` script just invokes `docker-compose` commands.
5. The `push` script runs `run_build()` from `hooks/common` with a `--push-only` flag.
This causes the `build.sh` script to not re-build the Docker image, but just the just built image.
The _Docker Tag_ configuration setting (`$DOCKER_TAG`) is only used to select the type (_release_, _prerelease_, _branches_) of the build in `hooks/common`.
Because it has a different meaning in all the other build scripts, it is `unset` after it has served it's purpose.
[overwrite]: https://docs.docker.com/docker-hub/builds/advanced/#override-build-test-or-push-commands

View File

@ -3,7 +3,7 @@
[![GitHub release (latest by date)](https://img.shields.io/github/v/release/netbox-community/netbox-docker)][github-release] [![GitHub release (latest by date)](https://img.shields.io/github/v/release/netbox-community/netbox-docker)][github-release]
[![GitHub stars](https://img.shields.io/github/stars/netbox-community/netbox-docker)][github-stargazers] [![GitHub stars](https://img.shields.io/github/stars/netbox-community/netbox-docker)][github-stargazers]
![GitHub closed pull requests](https://img.shields.io/github/issues-pr-closed-raw/netbox-community/netbox-docker) ![GitHub closed pull requests](https://img.shields.io/github/issues-pr-closed-raw/netbox-community/netbox-docker)
![Docker Cloud Build Status](https://img.shields.io/docker/cloud/build/netboxcommunity/netbox) ![Github release workflow](https://img.shields.io/github/workflow/status/netbox-community/netbox-docker/release)
![Docker Pulls](https://img.shields.io/docker/pulls/netboxcommunity/netbox) ![Docker Pulls](https://img.shields.io/docker/pulls/netboxcommunity/netbox)
[![MicroBadger Layers](https://img.shields.io/microbadger/layers/netboxcommunity/netbox)][netbox-docker-microbadger] [![MicroBadger Layers](https://img.shields.io/microbadger/layers/netboxcommunity/netbox)][netbox-docker-microbadger]
[![MicroBadger Size](https://img.shields.io/microbadger/image-size/netboxcommunity/netbox)][netbox-docker-microbadger] [![MicroBadger Size](https://img.shields.io/microbadger/image-size/netboxcommunity/netbox)][netbox-docker-microbadger]
@ -12,7 +12,8 @@
[The Github repository](netbox-docker-github) houses the components needed to build Netbox as a Docker container. [The Github repository](netbox-docker-github) houses the components needed to build Netbox as a Docker container.
Images are built using this code and are released to [Docker Hub][netbox-dockerhub] once a day. Images are built using this code and are released to [Docker Hub][netbox-dockerhub] once a day.
Do you have any questions? Before opening an issue on Github, please join the [Network To Code][ntc-slack] Slack and ask for help in our [`#netbox-docker`][netbox-docker-slack] channel. Do you have any questions?
Before opening an issue on Github, please join the [Network To Code][ntc-slack] Slack and ask for help in our [`#netbox-docker`][netbox-docker-slack] channel.
[github-stargazers]: https://github.com/netbox-community/netbox-docker/stargazers [github-stargazers]: https://github.com/netbox-community/netbox-docker/stargazers
[github-release]: https://github.com/netbox-community/netbox-docker/releases [github-release]: https://github.com/netbox-community/netbox-docker/releases
@ -21,20 +22,22 @@ Do you have any questions? Before opening an issue on Github, please join the [N
[netbox-docker-github]: https://github.com/netbox-community/netbox-docker/ [netbox-docker-github]: https://github.com/netbox-community/netbox-docker/
[ntc-slack]: http://slack.networktocode.com/ [ntc-slack]: http://slack.networktocode.com/
[netbox-docker-slack]: https://slack.com/app_redirect?channel=netbox-docker&team=T09LQ7E9E [netbox-docker-slack]: https://slack.com/app_redirect?channel=netbox-docker&team=T09LQ7E9E
[netbox-docker-license]: https://github.com/netbox-community/netbox-docker/blob/master/LICENSE [netbox-docker-license]: https://github.com/netbox-community/netbox-docker/blob/release/LICENSE
## Docker Tags ## Docker Tags
* `vX.Y.Z`: Release builds, built from [releases of Netbox][netbox-releases]. * `vX.Y.Z`: These are release builds, automatically built from [the corresponding releases of Netbox][netbox-releases].
* `latest`: Release builds, built from [`master` branch of Netbox][netbox-master]. * `latest`: These are release builds, automatically built from [the `master` branch of Netbox][netbox-master].
* `snapshot`: Pre-release builds, built from the [`develop` branch of Netbox][netbox-develop]. * `snapshot`: These are pre-release builds, automatically built from the [`develop` branch of Netbox][netbox-develop].
* `develop-X.Y`: Pre-release builds, built from the corresponding [branch of Netbox][netbox-branches]. * `develop-X.Y`: These are pre-release builds, automatically built from the corresponding [branch of Netbox][netbox-branches].
Then there is currently one extra tags for each of the above labels: Then there is currently one extra tags for each of the above tags:
* `-ldap`: Contains additional dependencies and configurations for connecting Netbox to an LDAP directroy. * `-ldap`: Contains additional dependencies and configurations for connecting Netbox to an LDAP directroy.
[Learn more about that in our wiki][netbox-docker-ldap]. [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-releases]: https://github.com/netbox-community/netbox/releases
[netbox-master]: https://github.com/netbox-community/netbox/tree/master [netbox-master]: https://github.com/netbox-community/netbox/tree/master
[netbox-develop]: https://github.com/netbox-community/netbox/tree/develop [netbox-develop]: https://github.com/netbox-community/netbox/tree/develop
@ -43,42 +46,50 @@ Then there is currently one extra tags for each of the above labels:
## Quickstart ## Quickstart
To get Netbox up and running in Docker: To get Netbox Docker up and running run the following commands.
There is a more complete [_Getting Started_ guide on our wiki][wiki-getting-started] which explains every step.
```bash ```bash
git clone -b release https://github.com/netbox-community/netbox-docker.git git clone -b release https://github.com/netbox-community/netbox-docker.git
cd netbox-docker cd netbox-docker
tee netbox-docker.override.yml <<EOF
version: '3.4'
services:
nginx:
ports:
- 8000:8080
EOF
docker-compose pull docker-compose pull
docker-compose up -d docker-compose up
``` ```
The application will be available after a few minutes. The whole application will be available after a few minutes.
Use `docker-compose port nginx 8080` to find out where to connect to. Open the URL `http://0.0.0.0:8000/` in a web-browser.
You should see the Netbox homepage.
```bash In the top-right corner you can login.
$ echo "http://$(docker-compose port nginx 8080)/"
http://0.0.0.0:32768/
# Open netbox in your default browser on macOS:
$ open "http://$(docker-compose port nginx 8080)/"
# Open netbox in your default browser on (most) linuxes:
$ xdg-open "http://$(docker-compose port nginx 8080)/" &>/dev/null &
```
Alternatively, use something like [Reception][docker-reception] to connect to _docker-compose_ projects.
The default credentials are: The default credentials are:
* Username: **admin** * Username: **admin**
* Password: **admin** * Password: **admin**
* API Token: **0123456789abcdef0123456789abcdef01234567** * API Token: **0123456789abcdef0123456789abcdef01234567**
There is a more complete [Getting Started guide on our Wiki][wiki-getting-started].
[wiki-getting-started]: https://github.com/netbox-community/netbox-docker/wiki/Getting-Started [wiki-getting-started]: https://github.com/netbox-community/netbox-docker/wiki/Getting-Started
[docker-reception]: https://github.com/nxt-engineering/reception [docker-reception]: https://github.com/nxt-engineering/reception
## Documentation
Please refer [to our wiki on Github][netbox-docker-wiki] for further information on how to use this Netbox Docker image properly.
It covers advanced topics such as using secret files, deployment to Kubernetes as well as NAPALM and LDAP configuration.
[netbox-docker-wiki]: https://github.com/netbox-community/netbox-docker/wiki/
## Getting Help
Please join [our Slack channel `#netbox-docker`][netbox-docker-slack] on the [Network To Code Slack][ntc-slack].
It's free to use and there are almost always people online that can help.
If you need help with using Netbox or developing for it or against it's API you may find the `#netbox` channel on the same Slack instance very helpful.
## Dependencies ## 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:
@ -88,17 +99,10 @@ This project relies only on *Docker* and *docker-compose* meeting these requirem
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`.
## Documentation ## Use a Specific Netbox Version
Please refer [to our wiki on Github][netbox-docker-wiki] for further information on how to use this Netbox Docker image properly. The `docker-compose.yml` file is prepared to run a specific version of Netbox, instead of `latest`.
It covers advanced topics such as using secret files, deployment to Kubernetes as well as NAPALM and LDAP configuration. To use this feature, set and export the environment-variable `VERSION` before launching `docker-compose`, as shown below.
[netbox-docker-wiki]: https://github.com/netbox-community/netbox-docker/wiki/
## Netbox Version
The `docker-compose.yml` file is prepared to run a specific version of Netbox.
To use this feature, set the environment-variable `VERSION` before launching `docker-compose`, as shown below.
`VERSION` may be set to the name of `VERSION` may be set to the name of
[any tag of the `netboxcommunity/netbox` Docker image on Docker Hub][netbox-dockerhub]. [any tag of the `netboxcommunity/netbox` Docker image on Docker Hub][netbox-dockerhub].
@ -124,31 +128,30 @@ docker-compose up -d
From time to time it might become necessary to re-engineer the structure of this setup. 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. 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. 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.) (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 .ContainerConfig.Labels}}"`. You can check the label of your local image by running `docker inspect netboxcommunity/netbox:v2.7.1 --format "{{json .Config.Labels}}"`.
Please read [the release notes][releases] carefully when updating to a new image version. Please read [the release notes][releases] carefully when updating to a new image version.
[releases]: https://github.com/netbox-community/netbox-docker/releases [releases]: https://github.com/netbox-community/netbox-docker/releases
## Rebuilding & Publishing images ## 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 Docker image. See `./build.sh --help` for more information.
### Publishing Docker Images For more details on custom builds [consult our wiki][netbox-docker-wiki-build].
New Docker images are built and published every 24h on the [Docker Build Infrastructure][docker-build-infra]. [netbox-docker-wiki-build]: https://github.com/netbox-community/netbox-docker/wiki/Build
`DOCKER_HUB.md` contains more information about the build infrastructure.
[docker-build-infra]: https://hub.docker.com/r/netboxcommunity/netbox/builds/
## Tests ## Tests
To run the tests coming with Netbox, use the `docker-compose.yml` file as such: We have a test script.
It runs Netbox's own unit tests and ensures that all initializers work:
```bash ```bash
docker-compose run netbox ./manage.py test IMAGE=netboxcommunity/netbox:latest ./test.sh
``` ```
## About ## About

View File

@ -1 +1 @@
0.21.0 0.23.0

View File

@ -170,6 +170,15 @@ PAGINATE_COUNT = int(os.environ.get('PAGINATE_COUNT', 50))
# When determining the primary IP address for a device, IPv6 is preferred over IPv4 by default. Set this to True to # 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 instead.
PREFER_IPV4 = os.environ.get('PREFER_IPV4', 'False').lower() == 'true' PREFER_IPV4 = os.environ.get('PREFER_IPV4', 'False').lower() == 'true'
# This determines how often the GitHub API is called to check the latest release of NetBox in seconds. Must be at least 1 hour.
RELEASE_CHECK_TIMEOUT = os.environ.get('RELEASE_CHECK_TIMEOUT', 24 * 3600)
# 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 = os.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 # 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. # this setting is derived from the installed location.
REPORTS_ROOT = os.environ.get('REPORTS_ROOT', '/etc/netbox/reports') REPORTS_ROOT = os.environ.get('REPORTS_ROOT', '/etc/netbox/reports')

View File

@ -70,8 +70,7 @@ AUTH_LDAP_USER_FLAGS_BY_GROUP = {
AUTH_LDAP_FIND_GROUP_PERMS = os.environ.get('AUTH_LDAP_FIND_GROUP_PERMS', 'True').lower() == 'true' AUTH_LDAP_FIND_GROUP_PERMS = os.environ.get('AUTH_LDAP_FIND_GROUP_PERMS', 'True').lower() == 'true'
# Cache groups for one hour to reduce LDAP traffic # Cache groups for one hour to reduce LDAP traffic
AUTH_LDAP_CACHE_GROUPS = os.environ.get('AUTH_LDAP_CACHE_GROUPS', 'True').lower() == 'true' AUTH_LDAP_CACHE_TIMEOUT = int(os.environ.get('AUTH_LDAP_CACHE_TIMEOUT', 3600))
AUTH_LDAP_GROUP_CACHE_TIMEOUT = int(os.environ.get('AUTH_LDAP_GROUP_CACHE_TIMEOUT', 3600))
# Populate the Django user from the LDAP directory. # Populate the Django user from the LDAP directory.
AUTH_LDAP_USER_ATTR_MAP = { AUTH_LDAP_USER_ATTR_MAP = {

View File

@ -5,6 +5,7 @@ services:
depends_on: depends_on:
- postgres - postgres
- redis - redis
- redis-cache
env_file: env/netbox.env env_file: env/netbox.env
user: '101' user: '101'
volumes: volumes:
@ -34,8 +35,15 @@ services:
command: command:
- sh - sh
- -c # this is to evaluate the $REDIS_PASSWORD from the env - -c # this is to evaluate the $REDIS_PASSWORD from the env
- redis-server --requirepass $$REDIS_PASSWORD ## $$ because of docker-compose - redis-server --appendonly yes --requirepass $$REDIS_PASSWORD ## $$ because of docker-compose
env_file: env/redis.env env_file: env/redis.env
redis-cache:
image: redis:5-alpine
command:
- sh
- -c # this is to evaluate the $REDIS_PASSWORD from the env
- redis-server --requirepass $$REDIS_PASSWORD ## $$ because of docker-compose
env_file: env/redis-cache.env
volumes: volumes:
netbox-static-files: netbox-static-files:
driver: local driver: local

View File

@ -57,7 +57,7 @@ services:
- sh - sh
- -c # this is to evaluate the $REDIS_PASSWORD from the env - -c # this is to evaluate the $REDIS_PASSWORD from the env
- redis-server --requirepass $$REDIS_PASSWORD ## $$ because of docker-compose - redis-server --requirepass $$REDIS_PASSWORD ## $$ because of docker-compose
env_file: env/redis.env env_file: env/redis-cache.env
volumes: volumes:
netbox-static-files: netbox-static-files:
driver: local driver: local

3
env/netbox.env vendored
View File

@ -20,7 +20,7 @@ REDIS_DATABASE=0
REDIS_SSL=false REDIS_SSL=false
REDIS_CACHE_HOST=redis-cache REDIS_CACHE_HOST=redis-cache
REDIS_CACHE_PASSWORD=t4Ph722qJ5QHeQ1qfu36 REDIS_CACHE_PASSWORD=t4Ph722qJ5QHeQ1qfu36
REDIS_CACHE_DATABASE=0 REDIS_CACHE_DATABASE=1
REDIS_CACHE_SSL=false REDIS_CACHE_SSL=false
SECRET_KEY=r8OwDznj!!dci#P9ghmRfdu1Ysxm0AiPeDCQhKE+N_rClfWNj SECRET_KEY=r8OwDznj!!dci#P9ghmRfdu1Ysxm0AiPeDCQhKE+N_rClfWNj
SKIP_STARTUP_SCRIPTS=false SKIP_STARTUP_SCRIPTS=false
@ -30,3 +30,4 @@ SUPERUSER_EMAIL=admin@example.com
SUPERUSER_PASSWORD=admin SUPERUSER_PASSWORD=admin
SUPERUSER_API_TOKEN=0123456789abcdef0123456789abcdef01234567 SUPERUSER_API_TOKEN=0123456789abcdef0123456789abcdef01234567
WEBHOOKS_ENABLED=true WEBHOOKS_ENABLED=true
RELEASE_CHECK_URL=https://api.github.com/repos/netbox-community/netbox/releases

View File

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

View File

@ -1,3 +1,15 @@
## To list all permissions, run:
##
## docker-compose run --rm --entrypoint /bin/bash netbox
## $ ./manage.py migrate
## $ ./manage.py shell
## > from django.contrib.auth.models import Permission
## > print('\n'.join([p.codename for p in Permission.objects.all()]))
##
## Permission lists support wildcards. See the examples below.
##
## Examples:
# technical_user: # technical_user:
# api_token: 0123456789technicaluser789abcdef01234567 # must be looooong! # api_token: 0123456789technicaluser789abcdef01234567 # must be looooong!
# reader: # reader:
@ -5,9 +17,7 @@
# writer: # writer:
# password: writer # password: writer
# permissions: # permissions:
# - add_device
# - change_device
# - delete_device # - delete_device
# - add_virtualmachine
# - change_virtualmachine
# - delete_virtualmachine # - delete_virtualmachine
# - add_*
# - change_*

View File

@ -1,34 +1,23 @@
from django.contrib.auth.models import Permission, Group, User
from users.models import Token
from ruamel.yaml import YAML
from pathlib import Path
import sys import sys
file = Path('/opt/netbox/initializers/users.yml') from django.contrib.auth.models import Group, User
if not file.is_file(): from startup_script_utils import load_yaml, set_permissions
from users.models import Token
users = load_yaml('/opt/netbox/initializers/users.yml')
if users is None:
sys.exit() sys.exit()
with file.open('r') as stream: for username, user_details in users.items():
yaml=YAML(typ='safe') if not User.objects.filter(username=username):
users = yaml.load(stream) user = User.objects.create_user(
username = username,
password = user_details.get('password', 0) or User.objects.make_random_password)
if users is not None: print("👤 Created user",username)
for username, user_details in users.items():
if not User.objects.filter(username=username):
user = User.objects.create_user(
username = username,
password = user_details.get('password', 0) or User.objects.make_random_password)
print("👤 Created user ",username) if user_details.get('api_token', 0):
Token.objects.create(user=user, key=user_details['api_token'])
if user_details.get('api_token', 0): yaml_permissions = user_details.get('permissions', [])
Token.objects.create(user=user, key=user_details['api_token']) set_permissions(user.user_permissions, yaml_permissions)
user_permissions = user_details.get('permissions', [])
if user_permissions:
user.user_permissions.clear()
for permission_codename in user_details.get('permissions', []):
for permission in Permission.objects.filter(codename=permission_codename):
user.user_permissions.add(permission)
user.save()

View File

@ -1,32 +1,23 @@
from django.contrib.auth.models import Permission, Group, User
from ruamel.yaml import YAML
from pathlib import Path
import sys import sys
file = Path('/opt/netbox/initializers/groups.yml') from django.contrib.auth.models import Group, User
if not file.is_file(): from startup_script_utils import load_yaml, set_permissions
groups = load_yaml('/opt/netbox/initializers/groups.yml')
if groups is None:
sys.exit() sys.exit()
with file.open('r') as stream: for groupname, group_details in groups.items():
yaml=YAML(typ='safe') group, created = Group.objects.get_or_create(name=groupname)
groups = yaml.load(stream)
if groups is not None: if created:
for groupname, group_details in groups.items(): print("👥 Created group", groupname)
group, created = Group.objects.get_or_create(name=groupname)
if created: for username in group_details.get('users', []):
print("👥 Created group", groupname) user = User.objects.get(username=username)
for username in group_details.get('users', []): if user:
user = User.objects.get(username=username) user.groups.add(group)
if user: yaml_permissions = group_details.get('permissions', [])
user.groups.add(group) set_permissions(group.permissions, yaml_permissions)
group_permissions = group_details.get('permissions', [])
if group_permissions:
group.permissions.clear()
for permission_codename in group_details.get('permissions', []):
for permission in Permission.objects.filter(codename=permission_codename):
group.permissions.add(permission)

View File

@ -1,7 +1,6 @@
from extras.models import CustomField, CustomFieldChoice from extras.models import CustomField, CustomFieldChoice
from ruamel.yaml import YAML from startup_script_utils import load_yaml
from pathlib import Path
import sys import sys
def get_class_for_class_path(class_path): def get_class_for_class_path(class_path):
@ -13,47 +12,43 @@ def get_class_for_class_path(class_path):
clazz = getattr(module, class_name) clazz = getattr(module, class_name)
return ContentType.objects.get_for_model(clazz) return ContentType.objects.get_for_model(clazz)
file = Path('/opt/netbox/initializers/custom_fields.yml') customfields = load_yaml('/opt/netbox/initializers/custom_fields.yml')
if not file.is_file():
if customfields is None:
sys.exit() sys.exit()
with file.open('r') as stream: for cf_name, cf_details in customfields.items():
yaml = YAML(typ='safe') custom_field, created = CustomField.objects.get_or_create(name = cf_name)
customfields = yaml.load(stream)
if customfields is not None: if created:
for cf_name, cf_details in customfields.items(): if cf_details.get('default', 0):
custom_field, created = CustomField.objects.get_or_create(name = cf_name) custom_field.default = cf_details['default']
if created: if cf_details.get('description', 0):
if cf_details.get('default', 0): custom_field.description = cf_details['description']
custom_field.default = cf_details['default']
if cf_details.get('description', 0): if cf_details.get('label', 0):
custom_field.description = cf_details['description'] custom_field.label = cf_details['label']
if cf_details.get('label', 0): for object_type in cf_details.get('on_objects', []):
custom_field.label = cf_details['label'] custom_field.obj_type.add(get_class_for_class_path(object_type))
for object_type in cf_details.get('on_objects', []): if cf_details.get('required', 0):
custom_field.obj_type.add(get_class_for_class_path(object_type)) custom_field.required = cf_details['required']
if cf_details.get('required', 0): if cf_details.get('type', 0):
custom_field.required = cf_details['required'] custom_field.type = cf_details['type']
if cf_details.get('type', 0): if cf_details.get('weight', 0):
custom_field.type = cf_details['type'] custom_field.weight = cf_details['weight']
if cf_details.get('weight', 0): custom_field.save()
custom_field.weight = cf_details['weight']
custom_field.save() for idx, choice_details in enumerate(cf_details.get('choices', [])):
choice, _ = CustomFieldChoice.objects.get_or_create(
field=custom_field,
value=choice_details['value'],
defaults={'weight': idx * 10}
)
for idx, choice_details in enumerate(cf_details.get('choices', [])): print("🔧 Created custom field", cf_name)
choice, _ = CustomFieldChoice.objects.get_or_create(
field=custom_field,
value=choice_details['value'],
defaults={'weight': idx * 10}
)
print("🔧 Created custom field", cf_name)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -3,63 +3,57 @@ from ipam.models import IPAddress
from virtualization.models import Cluster from virtualization.models import Cluster
from tenancy.models import Tenant from tenancy.models import Tenant
from extras.models import CustomField, CustomFieldValue from extras.models import CustomField, CustomFieldValue
from ruamel.yaml import YAML from startup_script_utils import load_yaml
from pathlib import Path
import sys import sys
file = Path('/opt/netbox/initializers/devices.yml') devices = load_yaml('/opt/netbox/initializers/devices.yml')
if not file.is_file():
if devices is None:
sys.exit() sys.exit()
with file.open('r') as stream: required_assocs = {
yaml = YAML(typ='safe') 'device_role': (DeviceRole, 'name'),
devices = yaml.load(stream) 'device_type': (DeviceType, 'model'),
'site': (Site, 'name')
}
required_assocs = { optional_assocs = {
'device_role': (DeviceRole, 'name'), 'tenant': (Tenant, 'name'),
'device_type': (DeviceType, 'model'), 'platform': (Platform, 'name'),
'site': (Site, 'name') 'rack': (Rack, 'name'),
} 'cluster': (Cluster, 'name'),
'primary_ip4': (IPAddress, 'address'),
'primary_ip6': (IPAddress, 'address')
}
optional_assocs = { for params in devices:
'tenant': (Tenant, 'name'), custom_fields = params.pop('custom_fields', None)
'platform': (Platform, 'name'),
'rack': (Rack, 'name'),
'cluster': (Cluster, 'name'),
'primary_ip4': (IPAddress, 'address'),
'primary_ip6': (IPAddress, 'address')
}
if devices is not None: for assoc, details in required_assocs.items():
for params in devices: model, field = details
custom_fields = params.pop('custom_fields', None) query = { field: params.pop(assoc) }
for assoc, details in required_assocs.items(): params[assoc] = model.objects.get(**query)
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) }
for assoc, details in optional_assocs.items(): params[assoc] = model.objects.get(**query)
if assoc in params:
model, field = details
query = { field: params.pop(assoc) }
params[assoc] = model.objects.get(**query) device, created = Device.objects.get_or_create(**params)
device, created = Device.objects.get_or_create(**params) if created:
if custom_fields is not None:
for cf_name, cf_value in custom_fields.items():
custom_field = CustomField.objects.get(name=cf_name)
custom_field_value = CustomFieldValue.objects.create(
field=custom_field,
obj=device,
value=cf_value
)
if created: device.custom_field_values.add(custom_field_value)
if custom_fields is not None:
for cf_name, cf_value in custom_fields.items():
custom_field = CustomField.objects.get(name=cf_name)
custom_field_value = CustomFieldValue.objects.create(
field=custom_field,
obj=device,
value=cf_value
)
device.custom_field_values.add(custom_field_value) print("🖥️ Created device", device.name)
print("🖥️ Created device", device.name)

View File

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

View File

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

View File

@ -1,46 +1,42 @@
from ipam.models import Aggregate, RIR from ipam.models import Aggregate, RIR
from ruamel.yaml import YAML
from extras.models import CustomField, CustomFieldValue from extras.models import CustomField, CustomFieldValue
from netaddr import IPNetwork from netaddr import IPNetwork
from pathlib import Path from startup_script_utils import load_yaml
import sys import sys
file = Path('/opt/netbox/initializers/aggregates.yml') aggregates = load_yaml('/opt/netbox/initializers/aggregates.yml')
if not file.is_file():
if aggregates is None:
sys.exit() sys.exit()
with file.open('r') as stream: required_assocs = {
yaml = YAML(typ='safe') 'rir': (RIR, 'name')
aggregates = yaml.load(stream) }
required_assocs = { for params in aggregates:
'rir': (RIR, 'name') custom_fields = params.pop('custom_fields', None)
} params['prefix'] = IPNetwork(params['prefix'])
if aggregates is not None: for assoc, details in required_assocs.items():
for params in aggregates: model, field = details
custom_fields = params.pop('custom_fields', None) query = { field: params.pop(assoc) }
params['prefix'] = IPNetwork(params['prefix'])
for assoc, details in required_assocs.items(): params[assoc] = model.objects.get(**query)
model, field = details
query = { field: params.pop(assoc) }
params[assoc] = model.objects.get(**query) aggregate, created = Aggregate.objects.get_or_create(**params)
aggregate, created = Aggregate.objects.get_or_create(**params) if created:
if custom_fields is not None:
for cf_name, cf_value in custom_fields.items():
custom_field = CustomField.objects.get(name=cf_name)
custom_field_value = CustomFieldValue.objects.create(
field=custom_field,
obj=aggregate,
value=cf_value
)
if created: aggregate.custom_field_values.add(custom_field_value)
if custom_fields is not None:
for cf_name, cf_value in custom_fields.items():
custom_field = CustomField.objects.get(name=cf_name)
custom_field_value = CustomFieldValue.objects.create(
field=custom_field,
obj=aggregate,
value=cf_value
)
aggregate.custom_field_values.add(custom_field_value) print("🗞️ Created Aggregate", aggregate.prefix)
print("🗞️ Created Aggregate", aggregate.prefix)

View File

@ -1,57 +1,51 @@
from dcim.models import Site from dcim.models import Site
from virtualization.models import Cluster, ClusterType, ClusterGroup from virtualization.models import Cluster, ClusterType, ClusterGroup
from extras.models import CustomField, CustomFieldValue from extras.models import CustomField, CustomFieldValue
from ruamel.yaml import YAML from startup_script_utils import load_yaml
from pathlib import Path
import sys import sys
file = Path('/opt/netbox/initializers/clusters.yml') clusters = load_yaml('/opt/netbox/initializers/clusters.yml')
if not file.is_file():
if clusters is None:
sys.exit() sys.exit()
with file.open('r') as stream: required_assocs = {
yaml = YAML(typ='safe') 'type': (ClusterType, 'name')
clusters = yaml.load(stream) }
required_assocs = { optional_assocs = {
'type': (ClusterType, 'name') 'site': (Site, 'name'),
} 'group': (ClusterGroup, 'name')
}
optional_assocs = { for params in clusters:
'site': (Site, 'name'), custom_fields = params.pop('custom_fields', None)
'group': (ClusterGroup, 'name')
}
if clusters is not None: for assoc, details in required_assocs.items():
for params in clusters: model, field = details
custom_fields = params.pop('custom_fields', None) query = { field: params.pop(assoc) }
for assoc, details in required_assocs.items(): params[assoc] = model.objects.get(**query)
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) }
for assoc, details in optional_assocs.items(): params[assoc] = model.objects.get(**query)
if assoc in params:
model, field = details
query = { field: params.pop(assoc) }
params[assoc] = model.objects.get(**query) cluster, created = Cluster.objects.get_or_create(**params)
cluster, created = Cluster.objects.get_or_create(**params) if created:
if custom_fields is not None:
for cf_name, cf_value in custom_fields.items():
custom_field = CustomField.objects.get(name=cf_name)
custom_field_value = CustomFieldValue.objects.create(
field=custom_field,
obj=cluster,
value=cf_value
)
if created: cluster.custom_field_values.add(custom_field_value)
if custom_fields is not None:
for cf_name, cf_value in custom_fields.items():
custom_field = CustomField.objects.get(name=cf_name)
custom_field_value = CustomFieldValue.objects.create(
field=custom_field,
obj=cluster,
value=cf_value
)
cluster.custom_field_values.add(custom_field_value) print("🗄️ Created cluster", cluster.name)
print("🗄️ Created cluster", cluster.name)

View File

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

View File

@ -1,19 +1,14 @@
from ipam.models import Role from ipam.models import Role
from ruamel.yaml import YAML from startup_script_utils import load_yaml
from pathlib import Path
import sys import sys
file = Path('/opt/netbox/initializers/prefix_vlan_roles.yml') roles = load_yaml('/opt/netbox/initializers/prefix_vlan_roles.yml')
if not file.is_file():
if roles is None:
sys.exit() sys.exit()
with file.open('r') as stream: for params in roles:
yaml = YAML(typ='safe') role, created = Role.objects.get_or_create(**params)
roles = yaml.load(stream)
if roles is not None: if created:
for params in roles: print("⛹️‍ Created Prefix/VLAN Role", role.name)
role, created = Role.objects.get_or_create(**params)
if created:
print("⛹️‍ Created Prefix/VLAN Role", role.name)

View File

@ -1,46 +1,40 @@
from dcim.models import Site from dcim.models import Site
from ipam.models import VLANGroup from ipam.models import VLANGroup
from extras.models import CustomField, CustomFieldValue from extras.models import CustomField, CustomFieldValue
from ruamel.yaml import YAML from startup_script_utils import load_yaml
from pathlib import Path
import sys import sys
file = Path('/opt/netbox/initializers/vlan_groups.yml') vlan_groups = load_yaml('/opt/netbox/initializers/vlan_groups.yml')
if not file.is_file():
if vlan_groups is None:
sys.exit() sys.exit()
with file.open('r') as stream: optional_assocs = {
yaml = YAML(typ='safe') 'site': (Site, 'name')
vlan_groups = yaml.load(stream) }
optional_assocs = { for params in vlan_groups:
'site': (Site, 'name') custom_fields = params.pop('custom_fields', None)
}
if vlan_groups is not None: for assoc, details in optional_assocs.items():
for params in vlan_groups: if assoc in params:
custom_fields = params.pop('custom_fields', None) model, field = details
query = { field: params.pop(assoc) }
for assoc, details in optional_assocs.items(): params[assoc] = model.objects.get(**query)
if assoc in params:
model, field = details
query = { field: params.pop(assoc) }
params[assoc] = model.objects.get(**query) vlan_group, created = VLANGroup.objects.get_or_create(**params)
vlan_group, created = VLANGroup.objects.get_or_create(**params) if created:
if custom_fields is not None:
for cf_name, cf_value in custom_fields.items():
custom_field = CustomField.objects.get(name=cf_name)
custom_field_value = CustomFieldValue.objects.create(
field=custom_field,
obj=vlan_group,
value=cf_value
)
if created: vlan_group.custom_field_values.add(custom_field_value)
if custom_fields is not None:
for cf_name, cf_value in custom_fields.items():
custom_field = CustomField.objects.get(name=cf_name)
custom_field_value = CustomFieldValue.objects.create(
field=custom_field,
obj=vlan_group,
value=cf_value
)
vlan_group.custom_field_values.add(custom_field_value) print("🏘️ Created VLAN Group", vlan_group.name)
print("🏘️ Created VLAN Group", vlan_group.name)

View File

@ -2,50 +2,44 @@ from dcim.models import Site
from ipam.models import VLAN, VLANGroup, Role from ipam.models import VLAN, VLANGroup, Role
from tenancy.models import Tenant, TenantGroup from tenancy.models import Tenant, TenantGroup
from extras.models import CustomField, CustomFieldValue from extras.models import CustomField, CustomFieldValue
from ruamel.yaml import YAML from startup_script_utils import load_yaml
from pathlib import Path
import sys import sys
file = Path('/opt/netbox/initializers/vlans.yml') vlans = load_yaml('/opt/netbox/initializers/vlans.yml')
if not file.is_file():
if vlans is None:
sys.exit() sys.exit()
with file.open('r') as stream: optional_assocs = {
yaml = YAML(typ='safe') 'site': (Site, 'name'),
vlans = yaml.load(stream) 'tenant': (Tenant, 'name'),
'tenant_group': (TenantGroup, 'name'),
'group': (VLANGroup, 'name'),
'role': (Role, 'name')
}
optional_assocs = { for params in vlans:
'site': (Site, 'name'), custom_fields = params.pop('custom_fields', None)
'tenant': (Tenant, 'name'),
'tenant_group': (TenantGroup, 'name'),
'group': (VLANGroup, 'name'),
'role': (Role, 'name')
}
if vlans is not None: for assoc, details in optional_assocs.items():
for params in vlans: if assoc in params:
custom_fields = params.pop('custom_fields', None) model, field = details
query = { field: params.pop(assoc) }
for assoc, details in optional_assocs.items(): params[assoc] = model.objects.get(**query)
if assoc in params:
model, field = details
query = { field: params.pop(assoc) }
params[assoc] = model.objects.get(**query) vlan, created = VLAN.objects.get_or_create(**params)
vlan, created = VLAN.objects.get_or_create(**params) if created:
if custom_fields is not None:
for cf_name, cf_value in custom_fields.items():
custom_field = CustomField.objects.get(name=cf_name)
custom_field_value = CustomFieldValue.objects.create(
field=custom_field,
obj=vlan,
value=cf_value
)
if created: vlan.custom_field_values.add(custom_field_value)
if custom_fields is not None:
for cf_name, cf_value in custom_fields.items():
custom_field = CustomField.objects.get(name=cf_name)
custom_field_value = CustomFieldValue.objects.create(
field=custom_field,
obj=vlan,
value=cf_value
)
vlan.custom_field_values.add(custom_field_value) print("🏠 Created VLAN", vlan.name)
print("🏠 Created VLAN", vlan.name)

View File

@ -2,53 +2,45 @@ from dcim.models import Site
from ipam.models import Prefix, VLAN, Role, VRF from ipam.models import Prefix, VLAN, Role, VRF
from tenancy.models import Tenant, TenantGroup from tenancy.models import Tenant, TenantGroup
from extras.models import CustomField, CustomFieldValue from extras.models import CustomField, CustomFieldValue
from ruamel.yaml import YAML
from netaddr import IPNetwork from netaddr import IPNetwork
from pathlib import Path from startup_script_utils import load_yaml
import sys import sys
file = Path('/opt/netbox/initializers/prefixes.yml') prefixes = load_yaml('/opt/netbox/initializers/prefixes.yml')
if not file.is_file():
if prefixes is None:
sys.exit() sys.exit()
with file.open('r') as stream: optional_assocs = {
yaml = YAML(typ='safe') 'site': (Site, 'name'),
prefixes = yaml.load(stream) 'tenant': (Tenant, 'name'),
'tenant_group': (TenantGroup, 'name'),
'vlan': (VLAN, 'name'),
'role': (Role, 'name'),
'vrf': (VRF, 'name')
}
optional_assocs = { for params in prefixes:
'site': (Site, 'name'), custom_fields = params.pop('custom_fields', None)
'tenant': (Tenant, 'name'), params['prefix'] = IPNetwork(params['prefix'])
'tenant_group': (TenantGroup, 'name'),
'vlan': (VLAN, 'name'),
'role': (Role, 'name'),
'vrf': (VRF, 'name')
}
if prefixes is not None: for assoc, details in optional_assocs.items():
for params in prefixes: if assoc in params:
custom_fields = params.pop('custom_fields', None) model, field = details
params['prefix'] = IPNetwork(params['prefix']) query = { field: params.pop(assoc) }
params[assoc] = model.objects.get(**query)
for assoc, details in optional_assocs.items(): prefix, created = Prefix.objects.get_or_create(**params)
if assoc in params:
model, field = details
query = { field: params.pop(assoc) }
params[assoc] = model.objects.get(**query) if created:
if custom_fields is not None:
for cf_name, cf_value in custom_fields.items():
custom_field = CustomField.objects.get(name=cf_name)
custom_field_value = CustomFieldValue.objects.create(
field=custom_field,
obj=prefix,
value=cf_value
)
prefix.custom_field_values.add(custom_field_value)
prefix, created = Prefix.objects.get_or_create(**params) print("📌 Created Prefix", prefix.prefix)
if created:
if custom_fields is not None:
for cf_name, cf_value in custom_fields.items():
custom_field = CustomField.objects.get(name=cf_name)
custom_field_value = CustomFieldValue.objects.create(
field=custom_field,
obj=prefix,
value=cf_value
)
prefix.custom_field_values.add(custom_field_value)
print("📌 Created Prefix", prefix.prefix)

View File

@ -2,58 +2,52 @@ from dcim.models import Site, Platform, DeviceRole
from virtualization.models import Cluster, VirtualMachine from virtualization.models import Cluster, VirtualMachine
from tenancy.models import Tenant from tenancy.models import Tenant
from extras.models import CustomField, CustomFieldValue from extras.models import CustomField, CustomFieldValue
from ruamel.yaml import YAML from startup_script_utils import load_yaml
from pathlib import Path
import sys import sys
file = Path('/opt/netbox/initializers/virtual_machines.yml') virtual_machines = load_yaml('/opt/netbox/initializers/virtual_machines.yml')
if not file.is_file():
if virtual_machines is None:
sys.exit() sys.exit()
with file.open('r') as stream: required_assocs = {
yaml = YAML(typ='safe') 'cluster': (Cluster, 'name')
virtual_machines = yaml.load(stream) }
required_assocs = { optional_assocs = {
'cluster': (Cluster, 'name') 'tenant': (Tenant, 'name'),
} 'platform': (Platform, 'name'),
'role': (DeviceRole, 'name')
}
optional_assocs = { for params in virtual_machines:
'tenant': (Tenant, 'name'), custom_fields = params.pop('custom_fields', None)
'platform': (Platform, 'name'),
'role': (DeviceRole, 'name')
}
if virtual_machines is not None: for assoc, details in required_assocs.items():
for params in virtual_machines: model, field = details
custom_fields = params.pop('custom_fields', None) query = { field: params.pop(assoc) }
for assoc, details in required_assocs.items(): params[assoc] = model.objects.get(**query)
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) }
for assoc, details in optional_assocs.items(): params[assoc] = model.objects.get(**query)
if assoc in params:
model, field = details
query = { field: params.pop(assoc) }
params[assoc] = model.objects.get(**query) virtual_machine, created = VirtualMachine.objects.get_or_create(**params)
virtual_machine, created = VirtualMachine.objects.get_or_create(**params) if created:
if custom_fields is not None:
for cf_name, cf_value in custom_fields.items():
custom_field = CustomField.objects.get(name=cf_name)
custom_field_value = CustomFieldValue.objects.create(
field=custom_field,
obj=virtual_machine,
value=cf_value
)
if created: virtual_machine.custom_field_values.add(custom_field_value)
if custom_fields is not None:
for cf_name, cf_value in custom_fields.items():
custom_field = CustomField.objects.get(name=cf_name)
custom_field_value = CustomFieldValue.objects.create(
field=custom_field,
obj=virtual_machine,
value=cf_value
)
virtual_machine.custom_field_values.add(custom_field_value) print("🖥️ Created virtual machine", virtual_machine.name)
print("🖥️ Created virtual machine", virtual_machine.name)

View File

@ -1,45 +1,39 @@
from dcim.models import Interface from dcim.models import Interface
from virtualization.models import VirtualMachine from virtualization.models import VirtualMachine
from extras.models import CustomField, CustomFieldValue from extras.models import CustomField, CustomFieldValue
from ruamel.yaml import YAML from startup_script_utils import load_yaml
from pathlib import Path
import sys import sys
file = Path('/opt/netbox/initializers/virtualization_interfaces.yml') interfaces = load_yaml('/opt/netbox/initializers/virtualization_interfaces.yml')
if not file.is_file():
if interfaces is None:
sys.exit() sys.exit()
with file.open('r') as stream: required_assocs = {
yaml = YAML(typ='safe') 'virtual_machine': (VirtualMachine, 'name')
interfaces = yaml.load(stream) }
required_assocs = { for params in interfaces:
'virtual_machine': (VirtualMachine, 'name') custom_fields = params.pop('custom_fields', None)
}
if interfaces is not None: for assoc, details in required_assocs.items():
for params in interfaces: model, field = details
custom_fields = params.pop('custom_fields', None) query = { field: params.pop(assoc) }
for assoc, details in required_assocs.items(): params[assoc] = model.objects.get(**query)
model, field = details
query = { field: params.pop(assoc) }
params[assoc] = model.objects.get(**query) interface, created = Interface.objects.get_or_create(**params)
interface, created = Interface.objects.get_or_create(**params) if created:
if custom_fields is not None:
for cf_name, cf_value in custom_fields.items():
custom_field = CustomField.objects.get(name=cf_name)
custom_field_value = CustomFieldValue.objects.create(
field=custom_field,
obj=interface,
value=cf_value
)
if created: interface.custom_field_values.add(custom_field_value)
if custom_fields is not None:
for cf_name, cf_value in custom_fields.items():
custom_field = CustomField.objects.get(name=cf_name)
custom_field_value = CustomFieldValue.objects.create(
field=custom_field,
obj=interface,
value=cf_value
)
interface.custom_field_values.add(custom_field_value) print("🧷 Created interface", interface.name, interface.virtual_machine.name)
print("🧷 Created interface", interface.name, interface.virtual_machine.name)

View File

@ -1,44 +1,38 @@
from dcim.models import Interface, Device from dcim.models import Interface, Device
from extras.models import CustomField, CustomFieldValue from extras.models import CustomField, CustomFieldValue
from ruamel.yaml import YAML from startup_script_utils import load_yaml
from pathlib import Path
import sys import sys
file = Path('/opt/netbox/initializers/dcim_interfaces.yml') interfaces= load_yaml('/opt/netbox/initializers/dcim_interfaces.yml')
if not file.is_file():
if interfaces is None:
sys.exit() sys.exit()
with file.open('r') as stream: required_assocs = {
yaml = YAML(typ='safe') 'device': (Device, 'name')
interfaces = yaml.load(stream) }
required_assocs = { for params in interfaces:
'device': (Device, 'name') custom_fields = params.pop('custom_fields', None)
}
if interfaces is not None: for assoc, details in required_assocs.items():
for params in interfaces: model, field = details
custom_fields = params.pop('custom_fields', None) query = { field: params.pop(assoc) }
for assoc, details in required_assocs.items(): params[assoc] = model.objects.get(**query)
model, field = details
query = { field: params.pop(assoc) }
params[assoc] = model.objects.get(**query) interface, created = Interface.objects.get_or_create(**params)
interface, created = Interface.objects.get_or_create(**params) if created:
if custom_fields is not None:
for cf_name, cf_value in custom_fields.items():
custom_field = CustomField.objects.get(name=cf_name)
custom_field_value = CustomFieldValue.objects.create(
field=custom_field,
obj=interface,
value=cf_value
)
if created: interface.custom_field_values.add(custom_field_value)
if custom_fields is not None:
for cf_name, cf_value in custom_fields.items():
custom_field = CustomField.objects.get(name=cf_name)
custom_field_value = CustomFieldValue.objects.create(
field=custom_field,
obj=interface,
value=cf_value
)
interface.custom_field_values.add(custom_field_value) print("🧷 Created interface", interface.name, interface.device.name)
print("🧷 Created interface", interface.name, interface.device.name)

View File

@ -3,63 +3,58 @@ from dcim.models import Device, Interface
from virtualization.models import VirtualMachine from virtualization.models import VirtualMachine
from tenancy.models import Tenant from tenancy.models import Tenant
from extras.models import CustomField, CustomFieldValue from extras.models import CustomField, CustomFieldValue
from ruamel.yaml import YAML
from netaddr import IPNetwork from netaddr import IPNetwork
from pathlib import Path from startup_script_utils import load_yaml
import sys import sys
file = Path('/opt/netbox/initializers/ip_addresses.yml') ip_addresses = load_yaml('/opt/netbox/initializers/ip_addresses.yml')
if not file.is_file():
if ip_addresses is None:
sys.exit() sys.exit()
with file.open('r') as stream: optional_assocs = {
yaml = YAML(typ='safe') 'tenant': (Tenant, 'name'),
ip_addresses = yaml.load(stream) 'vrf': (VRF, 'name'),
'interface': (Interface, 'name')
}
optional_assocs = { for params in ip_addresses:
'tenant': (Tenant, 'name'), vm = params.pop('virtual_machine', None)
'vrf': (VRF, 'name'), device = params.pop('device', None)
'interface': (Interface, 'name') custom_fields = params.pop('custom_fields', None)
} params['address'] = IPNetwork(params['address'])
if ip_addresses is not None: if vm and device:
for params in ip_addresses: print("IP Address can only specify one of the following: virtual_machine or device.")
vm = params.pop('virtual_machine', None) sys.exit()
device = params.pop('device', None)
custom_fields = params.pop('custom_fields', None)
params['address'] = IPNetwork(params['address'])
if vm and device: for assoc, details in optional_assocs.items():
print("IP Address can only specify one of the following: virtual_machine or device.") if assoc in params:
sys.exit() model, field = details
if assoc == 'interface':
if vm:
vm_id = VirtualMachine.objects.get(name=vm).id
query = { field: params.pop(assoc), "virtual_machine_id": vm_id }
elif device:
dev_id = Device.objects.get(name=device).id
query = { field: params.pop(assoc), "device_id": dev_id }
else:
query = { field: params.pop(assoc) }
params[assoc] = model.objects.get(**query)
for assoc, details in optional_assocs.items(): ip_address, created = IPAddress.objects.get_or_create(**params)
if assoc in params:
model, field = details
if assoc == 'interface':
if vm:
vm_id = VirtualMachine.objects.get(name=vm).id
query = { field: params.pop(assoc), "virtual_machine_id": vm_id }
elif device:
dev_id = Device.objects.get(name=device).id
query = { field: params.pop(assoc), "device_id": dev_id }
else:
query = { field: params.pop(assoc) }
params[assoc] = model.objects.get(**query)
ip_address, created = IPAddress.objects.get_or_create(**params) if created:
if custom_fields is not None:
for cf_name, cf_value in custom_fields.items():
custom_field = CustomField.objects.get(name=cf_name)
custom_field_value = CustomFieldValue.objects.create(
field=custom_field,
obj=ip_address,
value=cf_value
)
if created: ip_address.custom_field_values.add(custom_field_value)
if custom_fields is not None:
for cf_name, cf_value in custom_fields.items():
custom_field = CustomField.objects.get(name=cf_name)
custom_field_value = CustomFieldValue.objects.create(
field=custom_field,
obj=ip_address,
value=cf_value
)
ip_address.custom_field_values.add(custom_field_value) print("🧬 Created IP Address", ip_address.address)
print("🧬 Created IP Address", ip_address.address)

View File

@ -7,12 +7,12 @@ from os.path import dirname, abspath
this_dir = dirname(abspath(__file__)) this_dir = dirname(abspath(__file__))
def filename(f): def filename(f):
return f.name return f.name
with scandir(dirname(abspath(__file__))) as it: with scandir(dirname(abspath(__file__))) as it:
for f in sorted(it, key = filename): for f in sorted(it, key = filename):
if f.name.startswith('__') or not f.is_file(): if f.name.startswith('__') or not f.is_file():
continue continue
print(f"Running {f.path}") print(f"Running {f.path}")
runpy.run_path(f.path) runpy.run_path(f.path)

View File

@ -0,0 +1,2 @@
from .load_yaml import load_yaml
from .permissions import set_permissions

View File

@ -0,0 +1,10 @@
from ruamel.yaml import YAML
from pathlib import Path
def load_yaml(yaml_file: str):
yf = Path(yaml_file)
if not yf.is_file():
return None
with yf.open("r") as stream:
yaml = YAML(typ="safe")
return yaml.load(stream)

View File

@ -0,0 +1,18 @@
from django.contrib.auth.models import Permission
def set_permissions(subject, permission_filters):
if subject is None or permission_filters is None:
return
subject.clear()
for permission_filter in permission_filters:
if "*" in permission_filter:
permission_filter_regex = "^" + permission_filter.replace("*", ".*") + "$"
permissions = Permission.objects.filter(codename__iregex=permission_filter_regex)
print(" ⚿ Granting", permissions.count(), "permissions matching '" + permission_filter + "'")
else:
permissions = Permission.objects.filter(codename=permission_filter)
print(" ⚿ Granting permission", permission_filter)
for permission in permissions:
subject.add(permission)