commit
aa4d630a0f
|
@ -19,8 +19,7 @@ jobs:
|
||||||
- ./build.sh develop
|
- ./build.sh develop
|
||||||
docker_from:
|
docker_from:
|
||||||
- '' # use the default of the build script
|
- '' # use the default of the build script
|
||||||
- python:3.8-alpine
|
# - python:3.10-rc-alpine # disable until dependencies work
|
||||||
- python:3.9-alpine
|
|
||||||
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
|
||||||
|
|
|
@ -50,3 +50,34 @@ jobs:
|
||||||
name: Logout of the Docker Registry
|
name: Logout of the Docker Registry
|
||||||
run: docker logout "${DOCKER_REGISTRY}"
|
run: docker logout "${DOCKER_REGISTRY}"
|
||||||
if: steps.docker-build.outputs.skipped != 'true'
|
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'
|
||||||
|
|
13
README.md
13
README.md
|
@ -10,7 +10,7 @@
|
||||||
[![GitHub license](https://img.shields.io/github/license/netbox-community/netbox-docker)][netbox-docker-license]
|
[![GitHub license](https://img.shields.io/github/license/netbox-community/netbox-docker)][netbox-docker-license]
|
||||||
|
|
||||||
[The Github repository](netbox-docker-github) houses the components needed to build Netbox as a Docker container.
|
[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] and [Quay.io][netbox-quayio] once a day.
|
||||||
|
|
||||||
Do you have any questions?
|
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.
|
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.
|
||||||
|
@ -18,11 +18,12 @@ Before opening an issue on Github, please join the [Network To Code][ntc-slack]
|
||||||
[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
|
||||||
[netbox-docker-microbadger]: https://microbadger.com/images/netboxcommunity/netbox
|
[netbox-docker-microbadger]: https://microbadger.com/images/netboxcommunity/netbox
|
||||||
[netbox-dockerhub]: https://hub.docker.com/r/netboxcommunity/netbox/tags/
|
[netbox-dockerhub]: https://hub.docker.com/r/netboxcommunity/netbox/
|
||||||
[netbox-docker-github]: https://github.com/netbox-community/netbox-docker/
|
[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/release/LICENSE
|
[netbox-docker-license]: https://github.com/netbox-community/netbox-docker/blob/release/LICENSE
|
||||||
|
[netbox-quayio]: https://quay.io/repository/netboxcommunity/netbox
|
||||||
|
|
||||||
## Docker Tags
|
## Docker Tags
|
||||||
|
|
||||||
|
@ -85,11 +86,13 @@ It covers advanced topics such as using files for secrets, deployment to Kuberne
|
||||||
|
|
||||||
## Getting Help
|
## Getting Help
|
||||||
|
|
||||||
Please join [our Slack channel `#netbox-docker`][netbox-docker-slack] on the [Network To Code Slack][ntc-slack].
|
Feel free to ask questions in our [Github Community][netbox-community] or 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.
|
which is free to use and where there are almost always people online that can help you in the Slack channel.
|
||||||
|
|
||||||
If you need help with using Netbox or developing for it or against it's API you may find the `#netbox` channel on the same Slack instance very helpful.
|
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.
|
||||||
|
|
||||||
|
[netbox-community]: https://github.com/netbox-community/netbox-docker/discussions
|
||||||
|
|
||||||
## 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:
|
||||||
|
@ -104,7 +107,7 @@ To check the version installed on your system run `docker --version` and `docker
|
||||||
The `docker-compose.yml` file is prepared to run a specific version of Netbox, instead of `latest`.
|
The `docker-compose.yml` file is prepared to run a specific version of Netbox, instead of `latest`.
|
||||||
To use this feature, set and export the environment-variable `VERSION` before launching `docker-compose`, as shown below.
|
To use this feature, set and export 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] or [Quay.io][netbox-quayio].
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
export VERSION=v2.7.1
|
export VERSION=v2.7.1
|
||||||
|
|
4
build.sh
4
build.sh
|
@ -49,7 +49,7 @@ if [ "${1}x" == "x" ] || [ "${1}" == "--help" ] || [ "${1}" == "-h" ]; then
|
||||||
echo " DOCKERFILE The name of Dockerfile to use."
|
echo " DOCKERFILE The name of Dockerfile to use."
|
||||||
echo " Default: Dockerfile"
|
echo " Default: Dockerfile"
|
||||||
echo " DOCKER_FROM The base image to use."
|
echo " DOCKER_FROM The base image to use."
|
||||||
echo " Default: 'python:3.8-alpine'"
|
echo " Default: 'python:3.9-alpine'"
|
||||||
echo " DOCKER_TARGET A specific target to build."
|
echo " DOCKER_TARGET A specific target to build."
|
||||||
echo " It's currently not possible to pass multiple targets."
|
echo " It's currently not possible to pass multiple targets."
|
||||||
echo " Default: main ldap"
|
echo " Default: main ldap"
|
||||||
|
@ -157,7 +157,7 @@ fi
|
||||||
# Determining the value for DOCKER_FROM
|
# Determining the value for DOCKER_FROM
|
||||||
###
|
###
|
||||||
if [ -z "$DOCKER_FROM" ]; then
|
if [ -z "$DOCKER_FROM" ]; then
|
||||||
DOCKER_FROM="python:3.8-alpine"
|
DOCKER_FROM="python:3.9-alpine"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
###
|
###
|
||||||
|
|
|
@ -157,7 +157,7 @@ LOGIN_REQUIRED = environ.get('LOGIN_REQUIRED', 'False').lower() == 'true'
|
||||||
|
|
||||||
# The length of time (in seconds) for which a user will remain logged into the web UI before being prompted to
|
# 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])
|
# re-authenticate. (Default: 1209600 [14 days])
|
||||||
LOGIN_TIMEOUT = environ.get('LOGIN_TIMEOUT', None)
|
LOGIN_TIMEOUT = int(environ.get('LOGIN_TIMEOUT', 1209600))
|
||||||
|
|
||||||
# Setting this to True will display a "maintenance mode" banner at the top of every page.
|
# 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'
|
MAINTENANCE_MODE = environ.get('MAINTENANCE_MODE', 'False').lower() == 'true'
|
||||||
|
@ -233,7 +233,7 @@ SCRIPTS_ROOT = environ.get('SCRIPTS_ROOT', '/etc/netbox/scripts')
|
||||||
# By default, NetBox will store session data in the database. Alternatively, a file path can be specified here to use
|
# 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
|
# 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.
|
# database access.) Note that the user as which NetBox runs must have read and write permissions to this path.
|
||||||
SESSION_FILE_PATH = environ.get('REPORTS_ROOT', None)
|
SESSION_FILE_PATH = environ.get('SESSIONS_ROOT', None)
|
||||||
|
|
||||||
# Time zone (default: UTC)
|
# Time zone (default: UTC)
|
||||||
TIME_ZONE = environ.get('TIME_ZONE', 'UTC')
|
TIME_ZONE = environ.get('TIME_ZONE', 'UTC')
|
||||||
|
|
|
@ -60,14 +60,17 @@ AUTH_LDAP_GROUP_SEARCH = LDAPSearch(AUTH_LDAP_GROUP_SEARCH_BASEDN, ldap.SCOPE_SU
|
||||||
AUTH_LDAP_GROUP_TYPE = _import_group_type(environ.get('AUTH_LDAP_GROUP_TYPE', 'GroupOfNamesType'))
|
AUTH_LDAP_GROUP_TYPE = _import_group_type(environ.get('AUTH_LDAP_GROUP_TYPE', 'GroupOfNamesType'))
|
||||||
|
|
||||||
# Define a group required to login.
|
# Define a group required to login.
|
||||||
AUTH_LDAP_REQUIRE_GROUP = environ.get('AUTH_LDAP_REQUIRE_GROUP_DN', '')
|
AUTH_LDAP_REQUIRE_GROUP = environ.get('AUTH_LDAP_REQUIRE_GROUP_DN')
|
||||||
|
|
||||||
# Define special user types using groups. Exercise great caution when assigning superuser status.
|
# Define special user types using groups. Exercise great caution when assigning superuser status.
|
||||||
AUTH_LDAP_USER_FLAGS_BY_GROUP = {
|
AUTH_LDAP_USER_FLAGS_BY_GROUP = {}
|
||||||
|
|
||||||
|
if AUTH_LDAP_REQUIRE_GROUP is not None:
|
||||||
|
AUTH_LDAP_USER_FLAGS_BY_GROUP = {
|
||||||
"is_active": environ.get('AUTH_LDAP_REQUIRE_GROUP_DN', ''),
|
"is_active": environ.get('AUTH_LDAP_REQUIRE_GROUP_DN', ''),
|
||||||
"is_staff": environ.get('AUTH_LDAP_IS_ADMIN_DN', ''),
|
"is_staff": environ.get('AUTH_LDAP_IS_ADMIN_DN', ''),
|
||||||
"is_superuser": environ.get('AUTH_LDAP_IS_SUPERUSER_DN', '')
|
"is_superuser": environ.get('AUTH_LDAP_IS_SUPERUSER_DN', '')
|
||||||
}
|
}
|
||||||
|
|
||||||
# For more granular permissions, we can map LDAP groups to Django groups.
|
# For more granular permissions, we can map LDAP groups to Django groups.
|
||||||
AUTH_LDAP_FIND_GROUP_PERMS = environ.get('AUTH_LDAP_FIND_GROUP_PERMS', 'True').lower() == 'true'
|
AUTH_LDAP_FIND_GROUP_PERMS = environ.get('AUTH_LDAP_FIND_GROUP_PERMS', 'True').lower() == 'true'
|
||||||
|
|
|
@ -43,20 +43,16 @@
|
||||||
# required: false
|
# required: false
|
||||||
# filter_logic: exact
|
# filter_logic: exact
|
||||||
# weight: 30
|
# weight: 30
|
||||||
|
# default: First Item
|
||||||
# on_objects:
|
# on_objects:
|
||||||
# - dcim.models.Device
|
# - dcim.models.Device
|
||||||
# choices:
|
# choices:
|
||||||
# - value: First Item
|
# - First Item
|
||||||
# weight: 10
|
# - Second Item
|
||||||
# - value: Second Item
|
# - Third Item
|
||||||
# weight: 20
|
# - Fifth Item
|
||||||
# - value: Third Item
|
# - Fourth Item
|
||||||
# weight: 30
|
# select_field_legacy_format:
|
||||||
# - value: Fifth Item
|
|
||||||
# weight: 50
|
|
||||||
# - value: Fourth Item
|
|
||||||
# weight: 40
|
|
||||||
# select_field_auto_weight:
|
|
||||||
# type: select
|
# type: select
|
||||||
# label: Choose between items
|
# label: Choose between items
|
||||||
# required: false
|
# required: false
|
||||||
|
@ -65,9 +61,9 @@
|
||||||
# on_objects:
|
# on_objects:
|
||||||
# - dcim.models.Device
|
# - dcim.models.Device
|
||||||
# choices:
|
# choices:
|
||||||
# - value: A
|
# - value: A # this is the deprecated format.
|
||||||
# - value: B
|
# - value: B # we only use it for the tests.
|
||||||
# - value: C
|
# - value: C # please see above for the new format.
|
||||||
# - value: "D like deprecated"
|
# - value: "D like deprecated"
|
||||||
# weight: 999
|
# weight: 999
|
||||||
# - value: E
|
# - value: E
|
||||||
|
@ -76,7 +72,7 @@
|
||||||
# label: Yes Or No?
|
# label: Yes Or No?
|
||||||
# required: true
|
# required: true
|
||||||
# filter_logic: loose
|
# filter_logic: loose
|
||||||
# default: "false" # important: but "false" in quotes!
|
# default: "false" # important: put "false" in quotes!
|
||||||
# weight: 90
|
# weight: 90
|
||||||
# on_objects:
|
# on_objects:
|
||||||
# - dcim.models.Device
|
# - dcim.models.Device
|
||||||
|
|
|
@ -2,22 +2,22 @@
|
||||||
# manufacturer: Manufacturer 1
|
# manufacturer: Manufacturer 1
|
||||||
# slug: model-1
|
# slug: model-1
|
||||||
# u_height: 2
|
# u_height: 2
|
||||||
# custom_fields:
|
# custom_field_data:
|
||||||
# text_field: Description
|
# text_field: Description
|
||||||
# - model: Model 2
|
# - model: Model 2
|
||||||
# manufacturer: Manufacturer 1
|
# manufacturer: Manufacturer 1
|
||||||
# slug: model-2
|
# slug: model-2
|
||||||
# custom_fields:
|
# custom_field_data:
|
||||||
# text_field: Description
|
# text_field: Description
|
||||||
# - model: Model 3
|
# - model: Model 3
|
||||||
# manufacturer: Manufacturer 1
|
# manufacturer: Manufacturer 1
|
||||||
# slug: model-3
|
# slug: model-3
|
||||||
# is_full_depth: false
|
# is_full_depth: false
|
||||||
# u_height: 0
|
# u_height: 0
|
||||||
# custom_fields:
|
# custom_field_data:
|
||||||
# text_field: Description
|
# text_field: Description
|
||||||
# - model: Other
|
# - model: Other
|
||||||
# manufacturer: No Name
|
# manufacturer: No Name
|
||||||
# slug: other
|
# slug: other
|
||||||
# custom_fields:
|
# custom_field_data:
|
||||||
# text_field: Description
|
# text_field: Description
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
# rack: rack-01
|
# rack: rack-01
|
||||||
# face: front
|
# face: front
|
||||||
# position: 1
|
# position: 1
|
||||||
# custom_fields:
|
# custom_field_data:
|
||||||
# text_field: Description
|
# text_field: Description
|
||||||
# - name: server02
|
# - name: server02
|
||||||
# device_role: server
|
# device_role: server
|
||||||
|
@ -31,7 +31,7 @@
|
||||||
# position: 2
|
# position: 2
|
||||||
# primary_ip4: 10.1.1.2/24
|
# primary_ip4: 10.1.1.2/24
|
||||||
# primary_ip6: 2001:db8:a000:1::2/64
|
# primary_ip6: 2001:db8:a000:1::2/64
|
||||||
# custom_fields:
|
# custom_field_data:
|
||||||
# text_field: Description
|
# text_field: Description
|
||||||
# - name: server03
|
# - name: server03
|
||||||
# device_role: server
|
# device_role: server
|
||||||
|
@ -40,5 +40,5 @@
|
||||||
# rack: rack-03
|
# rack: rack-03
|
||||||
# face: front
|
# face: front
|
||||||
# position: 3
|
# position: 3
|
||||||
# custom_fields:
|
# custom_field_data:
|
||||||
# text_field: Description
|
# text_field: Description
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
# type: 4-post-cabinet
|
# type: 4-post-cabinet
|
||||||
# width: 19
|
# width: 19
|
||||||
# u_height: 47
|
# u_height: 47
|
||||||
# custom_fields:
|
# custom_field_data:
|
||||||
# text_field: Description
|
# text_field: Description
|
||||||
# - site: AMS 2
|
# - site: AMS 2
|
||||||
# name: rack-02
|
# name: rack-02
|
||||||
|
@ -28,7 +28,7 @@
|
||||||
# type: 4-post-cabinet
|
# type: 4-post-cabinet
|
||||||
# width: 19
|
# width: 19
|
||||||
# u_height: 47
|
# u_height: 47
|
||||||
# custom_fields:
|
# custom_field_data:
|
||||||
# text_field: Description
|
# text_field: Description
|
||||||
# - site: SING 1
|
# - site: SING 1
|
||||||
# name: rack-03
|
# name: rack-03
|
||||||
|
@ -37,5 +37,5 @@
|
||||||
# type: 4-post-cabinet
|
# type: 4-post-cabinet
|
||||||
# width: 19
|
# width: 19
|
||||||
# u_height: 47
|
# u_height: 47
|
||||||
# custom_fields:
|
# custom_field_data:
|
||||||
# text_field: Description
|
# text_field: Description
|
||||||
|
|
|
@ -4,29 +4,29 @@
|
||||||
# status: active
|
# status: active
|
||||||
# facility: Amsterdam 1
|
# facility: Amsterdam 1
|
||||||
# asn: 12345
|
# asn: 12345
|
||||||
# custom_fields:
|
# custom_field_data:
|
||||||
# text_field: Description
|
# text_field: Description for AMS1
|
||||||
# - name: AMS 2
|
# - name: AMS 2
|
||||||
# slug: ams2
|
# slug: ams2
|
||||||
# region: Downtown
|
# region: Downtown
|
||||||
# status: active
|
# status: active
|
||||||
# facility: Amsterdam 2
|
# facility: Amsterdam 2
|
||||||
# asn: 54321
|
# asn: 54321
|
||||||
# custom_fields:
|
# custom_field_data:
|
||||||
# text_field: Description
|
# text_field: Description for AMS2
|
||||||
# - name: AMS 3
|
# - name: AMS 3
|
||||||
# slug: ams3
|
# slug: ams3
|
||||||
# region: Suburbs
|
# region: Suburbs
|
||||||
# status: active
|
# status: active
|
||||||
# facility: Amsterdam 3
|
# facility: Amsterdam 3
|
||||||
# asn: 67890
|
# asn: 67890
|
||||||
# custom_fields:
|
# custom_field_data:
|
||||||
# text_field: Description
|
# text_field: Description for AMS3
|
||||||
# - name: SING 1
|
# - name: SING 1
|
||||||
# slug: sing1
|
# slug: sing1
|
||||||
# region: Singapore
|
# region: Singapore
|
||||||
# status: active
|
# status: active
|
||||||
# facility: Singapore 1
|
# facility: Singapore 1
|
||||||
# asn: 09876
|
# asn: 09876
|
||||||
# custom_fields:
|
# custom_field_data:
|
||||||
# text_field: Description
|
# text_field: Description for SING1
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from django.contrib.auth.models import Group, User
|
from django.contrib.auth.models import User
|
||||||
from startup_script_utils import load_yaml, set_permissions
|
from startup_script_utils import load_yaml, set_permissions
|
||||||
from users.models import Token
|
from users.models import Token
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
from extras.models import CustomField, CustomFieldChoice
|
|
||||||
|
|
||||||
from startup_script_utils import load_yaml
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
from extras.models import CustomField
|
||||||
|
from startup_script_utils import load_yaml
|
||||||
|
|
||||||
def get_class_for_class_path(class_path):
|
def get_class_for_class_path(class_path):
|
||||||
import importlib
|
import importlib
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
|
@ -21,34 +21,38 @@ for cf_name, cf_details in customfields.items():
|
||||||
custom_field, created = CustomField.objects.get_or_create(name = cf_name)
|
custom_field, created = CustomField.objects.get_or_create(name = cf_name)
|
||||||
|
|
||||||
if created:
|
if created:
|
||||||
if cf_details.get('default', 0):
|
if cf_details.get('default', False):
|
||||||
custom_field.default = cf_details['default']
|
custom_field.default = cf_details['default']
|
||||||
|
|
||||||
if cf_details.get('description', 0):
|
if cf_details.get('description', False):
|
||||||
custom_field.description = cf_details['description']
|
custom_field.description = cf_details['description']
|
||||||
|
|
||||||
if cf_details.get('label', 0):
|
if cf_details.get('label', False):
|
||||||
custom_field.label = cf_details['label']
|
custom_field.label = cf_details['label']
|
||||||
|
|
||||||
for object_type in cf_details.get('on_objects', []):
|
for object_type in cf_details.get('on_objects', []):
|
||||||
custom_field.obj_type.add(get_class_for_class_path(object_type))
|
custom_field.content_types.add(get_class_for_class_path(object_type))
|
||||||
|
|
||||||
if cf_details.get('required', 0):
|
if cf_details.get('required', False):
|
||||||
custom_field.required = cf_details['required']
|
custom_field.required = cf_details['required']
|
||||||
|
|
||||||
if cf_details.get('type', 0):
|
if cf_details.get('type', False):
|
||||||
custom_field.type = cf_details['type']
|
custom_field.type = cf_details['type']
|
||||||
|
|
||||||
if cf_details.get('weight', 0):
|
if cf_details.get('weight', -1) >= 0:
|
||||||
custom_field.weight = cf_details['weight']
|
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()
|
custom_field.save()
|
||||||
|
|
||||||
for idx, choice_details in enumerate(cf_details.get('choices', [])):
|
|
||||||
choice, _ = CustomFieldChoice.objects.get_or_create(
|
|
||||||
field=custom_field,
|
|
||||||
value=choice_details['value'],
|
|
||||||
defaults={'weight': idx * 10}
|
|
||||||
)
|
|
||||||
|
|
||||||
print("🔧 Created custom field", cf_name)
|
print("🔧 Created custom field", cf_name)
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
from dcim.models import Region, Site
|
|
||||||
from extras.models import CustomField, CustomFieldValue
|
|
||||||
from tenancy.models import Tenant
|
|
||||||
from startup_script_utils import load_yaml
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
from dcim.models import Region, Site
|
||||||
|
from startup_script_utils import *
|
||||||
|
from tenancy.models import Tenant
|
||||||
|
|
||||||
sites = load_yaml('/opt/netbox/initializers/sites.yml')
|
sites = load_yaml('/opt/netbox/initializers/sites.yml')
|
||||||
|
|
||||||
if sites is None:
|
if sites is None:
|
||||||
|
@ -15,7 +15,7 @@ optional_assocs = {
|
||||||
}
|
}
|
||||||
|
|
||||||
for params in sites:
|
for params in sites:
|
||||||
custom_fields = params.pop('custom_fields', None)
|
custom_field_data = pop_custom_fields(params)
|
||||||
|
|
||||||
for assoc, details in optional_assocs.items():
|
for assoc, details in optional_assocs.items():
|
||||||
if assoc in params:
|
if assoc in params:
|
||||||
|
@ -27,15 +27,6 @@ for params in sites:
|
||||||
site, created = Site.objects.get_or_create(**params)
|
site, created = Site.objects.get_or_create(**params)
|
||||||
|
|
||||||
if created:
|
if created:
|
||||||
if custom_fields is not None:
|
set_custom_fields_values(site, custom_field_data)
|
||||||
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)
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
from dcim.models import DeviceType, Manufacturer, Region
|
|
||||||
from tenancy.models import Tenant
|
|
||||||
from extras.models import CustomField, CustomFieldValue
|
|
||||||
from startup_script_utils import load_yaml
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
from dcim.models import DeviceType, Manufacturer, Region
|
||||||
|
from startup_script_utils import *
|
||||||
|
from tenancy.models import Tenant
|
||||||
|
|
||||||
device_types = load_yaml('/opt/netbox/initializers/device_types.yml')
|
device_types = load_yaml('/opt/netbox/initializers/device_types.yml')
|
||||||
|
|
||||||
if device_types is None:
|
if device_types is None:
|
||||||
|
@ -19,7 +19,7 @@ optional_assocs = {
|
||||||
}
|
}
|
||||||
|
|
||||||
for params in device_types:
|
for params in device_types:
|
||||||
custom_fields = params.pop('custom_fields', None)
|
custom_field_data = pop_custom_fields(params)
|
||||||
|
|
||||||
for assoc, details in required_assocs.items():
|
for assoc, details in required_assocs.items():
|
||||||
model, field = details
|
model, field = details
|
||||||
|
@ -37,15 +37,6 @@ for params in device_types:
|
||||||
device_type, created = DeviceType.objects.get_or_create(**params)
|
device_type, created = DeviceType.objects.get_or_create(**params)
|
||||||
|
|
||||||
if created:
|
if created:
|
||||||
if custom_fields is not None:
|
set_custom_fields_values(device_type, custom_field_data)
|
||||||
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)
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
from dcim.models import Site, RackRole, Rack, RackGroup
|
|
||||||
from tenancy.models import Tenant
|
|
||||||
from extras.models import CustomField, CustomFieldValue
|
|
||||||
from startup_script_utils import load_yaml
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
from dcim.models import Site, RackRole, Rack, RackGroup
|
||||||
|
from startup_script_utils import *
|
||||||
|
from tenancy.models import Tenant
|
||||||
|
|
||||||
racks = load_yaml('/opt/netbox/initializers/racks.yml')
|
racks = load_yaml('/opt/netbox/initializers/racks.yml')
|
||||||
|
|
||||||
if racks is None:
|
if racks is None:
|
||||||
|
@ -20,7 +20,7 @@ optional_assocs = {
|
||||||
}
|
}
|
||||||
|
|
||||||
for params in racks:
|
for params in racks:
|
||||||
custom_fields = params.pop('custom_fields', None)
|
custom_field_data = pop_custom_fields(params)
|
||||||
|
|
||||||
for assoc, details in required_assocs.items():
|
for assoc, details in required_assocs.items():
|
||||||
model, field = details
|
model, field = details
|
||||||
|
@ -38,15 +38,6 @@ for params in racks:
|
||||||
rack, created = Rack.objects.get_or_create(**params)
|
rack, created = Rack.objects.get_or_create(**params)
|
||||||
|
|
||||||
if created:
|
if created:
|
||||||
if custom_fields is not None:
|
set_custom_fields_values(rack, custom_field_data)
|
||||||
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)
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
from tenancy.models import Tenant, TenantGroup
|
|
||||||
from extras.models import CustomField, CustomFieldValue
|
|
||||||
from startup_script_utils import load_yaml
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
from startup_script_utils import *
|
||||||
|
from tenancy.models import Tenant, TenantGroup
|
||||||
|
|
||||||
tenants = load_yaml('/opt/netbox/initializers/tenants.yml')
|
tenants = load_yaml('/opt/netbox/initializers/tenants.yml')
|
||||||
|
|
||||||
if tenants is None:
|
if tenants is None:
|
||||||
|
@ -13,7 +13,7 @@ optional_assocs = {
|
||||||
}
|
}
|
||||||
|
|
||||||
for params in tenants:
|
for params in tenants:
|
||||||
custom_fields = params.pop('custom_fields', None)
|
custom_field_data = pop_custom_fields(params)
|
||||||
|
|
||||||
for assoc, details in optional_assocs.items():
|
for assoc, details in optional_assocs.items():
|
||||||
if assoc in params:
|
if assoc in params:
|
||||||
|
@ -25,15 +25,6 @@ for params in tenants:
|
||||||
tenant, created = Tenant.objects.get_or_create(**params)
|
tenant, created = Tenant.objects.get_or_create(**params)
|
||||||
|
|
||||||
if created:
|
if created:
|
||||||
if custom_fields is not None:
|
set_custom_fields_values(tenant, custom_field_data)
|
||||||
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)
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
from dcim.models import Site, Rack, DeviceRole, DeviceType, Device, Platform
|
|
||||||
from virtualization.models import Cluster
|
|
||||||
from tenancy.models import Tenant
|
|
||||||
from extras.models import CustomField, CustomFieldValue
|
|
||||||
from startup_script_utils import load_yaml
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
from dcim.models import Site, Rack, DeviceRole, DeviceType, Device, Platform
|
||||||
|
from startup_script_utils import *
|
||||||
|
from tenancy.models import Tenant
|
||||||
|
from virtualization.models import Cluster
|
||||||
|
|
||||||
devices = load_yaml('/opt/netbox/initializers/devices.yml')
|
devices = load_yaml('/opt/netbox/initializers/devices.yml')
|
||||||
|
|
||||||
if devices is None:
|
if devices is None:
|
||||||
|
@ -24,7 +24,8 @@ optional_assocs = {
|
||||||
}
|
}
|
||||||
|
|
||||||
for params in devices:
|
for params in devices:
|
||||||
custom_fields = params.pop('custom_fields', None)
|
custom_field_data = pop_custom_fields(params)
|
||||||
|
|
||||||
# primary ips are handled later in `270_primary_ips.py`
|
# primary ips are handled later in `270_primary_ips.py`
|
||||||
params.pop('primary_ip4', None)
|
params.pop('primary_ip4', None)
|
||||||
params.pop('primary_ip6', None)
|
params.pop('primary_ip6', None)
|
||||||
|
@ -45,15 +46,6 @@ for params in devices:
|
||||||
device, created = Device.objects.get_or_create(**params)
|
device, created = Device.objects.get_or_create(**params)
|
||||||
|
|
||||||
if created:
|
if created:
|
||||||
if custom_fields is not None:
|
set_custom_fields_values(device, custom_field_data)
|
||||||
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)
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
from ipam.models import Aggregate, RIR
|
|
||||||
|
|
||||||
from extras.models import CustomField, CustomFieldValue
|
|
||||||
|
|
||||||
from netaddr import IPNetwork
|
|
||||||
from startup_script_utils import load_yaml
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
from ipam.models import Aggregate, RIR
|
||||||
|
from netaddr import IPNetwork
|
||||||
|
from startup_script_utils import *
|
||||||
|
|
||||||
aggregates = load_yaml('/opt/netbox/initializers/aggregates.yml')
|
aggregates = load_yaml('/opt/netbox/initializers/aggregates.yml')
|
||||||
|
|
||||||
if aggregates is None:
|
if aggregates is None:
|
||||||
|
@ -16,7 +14,8 @@ required_assocs = {
|
||||||
}
|
}
|
||||||
|
|
||||||
for params in aggregates:
|
for params in aggregates:
|
||||||
custom_fields = params.pop('custom_fields', None)
|
custom_field_data = pop_custom_fields(params)
|
||||||
|
|
||||||
params['prefix'] = IPNetwork(params['prefix'])
|
params['prefix'] = IPNetwork(params['prefix'])
|
||||||
|
|
||||||
for assoc, details in required_assocs.items():
|
for assoc, details in required_assocs.items():
|
||||||
|
@ -28,15 +27,6 @@ for params in aggregates:
|
||||||
aggregate, created = Aggregate.objects.get_or_create(**params)
|
aggregate, created = Aggregate.objects.get_or_create(**params)
|
||||||
|
|
||||||
if created:
|
if created:
|
||||||
if custom_fields is not None:
|
set_custom_fields_values(aggregate, custom_field_data)
|
||||||
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)
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
from dcim.models import Site
|
|
||||||
from virtualization.models import Cluster, ClusterType, ClusterGroup
|
|
||||||
from extras.models import CustomField, CustomFieldValue
|
|
||||||
from startup_script_utils import load_yaml
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
from dcim.models import Site
|
||||||
|
from startup_script_utils import *
|
||||||
|
from virtualization.models import Cluster, ClusterType, ClusterGroup
|
||||||
|
|
||||||
clusters = load_yaml('/opt/netbox/initializers/clusters.yml')
|
clusters = load_yaml('/opt/netbox/initializers/clusters.yml')
|
||||||
|
|
||||||
if clusters is None:
|
if clusters is None:
|
||||||
|
@ -19,7 +19,7 @@ optional_assocs = {
|
||||||
}
|
}
|
||||||
|
|
||||||
for params in clusters:
|
for params in clusters:
|
||||||
custom_fields = params.pop('custom_fields', None)
|
custom_field_data = pop_custom_fields(params)
|
||||||
|
|
||||||
for assoc, details in required_assocs.items():
|
for assoc, details in required_assocs.items():
|
||||||
model, field = details
|
model, field = details
|
||||||
|
@ -37,15 +37,6 @@ for params in clusters:
|
||||||
cluster, created = Cluster.objects.get_or_create(**params)
|
cluster, created = Cluster.objects.get_or_create(**params)
|
||||||
|
|
||||||
if created:
|
if created:
|
||||||
if custom_fields is not None:
|
set_custom_fields_values(cluster, custom_field_data)
|
||||||
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)
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
from ipam.models import VRF
|
|
||||||
from tenancy.models import Tenant
|
|
||||||
|
|
||||||
from extras.models import CustomField, CustomFieldValue
|
|
||||||
|
|
||||||
from startup_script_utils import load_yaml
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
from ipam.models import VRF
|
||||||
|
from startup_script_utils import *
|
||||||
|
from tenancy.models import Tenant
|
||||||
|
|
||||||
vrfs = load_yaml('/opt/netbox/initializers/vrfs.yml')
|
vrfs = load_yaml('/opt/netbox/initializers/vrfs.yml')
|
||||||
|
|
||||||
if vrfs is None:
|
if vrfs is None:
|
||||||
|
@ -16,7 +14,7 @@ optional_assocs = {
|
||||||
}
|
}
|
||||||
|
|
||||||
for params in vrfs:
|
for params in vrfs:
|
||||||
custom_fields = params.pop('custom_fields', None)
|
custom_field_data = pop_custom_fields(params)
|
||||||
|
|
||||||
for assoc, details in optional_assocs.items():
|
for assoc, details in optional_assocs.items():
|
||||||
if assoc in params:
|
if assoc in params:
|
||||||
|
@ -28,15 +26,6 @@ for params in vrfs:
|
||||||
vrf, created = VRF.objects.get_or_create(**params)
|
vrf, created = VRF.objects.get_or_create(**params)
|
||||||
|
|
||||||
if created:
|
if created:
|
||||||
if custom_fields is not None:
|
set_custom_fields_values(vrf, custom_field_data)
|
||||||
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)
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
|
import sys
|
||||||
|
|
||||||
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 startup_script_utils import *
|
||||||
from startup_script_utils import load_yaml
|
|
||||||
import sys
|
|
||||||
|
|
||||||
vlan_groups = load_yaml('/opt/netbox/initializers/vlan_groups.yml')
|
vlan_groups = load_yaml('/opt/netbox/initializers/vlan_groups.yml')
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ optional_assocs = {
|
||||||
}
|
}
|
||||||
|
|
||||||
for params in vlan_groups:
|
for params in vlan_groups:
|
||||||
custom_fields = params.pop('custom_fields', None)
|
custom_field_data = pop_custom_fields(params)
|
||||||
|
|
||||||
for assoc, details in optional_assocs.items():
|
for assoc, details in optional_assocs.items():
|
||||||
if assoc in params:
|
if assoc in params:
|
||||||
|
@ -26,15 +26,6 @@ for params in vlan_groups:
|
||||||
vlan_group, created = VLANGroup.objects.get_or_create(**params)
|
vlan_group, created = VLANGroup.objects.get_or_create(**params)
|
||||||
|
|
||||||
if created:
|
if created:
|
||||||
if custom_fields is not None:
|
set_custom_fields_values(vlan_group, custom_field_data)
|
||||||
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)
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
|
import sys
|
||||||
|
|
||||||
from dcim.models import Site
|
from dcim.models import Site
|
||||||
from ipam.models import VLAN, VLANGroup, Role
|
from ipam.models import VLAN, VLANGroup, Role
|
||||||
|
from startup_script_utils import *
|
||||||
from tenancy.models import Tenant, TenantGroup
|
from tenancy.models import Tenant, TenantGroup
|
||||||
from extras.models import CustomField, CustomFieldValue
|
|
||||||
from startup_script_utils import load_yaml
|
|
||||||
import sys
|
|
||||||
|
|
||||||
vlans = load_yaml('/opt/netbox/initializers/vlans.yml')
|
vlans = load_yaml('/opt/netbox/initializers/vlans.yml')
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ optional_assocs = {
|
||||||
}
|
}
|
||||||
|
|
||||||
for params in vlans:
|
for params in vlans:
|
||||||
custom_fields = params.pop('custom_fields', None)
|
custom_field_data = pop_custom_fields(params)
|
||||||
|
|
||||||
for assoc, details in optional_assocs.items():
|
for assoc, details in optional_assocs.items():
|
||||||
if assoc in params:
|
if assoc in params:
|
||||||
|
@ -31,15 +31,6 @@ for params in vlans:
|
||||||
vlan, created = VLAN.objects.get_or_create(**params)
|
vlan, created = VLAN.objects.get_or_create(**params)
|
||||||
|
|
||||||
if created:
|
if created:
|
||||||
if custom_fields is not None:
|
set_custom_fields_values(vlan, custom_field_data)
|
||||||
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)
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
|
import sys
|
||||||
|
|
||||||
from dcim.models import Site
|
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 extras.models import CustomField, CustomFieldValue
|
|
||||||
from netaddr import IPNetwork
|
from netaddr import IPNetwork
|
||||||
from startup_script_utils import load_yaml
|
from startup_script_utils import *
|
||||||
import sys
|
from tenancy.models import Tenant, TenantGroup
|
||||||
|
|
||||||
prefixes = load_yaml('/opt/netbox/initializers/prefixes.yml')
|
prefixes = load_yaml('/opt/netbox/initializers/prefixes.yml')
|
||||||
|
|
||||||
|
@ -21,7 +21,8 @@ optional_assocs = {
|
||||||
}
|
}
|
||||||
|
|
||||||
for params in prefixes:
|
for params in prefixes:
|
||||||
custom_fields = params.pop('custom_fields', None)
|
custom_field_data = pop_custom_fields(params)
|
||||||
|
|
||||||
params['prefix'] = IPNetwork(params['prefix'])
|
params['prefix'] = IPNetwork(params['prefix'])
|
||||||
|
|
||||||
for assoc, details in optional_assocs.items():
|
for assoc, details in optional_assocs.items():
|
||||||
|
@ -33,14 +34,6 @@ for params in prefixes:
|
||||||
prefix, created = Prefix.objects.get_or_create(**params)
|
prefix, created = Prefix.objects.get_or_create(**params)
|
||||||
|
|
||||||
if created:
|
if created:
|
||||||
if custom_fields is not None:
|
set_custom_fields_values(prefix, custom_field_data)
|
||||||
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)
|
print("📌 Created Prefix", prefix.prefix)
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
from dcim.models import Site, Platform, DeviceRole
|
|
||||||
from virtualization.models import Cluster, VirtualMachine
|
|
||||||
from tenancy.models import Tenant
|
|
||||||
from extras.models import CustomField, CustomFieldValue
|
|
||||||
from startup_script_utils import load_yaml
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
from dcim.models import Platform, DeviceRole
|
||||||
|
from startup_script_utils import *
|
||||||
|
from tenancy.models import Tenant
|
||||||
|
from virtualization.models import Cluster, VirtualMachine
|
||||||
|
|
||||||
virtual_machines = load_yaml('/opt/netbox/initializers/virtual_machines.yml')
|
virtual_machines = load_yaml('/opt/netbox/initializers/virtual_machines.yml')
|
||||||
|
|
||||||
if virtual_machines is None:
|
if virtual_machines is None:
|
||||||
|
@ -21,7 +21,8 @@ optional_assocs = {
|
||||||
}
|
}
|
||||||
|
|
||||||
for params in virtual_machines:
|
for params in virtual_machines:
|
||||||
custom_fields = params.pop('custom_fields', None)
|
custom_field_data = pop_custom_fields(params)
|
||||||
|
|
||||||
# primary ips are handled later in `270_primary_ips.py`
|
# primary ips are handled later in `270_primary_ips.py`
|
||||||
params.pop('primary_ip4', None)
|
params.pop('primary_ip4', None)
|
||||||
params.pop('primary_ip6', None)
|
params.pop('primary_ip6', None)
|
||||||
|
@ -42,15 +43,6 @@ for params in virtual_machines:
|
||||||
virtual_machine, created = VirtualMachine.objects.get_or_create(**params)
|
virtual_machine, created = VirtualMachine.objects.get_or_create(**params)
|
||||||
|
|
||||||
if created:
|
if created:
|
||||||
if custom_fields is not None:
|
set_custom_fields_values(virtual_machine, custom_field_data)
|
||||||
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)
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
from virtualization.models import VirtualMachine, VMInterface
|
|
||||||
from extras.models import CustomField, CustomFieldValue
|
|
||||||
from startup_script_utils import load_yaml
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
from startup_script_utils import *
|
||||||
|
from virtualization.models import VirtualMachine, VMInterface
|
||||||
|
|
||||||
interfaces = load_yaml('/opt/netbox/initializers/virtualization_interfaces.yml')
|
interfaces = load_yaml('/opt/netbox/initializers/virtualization_interfaces.yml')
|
||||||
|
|
||||||
if interfaces is None:
|
if interfaces is None:
|
||||||
|
@ -13,7 +13,7 @@ required_assocs = {
|
||||||
}
|
}
|
||||||
|
|
||||||
for params in interfaces:
|
for params in interfaces:
|
||||||
custom_fields = params.pop('custom_fields', None)
|
custom_field_data = pop_custom_fields(params)
|
||||||
|
|
||||||
for assoc, details in required_assocs.items():
|
for assoc, details in required_assocs.items():
|
||||||
model, field = details
|
model, field = details
|
||||||
|
@ -24,15 +24,6 @@ for params in interfaces:
|
||||||
interface, created = VMInterface.objects.get_or_create(**params)
|
interface, created = VMInterface.objects.get_or_create(**params)
|
||||||
|
|
||||||
if created:
|
if created:
|
||||||
if custom_fields is not None:
|
set_custom_fields_values(interface, custom_field_data)
|
||||||
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)
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
from dcim.models import Interface, Device
|
|
||||||
from extras.models import CustomField, CustomFieldValue
|
|
||||||
from startup_script_utils import load_yaml
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
interfaces= load_yaml('/opt/netbox/initializers/dcim_interfaces.yml')
|
from dcim.models import Interface, Device
|
||||||
|
from startup_script_utils import *
|
||||||
|
|
||||||
|
interfaces = load_yaml('/opt/netbox/initializers/dcim_interfaces.yml')
|
||||||
|
|
||||||
if interfaces is None:
|
if interfaces is None:
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
@ -13,7 +13,7 @@ required_assocs = {
|
||||||
}
|
}
|
||||||
|
|
||||||
for params in interfaces:
|
for params in interfaces:
|
||||||
custom_fields = params.pop('custom_fields', None)
|
custom_field_data = pop_custom_fields(params)
|
||||||
|
|
||||||
for assoc, details in required_assocs.items():
|
for assoc, details in required_assocs.items():
|
||||||
model, field = details
|
model, field = details
|
||||||
|
@ -24,15 +24,6 @@ for params in interfaces:
|
||||||
interface, created = Interface.objects.get_or_create(**params)
|
interface, created = Interface.objects.get_or_create(**params)
|
||||||
|
|
||||||
if created:
|
if created:
|
||||||
if custom_fields is not None:
|
set_custom_fields_values(interface, custom_field_data)
|
||||||
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)
|
||||||
|
|
|
@ -3,10 +3,9 @@ import sys
|
||||||
from dcim.models import Device, Interface
|
from dcim.models import Device, Interface
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
from extras.models import CustomField, CustomFieldValue
|
|
||||||
from ipam.models import VRF, IPAddress
|
from ipam.models import VRF, IPAddress
|
||||||
from netaddr import IPNetwork
|
from netaddr import IPNetwork
|
||||||
from startup_script_utils import load_yaml
|
from startup_script_utils import *
|
||||||
from tenancy.models import Tenant
|
from tenancy.models import Tenant
|
||||||
from virtualization.models import VirtualMachine, VMInterface
|
from virtualization.models import VirtualMachine, VMInterface
|
||||||
|
|
||||||
|
@ -25,9 +24,10 @@ vm_interface_ct = ContentType.objects.filter(Q(app_label='virtualization', model
|
||||||
interface_ct = ContentType.objects.filter(Q(app_label='dcim', model='interface')).first()
|
interface_ct = ContentType.objects.filter(Q(app_label='dcim', model='interface')).first()
|
||||||
|
|
||||||
for params in ip_addresses:
|
for params in ip_addresses:
|
||||||
|
custom_field_data = pop_custom_fields(params)
|
||||||
|
|
||||||
vm = params.pop('virtual_machine', None)
|
vm = params.pop('virtual_machine', None)
|
||||||
device = params.pop('device', None)
|
device = params.pop('device', None)
|
||||||
custom_fields = params.pop('custom_fields', None)
|
|
||||||
params['address'] = IPNetwork(params['address'])
|
params['address'] = IPNetwork(params['address'])
|
||||||
|
|
||||||
if vm and device:
|
if vm and device:
|
||||||
|
@ -55,15 +55,6 @@ for params in ip_addresses:
|
||||||
ip_address, created = IPAddress.objects.get_or_create(**params)
|
ip_address, created = IPAddress.objects.get_or_create(**params)
|
||||||
|
|
||||||
if created:
|
if created:
|
||||||
if custom_fields is not None:
|
set_custom_fields_values(ip_address, custom_field_data)
|
||||||
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)
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
from .load_yaml import load_yaml
|
from .load_yaml import load_yaml
|
||||||
from .permissions import set_permissions
|
from .permissions import set_permissions
|
||||||
|
from .custom_fields import set_custom_fields_values, pop_custom_fields
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
def set_custom_fields_values(entity, custom_field_data):
|
||||||
|
if not custom_field_data:
|
||||||
|
return
|
||||||
|
|
||||||
|
entity.custom_field_data = custom_field_data
|
||||||
|
return entity.save()
|
||||||
|
|
||||||
|
def pop_custom_fields(params):
|
||||||
|
if 'custom_field_data' in params:
|
||||||
|
return params.pop('custom_field_data')
|
||||||
|
elif 'custom_fields' in params:
|
||||||
|
print("⚠️ Please rename 'custom_fields' to 'custom_field_data'!")
|
||||||
|
return params.pop('custom_fields')
|
||||||
|
|
||||||
|
return None
|
|
@ -1,5 +1,6 @@
|
||||||
from ruamel.yaml import YAML
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from ruamel.yaml import YAML
|
||||||
|
|
||||||
|
|
||||||
def load_yaml(yaml_file: str):
|
def load_yaml(yaml_file: str):
|
||||||
yf = Path(yaml_file)
|
yf = Path(yaml_file)
|
||||||
|
|
21
test.sh
21
test.sh
|
@ -1,12 +1,29 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
# Runs the original Netbox unit tests and tests whether all initializers work.
|
||||||
|
# Usage:
|
||||||
|
# ./test.sh latest
|
||||||
|
# ./test.sh v2.9.7
|
||||||
|
# ./test.sh develop-2.10
|
||||||
|
# IMAGE='netboxcommunity/netbox:latest' ./test.sh
|
||||||
|
# IMAGE='netboxcommunity/netbox:v2.9.7' ./test.sh
|
||||||
|
# IMAGE='netboxcommunity/netbox:develop-2.10' ./test.sh
|
||||||
|
# export IMAGE='netboxcommunity/netbox:latest'; ./test.sh
|
||||||
|
# export IMAGE='netboxcommunity/netbox:v2.9.7'; ./test.sh
|
||||||
|
# export IMAGE='netboxcommunity/netbox:develop-2.10'; ./test.sh
|
||||||
|
|
||||||
# exit when a command exits with an exit code != 0
|
# exit when a command exits with an exit code != 0
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
# version is used by `docker-compose.yml` do determine the tag
|
# IMAGE is used by `docker-compose.yml` do determine the tag
|
||||||
# of the Docker Image that is to be used
|
# of the Docker Image that is to be used
|
||||||
export IMAGE="${IMAGE-netboxcommunity/netbox:latest}"
|
if [ "${1}x" != "x" ]; then
|
||||||
|
# Use the command line argument
|
||||||
|
export IMAGE="netboxcommunity/netbox:${1}"
|
||||||
|
else
|
||||||
|
export IMAGE="${IMAGE-netboxcommunity/netbox:latest}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Ensure that an IMAGE is defined
|
||||||
if [ -z "${IMAGE}" ]; then
|
if [ -z "${IMAGE}" ]; then
|
||||||
echo "⚠️ No image defined"
|
echo "⚠️ No image defined"
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue