diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index 608e6e0..d77ceb5 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -46,7 +46,6 @@ - ./build.sh develop docker_from: - '' # use the default of the build script - - alpine:edge fail-fast: false runs-on: ubuntu-latest name: Builds new NetBox Docker Images diff --git a/Dockerfile b/Dockerfile index 505b888..51cd359 100644 --- a/Dockerfile +++ b/Dockerfile @@ -97,7 +97,7 @@ RUN mkdir -p static /opt/unit/state/ /opt/unit/tmp/ \ && chown -R unit:root media /opt/unit/ \ && chmod -R g+w media /opt/unit/ \ - && cd /opt/netbox/ && /opt/netbox/venv/bin/python -m mkdocs build \ + && cd /opt/netbox/ && SECRET_KEY="dummy" /opt/netbox/venv/bin/python -m mkdocs build \ --config-file /opt/netbox/mkdocs.yml --site-dir /opt/netbox/netbox/project-static/docs/ \ && SECRET_KEY="dummy" /opt/netbox/venv/bin/python /opt/netbox/netbox/manage.py collectstatic --no-input diff --git a/README.md b/README.md index d8aedf4..b76f9cf 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ ![Docker Pulls](https://img.shields.io/docker/pulls/netboxcommunity/netbox) [![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 container. +[The GitHub repository](netbox-docker-github) houses the components needed to build NetBox as a container. Images are built regularly using the code in that repository and are pushed to [Docker Hub][netbox-dockerhub], [Quay.io][netbox-quayio] and [GitHub Container Registry][netbox-ghcr]. Do you have any questions? @@ -19,7 +19,7 @@ [netbox-docker-microbadger]: https://microbadger.com/images/netboxcommunity/netbox [netbox-dockerhub]: https://hub.docker.com/r/netboxcommunity/netbox/ [netbox-quayio]: https://quay.io/repository/netboxcommunity/netbox -[netbox-ghcr]: https://ghcr.io/netbox-community/netbox/ +[netbox-ghcr]: https://github.com/netbox-community/netbox-docker/pkgs/container/netbox [netbox-docker-github]: https://github.com/netbox-community/netbox-docker/ [netbox-docker-slack]: https://join.slack.com/t/netdev-community/shared_invite/zt-mtts8g0n-Sm6Wutn62q_M4OdsaIycrQ [netbox-docker-slack-channel]: https://netdev-community.slack.com/archives/C01P0GEVBU7 @@ -75,7 +75,7 @@ You must use _NetBox Docker version_ `a.b.c` to guarantee the compatibility. These images are automatically built from [the `master` branch of NetBox][netbox-master]. * `snapshot-a.b.c`: - These are pre-release builds. + These are prerelease builds. They contain the support files of _NetBox Docker version_ `a.b.c`. You must use _NetBox Docker version_ `a.b.c` to guarantee the compatibility. These images are automatically built from the [`develop` branch of NetBox][netbox-develop]. @@ -106,7 +106,7 @@ ## Documentation -Please refer [to our wiki on Github][netbox-docker-wiki] for further information on how to use the NetBox Docker image properly. +Please refer [to our wiki on GitHub][netbox-docker-wiki] for further information on how to use the NetBox Docker image properly. The wiki covers advanced topics such as using files for secrets, configuring TLS, deployment to Kubernetes, monitoring and configuring NAPALM and LDAP. Our wiki is a community effort. @@ -116,7 +116,7 @@ ## Getting Help -Feel free to ask questions in our [Github Community][netbox-community] +Feel free to ask questions in our [GitHub Community][netbox-community] or [join our Slack][netbox-docker-slack] and ask [in our channel `#netbox-docker`][netbox-docker-slack-channel], which is free to use and where there are almost always people online that can help you in the Slack channel. diff --git a/VERSION b/VERSION index 26ca594..dc1e644 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.5.1 +1.6.0 diff --git a/configuration/configuration.py b/configuration/configuration.py index 311d1f0..1db6051 100644 --- a/configuration/configuration.py +++ b/configuration/configuration.py @@ -147,6 +147,9 @@ # by anonymous users. List models in the form `.`. Add '*' to this list to exempt all models. EXEMPT_VIEW_PERMISSIONS = list(filter(None, environ.get('EXEMPT_VIEW_PERMISSIONS', '').split(' '))) +# Enable GraphQL API. +GRAPHQL_ENABLED = environ.get('GRAPHQL_ENABLED', 'True').lower() == 'true' + # Enable custom logging. Please see the Django documentation for detailed guidance on configuring custom logs: # https://docs.djangoproject.com/en/stable/topics/logging/ LOGGING = {} diff --git a/docker-compose.yml b/docker-compose.yml index 3b68f08..9c6a284 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,7 +1,7 @@ version: '3.4' services: netbox: &netbox - image: netboxcommunity/netbox:${VERSION-v3.1-1.5.1} + image: netboxcommunity/netbox:${VERSION-v3.1-1.6.0} depends_on: - postgres - redis diff --git a/env/netbox.env b/env/netbox.env index 6593cbc..456cac9 100644 --- a/env/netbox.env +++ b/env/netbox.env @@ -14,6 +14,7 @@ # EMAIL_USE_SSL and EMAIL_USE_TLS are mutually exclusive, i.e. they can't both be `true`! EMAIL_USE_SSL=false EMAIL_USE_TLS=false +GRAPHQL_ENABLED=true HOUSEKEEPING_INTERVAL=86400 MAX_PAGE_SIZE=1000 MEDIA_ROOT=/opt/netbox/netbox/media diff --git a/initializers/asns.yml b/initializers/asns.yml new file mode 100644 index 0000000..f75408b --- /dev/null +++ b/initializers/asns.yml @@ -0,0 +1,7 @@ +# - asn: 1 +# rir: RFC1918 +# tenant: tenant1 +# - asn: 2 +# rir: RFC4193 ULA +# - asn: 3 +# rir: RFC3849 diff --git a/initializers/sites.yml b/initializers/sites.yml index 7ace3aa..700c853 100644 --- a/initializers/sites.yml +++ b/initializers/sites.yml @@ -3,7 +3,6 @@ # region: Downtown # status: active # facility: Amsterdam 1 -# asn: 12345 # custom_field_data: # text_field: Description for AMS1 # - name: AMS 2 @@ -11,7 +10,6 @@ # region: Downtown # status: active # facility: Amsterdam 2 -# asn: 54321 # custom_field_data: # text_field: Description for AMS2 # - name: AMS 3 @@ -19,7 +17,6 @@ # region: Suburbs # status: active # facility: Amsterdam 3 -# asn: 67890 # tenant: tenant1 # custom_field_data: # text_field: Description for AMS3 @@ -28,7 +25,6 @@ # region: Singapore # status: active # facility: Singapore 1 -# asn: 09876 # tenant: tenant2 # custom_field_data: # text_field: Description for SING1 diff --git a/requirements-container.txt b/requirements-container.txt index f47f232..2542395 100644 --- a/requirements-container.txt +++ b/requirements-container.txt @@ -1,5 +1,6 @@ -napalm==3.3.1 -ruamel.yaml==0.17.17 -django-auth-ldap==3.0.0 -google-crc32c==1.3.0 +django-auth-ldap==4.0.0 django-storages[azure,boto3,dropbox,google,libcloud,sftp]==1.12.3 +google-crc32c==1.3.0 +napalm==3.3.1 +ruamel.yaml==0.17.21 +tzdata==2021.5 diff --git a/startup_scripts/015_object_permissions.py b/startup_scripts/015_object_permissions.py deleted file mode 100644 index 8a5ecd4..0000000 --- a/startup_scripts/015_object_permissions.py +++ /dev/null @@ -1,66 +0,0 @@ -import sys - -from django.contrib.contenttypes.models import ContentType -from startup_script_utils import load_yaml -from users.models import AdminGroup, AdminUser, ObjectPermission - -object_permissions = load_yaml("/opt/netbox/initializers/object_permissions.yml") - -if object_permissions is None: - sys.exit() - - -for permission_name, permission_details in object_permissions.items(): - - object_permission, created = ObjectPermission.objects.get_or_create( - name=permission_name, - description=permission_details["description"], - enabled=permission_details["enabled"], - actions=permission_details["actions"], - ) - - if permission_details.get("object_types", 0): - object_types = permission_details["object_types"] - - if object_types == "all": - object_permission.object_types.set(ContentType.objects.all()) - - else: - for app_label, models in object_types.items(): - if models == "all": - app_models = ContentType.objects.filter(app_label=app_label) - - for app_model in app_models: - object_permission.object_types.add(app_model.id) - else: - # There is - for model in models: - object_permission.object_types.add( - ContentType.objects.get(app_label=app_label, model=model) - ) - - print("πŸ”“ Created object permission", object_permission.name) - - if permission_details.get("groups", 0): - for groupname in permission_details["groups"]: - group = AdminGroup.objects.filter(name=groupname).first() - - if group: - object_permission.groups.add(group) - print( - " πŸ‘₯ Assigned group %s object permission of %s" - % (groupname, object_permission.name) - ) - - if permission_details.get("users", 0): - for username in permission_details["users"]: - user = AdminUser.objects.filter(username=username).first() - - if user: - object_permission.users.add(user) - print( - " πŸ‘€ Assigned user %s object permission of %s" - % (username, object_permission.name) - ) - - object_permission.save() diff --git a/startup_scripts/020_custom_fields.py b/startup_scripts/020_custom_fields.py deleted file mode 100644 index a40883c..0000000 --- a/startup_scripts/020_custom_fields.py +++ /dev/null @@ -1,67 +0,0 @@ -import sys - -from extras.models import CustomField -from startup_script_utils import load_yaml - - -def get_class_for_class_path(class_path): - import importlib - - from django.contrib.contenttypes.models import ContentType - - module_name, class_name = class_path.rsplit(".", 1) - module = importlib.import_module(module_name) - clazz = getattr(module, class_name) - return ContentType.objects.get_for_model(clazz) - - -customfields = load_yaml("/opt/netbox/initializers/custom_fields.yml") - -if customfields is None: - sys.exit() - -for cf_name, cf_details in customfields.items(): - custom_field, created = CustomField.objects.get_or_create(name=cf_name) - - if created: - if cf_details.get("default", False): - custom_field.default = cf_details["default"] - - if cf_details.get("description", False): - custom_field.description = cf_details["description"] - - if cf_details.get("label", False): - custom_field.label = cf_details["label"] - - for object_type in cf_details.get("on_objects", []): - custom_field.content_types.add(get_class_for_class_path(object_type)) - - if cf_details.get("required", False): - custom_field.required = cf_details["required"] - - if cf_details.get("type", False): - custom_field.type = cf_details["type"] - - if cf_details.get("filter_logic", False): - custom_field.filter_logic = cf_details["filter_logic"] - - if cf_details.get("weight", -1) >= 0: - custom_field.weight = cf_details["weight"] - - if cf_details.get("choices", False): - custom_field.choices = [] - - for choice_detail in cf_details.get("choices", []): - if isinstance(choice_detail, dict) and "value" in choice_detail: - # legacy mode - print( - f"⚠️ Please migrate the choice '{choice_detail['value']}' of '{cf_name}'" - + " to the new format, as 'weight' is no longer supported!" - ) - custom_field.choices.append(choice_detail["value"]) - else: - custom_field.choices.append(choice_detail) - - custom_field.save() - - print("πŸ”§ Created custom field", cf_name) diff --git a/startup_scripts/020_object_permissions.py b/startup_scripts/020_object_permissions.py new file mode 100644 index 0000000..8a5ecd4 --- /dev/null +++ b/startup_scripts/020_object_permissions.py @@ -0,0 +1,66 @@ +import sys + +from django.contrib.contenttypes.models import ContentType +from startup_script_utils import load_yaml +from users.models import AdminGroup, AdminUser, ObjectPermission + +object_permissions = load_yaml("/opt/netbox/initializers/object_permissions.yml") + +if object_permissions is None: + sys.exit() + + +for permission_name, permission_details in object_permissions.items(): + + object_permission, created = ObjectPermission.objects.get_or_create( + name=permission_name, + description=permission_details["description"], + enabled=permission_details["enabled"], + actions=permission_details["actions"], + ) + + if permission_details.get("object_types", 0): + object_types = permission_details["object_types"] + + if object_types == "all": + object_permission.object_types.set(ContentType.objects.all()) + + else: + for app_label, models in object_types.items(): + if models == "all": + app_models = ContentType.objects.filter(app_label=app_label) + + for app_model in app_models: + object_permission.object_types.add(app_model.id) + else: + # There is + for model in models: + object_permission.object_types.add( + ContentType.objects.get(app_label=app_label, model=model) + ) + + print("πŸ”“ Created object permission", object_permission.name) + + if permission_details.get("groups", 0): + for groupname in permission_details["groups"]: + group = AdminGroup.objects.filter(name=groupname).first() + + if group: + object_permission.groups.add(group) + print( + " πŸ‘₯ Assigned group %s object permission of %s" + % (groupname, object_permission.name) + ) + + if permission_details.get("users", 0): + for username in permission_details["users"]: + user = AdminUser.objects.filter(username=username).first() + + if user: + object_permission.users.add(user) + print( + " πŸ‘€ Assigned user %s object permission of %s" + % (username, object_permission.name) + ) + + object_permission.save() diff --git a/startup_scripts/020_tags.py b/startup_scripts/020_tags.py deleted file mode 100644 index e50a000..0000000 --- a/startup_scripts/020_tags.py +++ /dev/null @@ -1,23 +0,0 @@ -import sys - -from extras.models import Tag -from startup_script_utils import load_yaml -from utilities.choices import ColorChoices - -tags = load_yaml("/opt/netbox/initializers/tags.yml") - -if tags is None: - sys.exit() - -for params in tags: - if "color" in params: - color = params.pop("color") - - for color_tpl in ColorChoices: - if color in color_tpl: - params["color"] = color_tpl[0] - - tag, created = Tag.objects.get_or_create(**params) - - if created: - print("🎨 Created Tag", tag.name) diff --git a/startup_scripts/020_tenant_groups.py b/startup_scripts/020_tenant_groups.py deleted file mode 100644 index 65cf155..0000000 --- a/startup_scripts/020_tenant_groups.py +++ /dev/null @@ -1,15 +0,0 @@ -import sys - -from startup_script_utils import load_yaml -from tenancy.models import TenantGroup - -tenant_groups = load_yaml("/opt/netbox/initializers/tenant_groups.yml") - -if tenant_groups is None: - sys.exit() - -for params in tenant_groups: - tenant_group, created = TenantGroup.objects.get_or_create(**params) - - if created: - print("πŸ”³ Created Tenant Group", tenant_group.name) diff --git a/startup_scripts/030_custom_fields.py b/startup_scripts/030_custom_fields.py new file mode 100644 index 0000000..a40883c --- /dev/null +++ b/startup_scripts/030_custom_fields.py @@ -0,0 +1,67 @@ +import sys + +from extras.models import CustomField +from startup_script_utils import load_yaml + + +def get_class_for_class_path(class_path): + import importlib + + from django.contrib.contenttypes.models import ContentType + + module_name, class_name = class_path.rsplit(".", 1) + module = importlib.import_module(module_name) + clazz = getattr(module, class_name) + return ContentType.objects.get_for_model(clazz) + + +customfields = load_yaml("/opt/netbox/initializers/custom_fields.yml") + +if customfields is None: + sys.exit() + +for cf_name, cf_details in customfields.items(): + custom_field, created = CustomField.objects.get_or_create(name=cf_name) + + if created: + if cf_details.get("default", False): + custom_field.default = cf_details["default"] + + if cf_details.get("description", False): + custom_field.description = cf_details["description"] + + if cf_details.get("label", False): + custom_field.label = cf_details["label"] + + for object_type in cf_details.get("on_objects", []): + custom_field.content_types.add(get_class_for_class_path(object_type)) + + if cf_details.get("required", False): + custom_field.required = cf_details["required"] + + if cf_details.get("type", False): + custom_field.type = cf_details["type"] + + if cf_details.get("filter_logic", False): + custom_field.filter_logic = cf_details["filter_logic"] + + if cf_details.get("weight", -1) >= 0: + custom_field.weight = cf_details["weight"] + + if cf_details.get("choices", False): + custom_field.choices = [] + + for choice_detail in cf_details.get("choices", []): + if isinstance(choice_detail, dict) and "value" in choice_detail: + # legacy mode + print( + f"⚠️ Please migrate the choice '{choice_detail['value']}' of '{cf_name}'" + + " to the new format, as 'weight' is no longer supported!" + ) + custom_field.choices.append(choice_detail["value"]) + else: + custom_field.choices.append(choice_detail) + + custom_field.save() + + print("πŸ”§ Created custom field", cf_name) diff --git a/startup_scripts/030_regions.py b/startup_scripts/030_regions.py deleted file mode 100644 index 9d5c91f..0000000 --- a/startup_scripts/030_regions.py +++ /dev/null @@ -1,25 +0,0 @@ -import sys - -from dcim.models import Region -from startup_script_utils import load_yaml - -regions = load_yaml("/opt/netbox/initializers/regions.yml") - -if regions is None: - sys.exit() - -optional_assocs = {"parent": (Region, "name")} - -for params in regions: - - for assoc, details in optional_assocs.items(): - if assoc in params: - model, field = details - query = {field: params.pop(assoc)} - - params[assoc] = model.objects.get(**query) - - region, created = Region.objects.get_or_create(**params) - - if created: - print("🌐 Created region", region.name) diff --git a/startup_scripts/030_tenants.py b/startup_scripts/030_tenants.py deleted file mode 100644 index 7b1a629..0000000 --- a/startup_scripts/030_tenants.py +++ /dev/null @@ -1,28 +0,0 @@ -import sys - -from startup_script_utils import load_yaml, pop_custom_fields, set_custom_fields_values -from tenancy.models import Tenant, TenantGroup - -tenants = load_yaml("/opt/netbox/initializers/tenants.yml") - -if tenants is None: - sys.exit() - -optional_assocs = {"group": (TenantGroup, "name")} - -for params in tenants: - custom_field_data = pop_custom_fields(params) - - for assoc, details in optional_assocs.items(): - if assoc in params: - model, field = details - query = {field: params.pop(assoc)} - - params[assoc] = model.objects.get(**query) - - tenant, created = Tenant.objects.get_or_create(**params) - - if created: - set_custom_fields_values(tenant, custom_field_data) - - print("πŸ‘©β€πŸ’» Created Tenant", tenant.name) diff --git a/startup_scripts/040_custom_links.py b/startup_scripts/040_custom_links.py new file mode 100644 index 0000000..40144bd --- /dev/null +++ b/startup_scripts/040_custom_links.py @@ -0,0 +1,33 @@ +import sys + +from django.contrib.contenttypes.models import ContentType +from extras.models import CustomLink +from startup_script_utils import load_yaml + +custom_links = load_yaml("/opt/netbox/initializers/custom_links.yml") + +if custom_links is None: + sys.exit() + + +def get_content_type_id(content_type): + try: + return ContentType.objects.get(model=content_type).id + except ContentType.DoesNotExist: + pass + + +for link in custom_links: + content_type = link.pop("content_type") + link["content_type_id"] = get_content_type_id(content_type) + if link["content_type_id"] is None: + print( + "⚠️ Unable to create Custom Link '{0}': The content_type '{1}' is unknown".format( + link.get("name"), content_type + ) + ) + continue + + custom_link, created = CustomLink.objects.get_or_create(**link) + if created: + print("πŸ”— Created Custom Link '{0}'".format(custom_link.name)) diff --git a/startup_scripts/040_sites.py b/startup_scripts/040_sites.py deleted file mode 100644 index f785139..0000000 --- a/startup_scripts/040_sites.py +++ /dev/null @@ -1,29 +0,0 @@ -import sys - -from dcim.models import Region, Site -from startup_script_utils import load_yaml, pop_custom_fields, set_custom_fields_values -from tenancy.models import Tenant - -sites = load_yaml("/opt/netbox/initializers/sites.yml") - -if sites is None: - sys.exit() - -optional_assocs = {"region": (Region, "name"), "tenant": (Tenant, "name")} - -for params in sites: - custom_field_data = pop_custom_fields(params) - - for assoc, details in optional_assocs.items(): - if assoc in params: - model, field = details - query = {field: params.pop(assoc)} - - params[assoc] = model.objects.get(**query) - - site, created = Site.objects.get_or_create(**params) - - if created: - set_custom_fields_values(site, custom_field_data) - - print("πŸ“ Created site", site.name) diff --git a/startup_scripts/050_manufacturers.py b/startup_scripts/050_manufacturers.py deleted file mode 100644 index d11b440..0000000 --- a/startup_scripts/050_manufacturers.py +++ /dev/null @@ -1,15 +0,0 @@ -import sys - -from dcim.models import Manufacturer -from startup_script_utils import load_yaml - -manufacturers = load_yaml("/opt/netbox/initializers/manufacturers.yml") - -if manufacturers is None: - sys.exit() - -for params in manufacturers: - manufacturer, created = Manufacturer.objects.get_or_create(**params) - - if created: - print("🏭 Created Manufacturer", manufacturer.name) diff --git a/startup_scripts/050_tags.py b/startup_scripts/050_tags.py new file mode 100644 index 0000000..e50a000 --- /dev/null +++ b/startup_scripts/050_tags.py @@ -0,0 +1,23 @@ +import sys + +from extras.models import Tag +from startup_script_utils import load_yaml +from utilities.choices import ColorChoices + +tags = load_yaml("/opt/netbox/initializers/tags.yml") + +if tags is None: + sys.exit() + +for params in tags: + if "color" in params: + color = params.pop("color") + + for color_tpl in ColorChoices: + if color in color_tpl: + params["color"] = color_tpl[0] + + tag, created = Tag.objects.get_or_create(**params) + + if created: + print("🎨 Created Tag", tag.name) diff --git a/startup_scripts/060_device_types.py b/startup_scripts/060_device_types.py deleted file mode 100644 index 0d3050b..0000000 --- a/startup_scripts/060_device_types.py +++ /dev/null @@ -1,37 +0,0 @@ -import sys - -from dcim.models import DeviceType, Manufacturer, Region -from startup_script_utils import load_yaml, pop_custom_fields, set_custom_fields_values -from tenancy.models import Tenant - -device_types = load_yaml("/opt/netbox/initializers/device_types.yml") - -if device_types is None: - sys.exit() - -required_assocs = {"manufacturer": (Manufacturer, "name")} - -optional_assocs = {"region": (Region, "name"), "tenant": (Tenant, "name")} - -for params in device_types: - custom_field_data = pop_custom_fields(params) - - for assoc, details in required_assocs.items(): - model, field = details - query = {field: params.pop(assoc)} - - params[assoc] = model.objects.get(**query) - - for assoc, details in optional_assocs.items(): - if assoc in params: - model, field = details - query = {field: params.pop(assoc)} - - params[assoc] = model.objects.get(**query) - - device_type, created = DeviceType.objects.get_or_create(**params) - - if created: - set_custom_fields_values(device_type, custom_field_data) - - print("πŸ”‘ Created device type", device_type.manufacturer, device_type.model) diff --git a/startup_scripts/060_webhooks.py b/startup_scripts/060_webhooks.py new file mode 100644 index 0000000..8787f5f --- /dev/null +++ b/startup_scripts/060_webhooks.py @@ -0,0 +1,34 @@ +import sys + +from django.contrib.contenttypes.models import ContentType +from extras.models import Webhook +from startup_script_utils import load_yaml + +webhooks = load_yaml("/opt/netbox/initializers/webhooks.yml") + +if webhooks is None: + sys.exit() + + +def get_content_type_id(hook_name, content_type): + try: + return ContentType.objects.get(model=content_type).id + except ContentType.DoesNotExist as ex: + print("⚠️ Webhook '{0}': The object_type '{1}' is unknown.".format(hook_name, content_type)) + raise ex + + +for hook in webhooks: + obj_types = hook.pop("object_types") + + try: + obj_type_ids = [get_content_type_id(hook["name"], obj) for obj in obj_types] + except ContentType.DoesNotExist: + continue + + webhook, created = Webhook.objects.get_or_create(**hook) + if created: + webhook.content_types.set(obj_type_ids) + webhook.save() + + print("πŸͺ Created Webhook {0}".format(webhook.name)) diff --git a/startup_scripts/070_rack_roles.py b/startup_scripts/070_rack_roles.py deleted file mode 100644 index 5850405..0000000 --- a/startup_scripts/070_rack_roles.py +++ /dev/null @@ -1,23 +0,0 @@ -import sys - -from dcim.models import RackRole -from startup_script_utils import load_yaml -from utilities.choices import ColorChoices - -rack_roles = load_yaml("/opt/netbox/initializers/rack_roles.yml") - -if rack_roles is None: - sys.exit() - -for params in rack_roles: - if "color" in params: - color = params.pop("color") - - for color_tpl in ColorChoices: - if color in color_tpl: - params["color"] = color_tpl[0] - - rack_role, created = RackRole.objects.get_or_create(**params) - - if created: - print("🎨 Created rack role", rack_role.name) diff --git a/startup_scripts/070_tenant_groups.py b/startup_scripts/070_tenant_groups.py new file mode 100644 index 0000000..65cf155 --- /dev/null +++ b/startup_scripts/070_tenant_groups.py @@ -0,0 +1,15 @@ +import sys + +from startup_script_utils import load_yaml +from tenancy.models import TenantGroup + +tenant_groups = load_yaml("/opt/netbox/initializers/tenant_groups.yml") + +if tenant_groups is None: + sys.exit() + +for params in tenant_groups: + tenant_group, created = TenantGroup.objects.get_or_create(**params) + + if created: + print("πŸ”³ Created Tenant Group", tenant_group.name) diff --git a/startup_scripts/075_locations.py b/startup_scripts/075_locations.py deleted file mode 100644 index d8a2c5a..0000000 --- a/startup_scripts/075_locations.py +++ /dev/null @@ -1,23 +0,0 @@ -import sys - -from dcim.models import Location, Site -from startup_script_utils import load_yaml - -rack_groups = load_yaml("/opt/netbox/initializers/locations.yml") - -if rack_groups is None: - sys.exit() - -required_assocs = {"site": (Site, "name")} - -for params in rack_groups: - - for assoc, details in required_assocs.items(): - model, field = details - query = {field: params.pop(assoc)} - params[assoc] = model.objects.get(**query) - - location, created = Location.objects.get_or_create(**params) - - if created: - print("🎨 Created location", location.name) diff --git a/startup_scripts/080_racks.py b/startup_scripts/080_racks.py deleted file mode 100644 index b2cfc80..0000000 --- a/startup_scripts/080_racks.py +++ /dev/null @@ -1,41 +0,0 @@ -import sys - -from dcim.models import Location, Rack, RackRole, Site -from startup_script_utils import load_yaml, pop_custom_fields, set_custom_fields_values -from tenancy.models import Tenant - -racks = load_yaml("/opt/netbox/initializers/racks.yml") - -if racks is None: - sys.exit() - -required_assocs = {"site": (Site, "name")} - -optional_assocs = { - "role": (RackRole, "name"), - "tenant": (Tenant, "name"), - "location": (Location, "name"), -} - -for params in racks: - custom_field_data = pop_custom_fields(params) - - for assoc, details in required_assocs.items(): - model, field = details - query = {field: params.pop(assoc)} - - params[assoc] = model.objects.get(**query) - - for assoc, details in optional_assocs.items(): - if assoc in params: - model, field = details - query = {field: params.pop(assoc)} - - params[assoc] = model.objects.get(**query) - - rack, created = Rack.objects.get_or_create(**params) - - if created: - set_custom_fields_values(rack, custom_field_data) - - print("πŸ”³ Created rack", rack.site, rack.name) diff --git a/startup_scripts/080_tenants.py b/startup_scripts/080_tenants.py new file mode 100644 index 0000000..7b1a629 --- /dev/null +++ b/startup_scripts/080_tenants.py @@ -0,0 +1,28 @@ +import sys + +from startup_script_utils import load_yaml, pop_custom_fields, set_custom_fields_values +from tenancy.models import Tenant, TenantGroup + +tenants = load_yaml("/opt/netbox/initializers/tenants.yml") + +if tenants is None: + sys.exit() + +optional_assocs = {"group": (TenantGroup, "name")} + +for params in tenants: + custom_field_data = pop_custom_fields(params) + + for assoc, details in optional_assocs.items(): + if assoc in params: + model, field = details + query = {field: params.pop(assoc)} + + params[assoc] = model.objects.get(**query) + + tenant, created = Tenant.objects.get_or_create(**params) + + if created: + set_custom_fields_values(tenant, custom_field_data) + + print("πŸ‘©β€πŸ’» Created Tenant", tenant.name) diff --git a/startup_scripts/090_device_roles.py b/startup_scripts/090_device_roles.py deleted file mode 100644 index 635acff..0000000 --- a/startup_scripts/090_device_roles.py +++ /dev/null @@ -1,24 +0,0 @@ -import sys - -from dcim.models import DeviceRole -from startup_script_utils import load_yaml -from utilities.choices import ColorChoices - -device_roles = load_yaml("/opt/netbox/initializers/device_roles.yml") - -if device_roles is None: - sys.exit() - -for params in device_roles: - - if "color" in params: - color = params.pop("color") - - for color_tpl in ColorChoices: - if color in color_tpl: - params["color"] = color_tpl[0] - - device_role, created = DeviceRole.objects.get_or_create(**params) - - if created: - print("🎨 Created device role", device_role.name) diff --git a/startup_scripts/090_regions.py b/startup_scripts/090_regions.py new file mode 100644 index 0000000..9d5c91f --- /dev/null +++ b/startup_scripts/090_regions.py @@ -0,0 +1,25 @@ +import sys + +from dcim.models import Region +from startup_script_utils import load_yaml + +regions = load_yaml("/opt/netbox/initializers/regions.yml") + +if regions is None: + sys.exit() + +optional_assocs = {"parent": (Region, "name")} + +for params in regions: + + for assoc, details in optional_assocs.items(): + if assoc in params: + model, field = details + query = {field: params.pop(assoc)} + + params[assoc] = model.objects.get(**query) + + region, created = Region.objects.get_or_create(**params) + + if created: + print("🌐 Created region", region.name) diff --git a/startup_scripts/100_platforms.py b/startup_scripts/100_platforms.py deleted file mode 100644 index 633b89f..0000000 --- a/startup_scripts/100_platforms.py +++ /dev/null @@ -1,27 +0,0 @@ -import sys - -from dcim.models import Manufacturer, Platform -from startup_script_utils import load_yaml - -platforms = load_yaml("/opt/netbox/initializers/platforms.yml") - -if platforms is None: - sys.exit() - -optional_assocs = { - "manufacturer": (Manufacturer, "name"), -} - -for params in platforms: - - for assoc, details in optional_assocs.items(): - if assoc in params: - model, field = details - query = {field: params.pop(assoc)} - - params[assoc] = model.objects.get(**query) - - platform, created = Platform.objects.get_or_create(**params) - - if created: - print("πŸ’Ύ Created platform", platform.name) diff --git a/startup_scripts/110_sites.py b/startup_scripts/110_sites.py new file mode 100644 index 0000000..f785139 --- /dev/null +++ b/startup_scripts/110_sites.py @@ -0,0 +1,29 @@ +import sys + +from dcim.models import Region, Site +from startup_script_utils import load_yaml, pop_custom_fields, set_custom_fields_values +from tenancy.models import Tenant + +sites = load_yaml("/opt/netbox/initializers/sites.yml") + +if sites is None: + sys.exit() + +optional_assocs = {"region": (Region, "name"), "tenant": (Tenant, "name")} + +for params in sites: + custom_field_data = pop_custom_fields(params) + + for assoc, details in optional_assocs.items(): + if assoc in params: + model, field = details + query = {field: params.pop(assoc)} + + params[assoc] = model.objects.get(**query) + + site, created = Site.objects.get_or_create(**params) + + if created: + set_custom_fields_values(site, custom_field_data) + + print("πŸ“ Created site", site.name) diff --git a/startup_scripts/120_locations.py b/startup_scripts/120_locations.py new file mode 100644 index 0000000..d8a2c5a --- /dev/null +++ b/startup_scripts/120_locations.py @@ -0,0 +1,23 @@ +import sys + +from dcim.models import Location, Site +from startup_script_utils import load_yaml + +rack_groups = load_yaml("/opt/netbox/initializers/locations.yml") + +if rack_groups is None: + sys.exit() + +required_assocs = {"site": (Site, "name")} + +for params in rack_groups: + + for assoc, details in required_assocs.items(): + model, field = details + query = {field: params.pop(assoc)} + params[assoc] = model.objects.get(**query) + + location, created = Location.objects.get_or_create(**params) + + if created: + print("🎨 Created location", location.name) diff --git a/startup_scripts/130_cluster_types.py b/startup_scripts/130_cluster_types.py deleted file mode 100644 index 9f361b1..0000000 --- a/startup_scripts/130_cluster_types.py +++ /dev/null @@ -1,15 +0,0 @@ -import sys - -from startup_script_utils import load_yaml -from virtualization.models import ClusterType - -cluster_types = load_yaml("/opt/netbox/initializers/cluster_types.yml") - -if cluster_types is None: - sys.exit() - -for params in cluster_types: - cluster_type, created = ClusterType.objects.get_or_create(**params) - - if created: - print("🧰 Created Cluster Type", cluster_type.name) diff --git a/startup_scripts/130_rack_roles.py b/startup_scripts/130_rack_roles.py new file mode 100644 index 0000000..5850405 --- /dev/null +++ b/startup_scripts/130_rack_roles.py @@ -0,0 +1,23 @@ +import sys + +from dcim.models import RackRole +from startup_script_utils import load_yaml +from utilities.choices import ColorChoices + +rack_roles = load_yaml("/opt/netbox/initializers/rack_roles.yml") + +if rack_roles is None: + sys.exit() + +for params in rack_roles: + if "color" in params: + color = params.pop("color") + + for color_tpl in ColorChoices: + if color in color_tpl: + params["color"] = color_tpl[0] + + rack_role, created = RackRole.objects.get_or_create(**params) + + if created: + print("🎨 Created rack role", rack_role.name) diff --git a/startup_scripts/135_cluster_groups.py b/startup_scripts/135_cluster_groups.py deleted file mode 100644 index fedd292..0000000 --- a/startup_scripts/135_cluster_groups.py +++ /dev/null @@ -1,15 +0,0 @@ -import sys - -from startup_script_utils import load_yaml -from virtualization.models import ClusterGroup - -cluster_groups = load_yaml("/opt/netbox/initializers/cluster_groups.yml") - -if cluster_groups is None: - sys.exit() - -for params in cluster_groups: - cluster_group, created = ClusterGroup.objects.get_or_create(**params) - - if created: - print("πŸ—„οΈ Created Cluster Group", cluster_group.name) diff --git a/startup_scripts/135_clusters.py b/startup_scripts/135_clusters.py deleted file mode 100644 index 2748f20..0000000 --- a/startup_scripts/135_clusters.py +++ /dev/null @@ -1,42 +0,0 @@ -import sys - -from dcim.models import Site -from startup_script_utils import load_yaml, pop_custom_fields, set_custom_fields_values -from tenancy.models import Tenant -from virtualization.models import Cluster, ClusterGroup, ClusterType - -clusters = load_yaml("/opt/netbox/initializers/clusters.yml") - -if clusters is None: - sys.exit() - -required_assocs = {"type": (ClusterType, "name")} - -optional_assocs = { - "site": (Site, "name"), - "group": (ClusterGroup, "name"), - "tenant": (Tenant, "name"), -} - -for params in clusters: - custom_field_data = pop_custom_fields(params) - - for assoc, details in required_assocs.items(): - model, field = details - query = {field: params.pop(assoc)} - - params[assoc] = model.objects.get(**query) - - for assoc, details in optional_assocs.items(): - if assoc in params: - model, field = details - query = {field: params.pop(assoc)} - - params[assoc] = model.objects.get(**query) - - cluster, created = Cluster.objects.get_or_create(**params) - - if created: - set_custom_fields_values(cluster, custom_field_data) - - print("πŸ—„οΈ Created cluster", cluster.name) diff --git a/startup_scripts/140_clusters.py b/startup_scripts/140_clusters.py deleted file mode 100644 index 2748f20..0000000 --- a/startup_scripts/140_clusters.py +++ /dev/null @@ -1,42 +0,0 @@ -import sys - -from dcim.models import Site -from startup_script_utils import load_yaml, pop_custom_fields, set_custom_fields_values -from tenancy.models import Tenant -from virtualization.models import Cluster, ClusterGroup, ClusterType - -clusters = load_yaml("/opt/netbox/initializers/clusters.yml") - -if clusters is None: - sys.exit() - -required_assocs = {"type": (ClusterType, "name")} - -optional_assocs = { - "site": (Site, "name"), - "group": (ClusterGroup, "name"), - "tenant": (Tenant, "name"), -} - -for params in clusters: - custom_field_data = pop_custom_fields(params) - - for assoc, details in required_assocs.items(): - model, field = details - query = {field: params.pop(assoc)} - - params[assoc] = model.objects.get(**query) - - for assoc, details in optional_assocs.items(): - if assoc in params: - model, field = details - query = {field: params.pop(assoc)} - - params[assoc] = model.objects.get(**query) - - cluster, created = Cluster.objects.get_or_create(**params) - - if created: - set_custom_fields_values(cluster, custom_field_data) - - print("πŸ—„οΈ Created cluster", cluster.name) diff --git a/startup_scripts/140_devices.py b/startup_scripts/140_devices.py deleted file mode 100644 index 423b7c9..0000000 --- a/startup_scripts/140_devices.py +++ /dev/null @@ -1,52 +0,0 @@ -import sys - -from dcim.models import Device, DeviceRole, DeviceType, Location, Platform, Rack, Site -from startup_script_utils import load_yaml, pop_custom_fields, set_custom_fields_values -from tenancy.models import Tenant -from virtualization.models import Cluster - -devices = load_yaml("/opt/netbox/initializers/devices.yml") - -if devices is None: - sys.exit() - -required_assocs = { - "device_role": (DeviceRole, "name"), - "device_type": (DeviceType, "model"), - "site": (Site, "name"), -} - -optional_assocs = { - "tenant": (Tenant, "name"), - "platform": (Platform, "name"), - "rack": (Rack, "name"), - "cluster": (Cluster, "name"), - "location": (Location, "name"), -} - -for params in devices: - custom_field_data = pop_custom_fields(params) - - # primary ips are handled later in `270_primary_ips.py` - params.pop("primary_ip4", None) - params.pop("primary_ip6", None) - - for assoc, details in required_assocs.items(): - model, field = details - query = {field: params.pop(assoc)} - - params[assoc] = model.objects.get(**query) - - for assoc, details in optional_assocs.items(): - if assoc in params: - model, field = details - query = {field: params.pop(assoc)} - - params[assoc] = model.objects.get(**query) - - device, created = Device.objects.get_or_create(**params) - - if created: - set_custom_fields_values(device, custom_field_data) - - print("πŸ–₯️ Created device", device.name) diff --git a/startup_scripts/140_racks.py b/startup_scripts/140_racks.py new file mode 100644 index 0000000..b2cfc80 --- /dev/null +++ b/startup_scripts/140_racks.py @@ -0,0 +1,41 @@ +import sys + +from dcim.models import Location, Rack, RackRole, Site +from startup_script_utils import load_yaml, pop_custom_fields, set_custom_fields_values +from tenancy.models import Tenant + +racks = load_yaml("/opt/netbox/initializers/racks.yml") + +if racks is None: + sys.exit() + +required_assocs = {"site": (Site, "name")} + +optional_assocs = { + "role": (RackRole, "name"), + "tenant": (Tenant, "name"), + "location": (Location, "name"), +} + +for params in racks: + custom_field_data = pop_custom_fields(params) + + for assoc, details in required_assocs.items(): + model, field = details + query = {field: params.pop(assoc)} + + params[assoc] = model.objects.get(**query) + + for assoc, details in optional_assocs.items(): + if assoc in params: + model, field = details + query = {field: params.pop(assoc)} + + params[assoc] = model.objects.get(**query) + + rack, created = Rack.objects.get_or_create(**params) + + if created: + set_custom_fields_values(rack, custom_field_data) + + print("πŸ”³ Created rack", rack.site, rack.name) diff --git a/startup_scripts/150_power_panels.py b/startup_scripts/150_power_panels.py new file mode 100644 index 0000000..8542435 --- /dev/null +++ b/startup_scripts/150_power_panels.py @@ -0,0 +1,36 @@ +import sys + +from dcim.models import Location, PowerPanel, Site +from startup_script_utils import load_yaml, pop_custom_fields, set_custom_fields_values + +power_panels = load_yaml("/opt/netbox/initializers/power_panels.yml") + +if power_panels is None: + sys.exit() + +required_assocs = {"site": (Site, "name")} + +optional_assocs = {"location": (Location, "name")} + +for params in power_panels: + custom_field_data = pop_custom_fields(params) + + for assoc, details in required_assocs.items(): + model, field = details + query = {field: params.pop(assoc)} + + params[assoc] = model.objects.get(**query) + + for assoc, details in optional_assocs.items(): + if assoc in params: + model, field = details + query = {field: params.pop(assoc)} + + params[assoc] = model.objects.get(**query) + + power_panel, created = PowerPanel.objects.get_or_create(**params) + + if created: + set_custom_fields_values(power_panel, custom_field_data) + + print("⚑ Created Power Panel", power_panel.site, power_panel.name) diff --git a/startup_scripts/150_rirs.py b/startup_scripts/150_rirs.py deleted file mode 100644 index 0e0df20..0000000 --- a/startup_scripts/150_rirs.py +++ /dev/null @@ -1,15 +0,0 @@ -import sys - -from ipam.models import RIR -from startup_script_utils import load_yaml - -rirs = load_yaml("/opt/netbox/initializers/rirs.yml") - -if rirs is None: - sys.exit() - -for params in rirs: - rir, created = RIR.objects.get_or_create(**params) - - if created: - print("πŸ—ΊοΈ Created RIR", rir.name) diff --git a/startup_scripts/160_aggregates.py b/startup_scripts/160_aggregates.py deleted file mode 100644 index c638e6f..0000000 --- a/startup_scripts/160_aggregates.py +++ /dev/null @@ -1,42 +0,0 @@ -import sys - -from ipam.models import RIR, Aggregate -from netaddr import IPNetwork -from startup_script_utils import load_yaml, pop_custom_fields, set_custom_fields_values -from tenancy.models import Tenant - -aggregates = load_yaml("/opt/netbox/initializers/aggregates.yml") - -if aggregates is None: - sys.exit() - -required_assocs = {"rir": (RIR, "name")} - -optional_assocs = { - "tenant": (Tenant, "name"), -} - -for params in aggregates: - custom_field_data = pop_custom_fields(params) - - params["prefix"] = IPNetwork(params["prefix"]) - - for assoc, details in required_assocs.items(): - model, field = details - query = {field: params.pop(assoc)} - - params[assoc] = model.objects.get(**query) - - for assoc, details in optional_assocs.items(): - if assoc in params: - model, field = details - query = {field: params.pop(assoc)} - - params[assoc] = model.objects.get(**query) - - aggregate, created = Aggregate.objects.get_or_create(**params) - - if created: - set_custom_fields_values(aggregate, custom_field_data) - - print("πŸ—žοΈ Created Aggregate", aggregate.prefix) diff --git a/startup_scripts/160_power_feeds.py b/startup_scripts/160_power_feeds.py new file mode 100644 index 0000000..f5aa5b5 --- /dev/null +++ b/startup_scripts/160_power_feeds.py @@ -0,0 +1,36 @@ +import sys + +from dcim.models import PowerFeed, PowerPanel, Rack +from startup_script_utils import load_yaml, pop_custom_fields, set_custom_fields_values + +power_feeds = load_yaml("/opt/netbox/initializers/power_feeds.yml") + +if power_feeds is None: + sys.exit() + +required_assocs = {"power_panel": (PowerPanel, "name")} + +optional_assocs = {"rack": (Rack, "name")} + +for params in power_feeds: + custom_field_data = pop_custom_fields(params) + + for assoc, details in required_assocs.items(): + model, field = details + query = {field: params.pop(assoc)} + + params[assoc] = model.objects.get(**query) + + for assoc, details in optional_assocs.items(): + if assoc in params: + model, field = details + query = {field: params.pop(assoc)} + + params[assoc] = model.objects.get(**query) + + power_feed, created = PowerFeed.objects.get_or_create(**params) + + if created: + set_custom_fields_values(power_feed, custom_field_data) + + print("⚑ Created Power Feed", power_feed.name) diff --git a/startup_scripts/165_cluster_groups.py b/startup_scripts/165_cluster_groups.py deleted file mode 100644 index fedd292..0000000 --- a/startup_scripts/165_cluster_groups.py +++ /dev/null @@ -1,15 +0,0 @@ -import sys - -from startup_script_utils import load_yaml -from virtualization.models import ClusterGroup - -cluster_groups = load_yaml("/opt/netbox/initializers/cluster_groups.yml") - -if cluster_groups is None: - sys.exit() - -for params in cluster_groups: - cluster_group, created = ClusterGroup.objects.get_or_create(**params) - - if created: - print("πŸ—„οΈ Created Cluster Group", cluster_group.name) diff --git a/startup_scripts/170_manufacturers.py b/startup_scripts/170_manufacturers.py new file mode 100644 index 0000000..d11b440 --- /dev/null +++ b/startup_scripts/170_manufacturers.py @@ -0,0 +1,15 @@ +import sys + +from dcim.models import Manufacturer +from startup_script_utils import load_yaml + +manufacturers = load_yaml("/opt/netbox/initializers/manufacturers.yml") + +if manufacturers is None: + sys.exit() + +for params in manufacturers: + manufacturer, created = Manufacturer.objects.get_or_create(**params) + + if created: + print("🏭 Created Manufacturer", manufacturer.name) diff --git a/startup_scripts/175_route_targets.py b/startup_scripts/175_route_targets.py deleted file mode 100644 index e1c8221..0000000 --- a/startup_scripts/175_route_targets.py +++ /dev/null @@ -1,29 +0,0 @@ -import sys - -from ipam.models import RouteTarget -from startup_script_utils import load_yaml, pop_custom_fields, set_custom_fields_values -from tenancy.models import Tenant - -route_targets = load_yaml("/opt/netbox/initializers/route_targets.yml") - -if route_targets is None: - sys.exit() - -optional_assocs = {"tenant": (Tenant, "name")} - -for params in route_targets: - custom_field_data = pop_custom_fields(params) - - for assoc, details in optional_assocs.items(): - if assoc in params: - model, field = details - query = {field: params.pop(assoc)} - - params[assoc] = model.objects.get(**query) - - route_target, created = RouteTarget.objects.get_or_create(**params) - - if created: - set_custom_fields_values(route_target, custom_field_data) - - print("🎯 Created Route Target", route_target.name) diff --git a/startup_scripts/180_device_roles.py b/startup_scripts/180_device_roles.py new file mode 100644 index 0000000..635acff --- /dev/null +++ b/startup_scripts/180_device_roles.py @@ -0,0 +1,24 @@ +import sys + +from dcim.models import DeviceRole +from startup_script_utils import load_yaml +from utilities.choices import ColorChoices + +device_roles = load_yaml("/opt/netbox/initializers/device_roles.yml") + +if device_roles is None: + sys.exit() + +for params in device_roles: + + if "color" in params: + color = params.pop("color") + + for color_tpl in ColorChoices: + if color in color_tpl: + params["color"] = color_tpl[0] + + device_role, created = DeviceRole.objects.get_or_create(**params) + + if created: + print("🎨 Created device role", device_role.name) diff --git a/startup_scripts/180_vrfs.py b/startup_scripts/180_vrfs.py deleted file mode 100644 index a67c8c8..0000000 --- a/startup_scripts/180_vrfs.py +++ /dev/null @@ -1,29 +0,0 @@ -import sys - -from ipam.models import VRF -from startup_script_utils import load_yaml, pop_custom_fields, set_custom_fields_values -from tenancy.models import Tenant - -vrfs = load_yaml("/opt/netbox/initializers/vrfs.yml") - -if vrfs is None: - sys.exit() - -optional_assocs = {"tenant": (Tenant, "name")} - -for params in vrfs: - custom_field_data = pop_custom_fields(params) - - for assoc, details in optional_assocs.items(): - if assoc in params: - model, field = details - query = {field: params.pop(assoc)} - - params[assoc] = model.objects.get(**query) - - vrf, created = VRF.objects.get_or_create(**params) - - if created: - set_custom_fields_values(vrf, custom_field_data) - - print("πŸ“¦ Created VRF", vrf.name) diff --git a/startup_scripts/190_device_types.py b/startup_scripts/190_device_types.py new file mode 100644 index 0000000..0d3050b --- /dev/null +++ b/startup_scripts/190_device_types.py @@ -0,0 +1,37 @@ +import sys + +from dcim.models import DeviceType, Manufacturer, Region +from startup_script_utils import load_yaml, pop_custom_fields, set_custom_fields_values +from tenancy.models import Tenant + +device_types = load_yaml("/opt/netbox/initializers/device_types.yml") + +if device_types is None: + sys.exit() + +required_assocs = {"manufacturer": (Manufacturer, "name")} + +optional_assocs = {"region": (Region, "name"), "tenant": (Tenant, "name")} + +for params in device_types: + custom_field_data = pop_custom_fields(params) + + for assoc, details in required_assocs.items(): + model, field = details + query = {field: params.pop(assoc)} + + params[assoc] = model.objects.get(**query) + + for assoc, details in optional_assocs.items(): + if assoc in params: + model, field = details + query = {field: params.pop(assoc)} + + params[assoc] = model.objects.get(**query) + + device_type, created = DeviceType.objects.get_or_create(**params) + + if created: + set_custom_fields_values(device_type, custom_field_data) + + print("πŸ”‘ Created device type", device_type.manufacturer, device_type.model) diff --git a/startup_scripts/190_prefix_vlan_roles.py b/startup_scripts/190_prefix_vlan_roles.py deleted file mode 100644 index ec359fb..0000000 --- a/startup_scripts/190_prefix_vlan_roles.py +++ /dev/null @@ -1,15 +0,0 @@ -import sys - -from ipam.models import Role -from startup_script_utils import load_yaml - -roles = load_yaml("/opt/netbox/initializers/prefix_vlan_roles.yml") - -if roles is None: - sys.exit() - -for params in roles: - role, created = Role.objects.get_or_create(**params) - - if created: - print("⛹️‍ Created Prefix/VLAN Role", role.name) diff --git a/startup_scripts/200_devices.py b/startup_scripts/200_devices.py new file mode 100644 index 0000000..423b7c9 --- /dev/null +++ b/startup_scripts/200_devices.py @@ -0,0 +1,52 @@ +import sys + +from dcim.models import Device, DeviceRole, DeviceType, Location, Platform, Rack, Site +from startup_script_utils import load_yaml, pop_custom_fields, set_custom_fields_values +from tenancy.models import Tenant +from virtualization.models import Cluster + +devices = load_yaml("/opt/netbox/initializers/devices.yml") + +if devices is None: + sys.exit() + +required_assocs = { + "device_role": (DeviceRole, "name"), + "device_type": (DeviceType, "model"), + "site": (Site, "name"), +} + +optional_assocs = { + "tenant": (Tenant, "name"), + "platform": (Platform, "name"), + "rack": (Rack, "name"), + "cluster": (Cluster, "name"), + "location": (Location, "name"), +} + +for params in devices: + custom_field_data = pop_custom_fields(params) + + # primary ips are handled later in `270_primary_ips.py` + params.pop("primary_ip4", None) + params.pop("primary_ip6", None) + + for assoc, details in required_assocs.items(): + model, field = details + query = {field: params.pop(assoc)} + + params[assoc] = model.objects.get(**query) + + for assoc, details in optional_assocs.items(): + if assoc in params: + model, field = details + query = {field: params.pop(assoc)} + + params[assoc] = model.objects.get(**query) + + device, created = Device.objects.get_or_create(**params) + + if created: + set_custom_fields_values(device, custom_field_data) + + print("πŸ–₯️ Created device", device.name) diff --git a/startup_scripts/200_vlan_groups.py b/startup_scripts/200_vlan_groups.py deleted file mode 100644 index 2a4a33d..0000000 --- a/startup_scripts/200_vlan_groups.py +++ /dev/null @@ -1,40 +0,0 @@ -import sys - -from django.contrib.contenttypes.models import ContentType -from ipam.models import VLANGroup -from startup_script_utils import load_yaml, pop_custom_fields, set_custom_fields_values - -vlan_groups = load_yaml("/opt/netbox/initializers/vlan_groups.yml") - -if vlan_groups is None: - sys.exit() - -optional_assocs = {"scope": (None, "name")} - -for params in vlan_groups: - custom_field_data = pop_custom_fields(params) - - for assoc, details in optional_assocs.items(): - if assoc in params: - model, field = details - query = {field: params.pop(assoc)} - # Get model from Contenttype - scope_type = params.pop("scope_type", None) - if not scope_type: - print(f"VLAN Group '{params['name']}': scope_type is missing from VLAN Group") - continue - app_label, model = str(scope_type).split(".") - ct = ContentType.objects.filter(app_label=app_label, model=model).first() - if not ct: - print( - f"VLAN Group '{params['name']}': ContentType for " - + f"app_label = '{app_label}' and model = '{model}' not found" - ) - continue - params["scope_id"] = ct.model_class().objects.get(**query).id - vlan_group, created = VLANGroup.objects.get_or_create(**params) - - if created: - set_custom_fields_values(vlan_group, custom_field_data) - - print("🏘️ Created VLAN Group", vlan_group.name) diff --git a/startup_scripts/210_dcim_interfaces.py b/startup_scripts/210_dcim_interfaces.py new file mode 100644 index 0000000..a802628 --- /dev/null +++ b/startup_scripts/210_dcim_interfaces.py @@ -0,0 +1,27 @@ +import sys + +from dcim.models import Device, Interface +from startup_script_utils import load_yaml, pop_custom_fields, set_custom_fields_values + +interfaces = load_yaml("/opt/netbox/initializers/dcim_interfaces.yml") + +if interfaces is None: + sys.exit() + +required_assocs = {"device": (Device, "name")} + +for params in interfaces: + custom_field_data = pop_custom_fields(params) + + for assoc, details in required_assocs.items(): + model, field = details + query = {field: params.pop(assoc)} + + params[assoc] = model.objects.get(**query) + + interface, created = Interface.objects.get_or_create(**params) + + if created: + set_custom_fields_values(interface, custom_field_data) + + print("🧷 Created interface", interface.name, interface.device.name) diff --git a/startup_scripts/210_vlans.py b/startup_scripts/210_vlans.py deleted file mode 100644 index e8ebb94..0000000 --- a/startup_scripts/210_vlans.py +++ /dev/null @@ -1,36 +0,0 @@ -import sys - -from dcim.models import Site -from ipam.models import VLAN, Role, VLANGroup -from startup_script_utils import load_yaml, pop_custom_fields, set_custom_fields_values -from tenancy.models import Tenant, TenantGroup - -vlans = load_yaml("/opt/netbox/initializers/vlans.yml") - -if vlans is None: - sys.exit() - -optional_assocs = { - "site": (Site, "name"), - "tenant": (Tenant, "name"), - "tenant_group": (TenantGroup, "name"), - "group": (VLANGroup, "name"), - "role": (Role, "name"), -} - -for params in vlans: - custom_field_data = pop_custom_fields(params) - - for assoc, details in optional_assocs.items(): - if assoc in params: - model, field = details - query = {field: params.pop(assoc)} - - params[assoc] = model.objects.get(**query) - - vlan, created = VLAN.objects.get_or_create(**params) - - if created: - set_custom_fields_values(vlan, custom_field_data) - - print("🏠 Created VLAN", vlan.name) diff --git a/startup_scripts/220_platforms.py b/startup_scripts/220_platforms.py new file mode 100644 index 0000000..633b89f --- /dev/null +++ b/startup_scripts/220_platforms.py @@ -0,0 +1,27 @@ +import sys + +from dcim.models import Manufacturer, Platform +from startup_script_utils import load_yaml + +platforms = load_yaml("/opt/netbox/initializers/platforms.yml") + +if platforms is None: + sys.exit() + +optional_assocs = { + "manufacturer": (Manufacturer, "name"), +} + +for params in platforms: + + for assoc, details in optional_assocs.items(): + if assoc in params: + model, field = details + query = {field: params.pop(assoc)} + + params[assoc] = model.objects.get(**query) + + platform, created = Platform.objects.get_or_create(**params) + + if created: + print("πŸ’Ύ Created platform", platform.name) diff --git a/startup_scripts/220_prefixes.py b/startup_scripts/220_prefixes.py deleted file mode 100644 index 4e2b0d0..0000000 --- a/startup_scripts/220_prefixes.py +++ /dev/null @@ -1,39 +0,0 @@ -import sys - -from dcim.models import Site -from ipam.models import VLAN, VRF, Prefix, Role -from netaddr import IPNetwork -from startup_script_utils import load_yaml, pop_custom_fields, set_custom_fields_values -from tenancy.models import Tenant, TenantGroup - -prefixes = load_yaml("/opt/netbox/initializers/prefixes.yml") - -if prefixes is None: - sys.exit() - -optional_assocs = { - "site": (Site, "name"), - "tenant": (Tenant, "name"), - "tenant_group": (TenantGroup, "name"), - "vlan": (VLAN, "name"), - "role": (Role, "name"), - "vrf": (VRF, "name"), -} - -for params in prefixes: - custom_field_data = pop_custom_fields(params) - - params["prefix"] = IPNetwork(params["prefix"]) - - for assoc, details in optional_assocs.items(): - if assoc in params: - model, field = details - query = {field: params.pop(assoc)} - params[assoc] = model.objects.get(**query) - - prefix, created = Prefix.objects.get_or_create(**params) - - if created: - set_custom_fields_values(prefix, custom_field_data) - - print("πŸ“Œ Created Prefix", prefix.prefix) diff --git a/startup_scripts/230_route_targets.py b/startup_scripts/230_route_targets.py new file mode 100644 index 0000000..e1c8221 --- /dev/null +++ b/startup_scripts/230_route_targets.py @@ -0,0 +1,29 @@ +import sys + +from ipam.models import RouteTarget +from startup_script_utils import load_yaml, pop_custom_fields, set_custom_fields_values +from tenancy.models import Tenant + +route_targets = load_yaml("/opt/netbox/initializers/route_targets.yml") + +if route_targets is None: + sys.exit() + +optional_assocs = {"tenant": (Tenant, "name")} + +for params in route_targets: + custom_field_data = pop_custom_fields(params) + + for assoc, details in optional_assocs.items(): + if assoc in params: + model, field = details + query = {field: params.pop(assoc)} + + params[assoc] = model.objects.get(**query) + + route_target, created = RouteTarget.objects.get_or_create(**params) + + if created: + set_custom_fields_values(route_target, custom_field_data) + + print("🎯 Created Route Target", route_target.name) diff --git a/startup_scripts/230_virtual_machines.py b/startup_scripts/230_virtual_machines.py deleted file mode 100644 index 2e3f428..0000000 --- a/startup_scripts/230_virtual_machines.py +++ /dev/null @@ -1,46 +0,0 @@ -import sys - -from dcim.models import DeviceRole, Platform -from startup_script_utils import load_yaml, pop_custom_fields, set_custom_fields_values -from tenancy.models import Tenant -from virtualization.models import Cluster, VirtualMachine - -virtual_machines = load_yaml("/opt/netbox/initializers/virtual_machines.yml") - -if virtual_machines is None: - sys.exit() - -required_assocs = {"cluster": (Cluster, "name")} - -optional_assocs = { - "tenant": (Tenant, "name"), - "platform": (Platform, "name"), - "role": (DeviceRole, "name"), -} - -for params in virtual_machines: - custom_field_data = pop_custom_fields(params) - - # primary ips are handled later in `270_primary_ips.py` - params.pop("primary_ip4", None) - params.pop("primary_ip6", None) - - for assoc, details in required_assocs.items(): - model, field = details - query = {field: params.pop(assoc)} - - params[assoc] = model.objects.get(**query) - - for assoc, details in optional_assocs.items(): - if assoc in params: - model, field = details - query = {field: params.pop(assoc)} - - params[assoc] = model.objects.get(**query) - - virtual_machine, created = VirtualMachine.objects.get_or_create(**params) - - if created: - set_custom_fields_values(virtual_machine, custom_field_data) - - print("πŸ–₯️ Created virtual machine", virtual_machine.name) diff --git a/startup_scripts/240_virtualization_interfaces.py b/startup_scripts/240_virtualization_interfaces.py deleted file mode 100644 index 6ee6347..0000000 --- a/startup_scripts/240_virtualization_interfaces.py +++ /dev/null @@ -1,27 +0,0 @@ -import sys - -from startup_script_utils import load_yaml, pop_custom_fields, set_custom_fields_values -from virtualization.models import VirtualMachine, VMInterface - -interfaces = load_yaml("/opt/netbox/initializers/virtualization_interfaces.yml") - -if interfaces is None: - sys.exit() - -required_assocs = {"virtual_machine": (VirtualMachine, "name")} - -for params in interfaces: - custom_field_data = pop_custom_fields(params) - - for assoc, details in required_assocs.items(): - model, field = details - query = {field: params.pop(assoc)} - - params[assoc] = model.objects.get(**query) - - interface, created = VMInterface.objects.get_or_create(**params) - - if created: - set_custom_fields_values(interface, custom_field_data) - - print("🧷 Created interface", interface.name, interface.virtual_machine.name) diff --git a/startup_scripts/240_vrfs.py b/startup_scripts/240_vrfs.py new file mode 100644 index 0000000..a67c8c8 --- /dev/null +++ b/startup_scripts/240_vrfs.py @@ -0,0 +1,29 @@ +import sys + +from ipam.models import VRF +from startup_script_utils import load_yaml, pop_custom_fields, set_custom_fields_values +from tenancy.models import Tenant + +vrfs = load_yaml("/opt/netbox/initializers/vrfs.yml") + +if vrfs is None: + sys.exit() + +optional_assocs = {"tenant": (Tenant, "name")} + +for params in vrfs: + custom_field_data = pop_custom_fields(params) + + for assoc, details in optional_assocs.items(): + if assoc in params: + model, field = details + query = {field: params.pop(assoc)} + + params[assoc] = model.objects.get(**query) + + vrf, created = VRF.objects.get_or_create(**params) + + if created: + set_custom_fields_values(vrf, custom_field_data) + + print("πŸ“¦ Created VRF", vrf.name) diff --git a/startup_scripts/250_dcim_interfaces.py b/startup_scripts/250_dcim_interfaces.py deleted file mode 100644 index a802628..0000000 --- a/startup_scripts/250_dcim_interfaces.py +++ /dev/null @@ -1,27 +0,0 @@ -import sys - -from dcim.models import Device, Interface -from startup_script_utils import load_yaml, pop_custom_fields, set_custom_fields_values - -interfaces = load_yaml("/opt/netbox/initializers/dcim_interfaces.yml") - -if interfaces is None: - sys.exit() - -required_assocs = {"device": (Device, "name")} - -for params in interfaces: - custom_field_data = pop_custom_fields(params) - - for assoc, details in required_assocs.items(): - model, field = details - query = {field: params.pop(assoc)} - - params[assoc] = model.objects.get(**query) - - interface, created = Interface.objects.get_or_create(**params) - - if created: - set_custom_fields_values(interface, custom_field_data) - - print("🧷 Created interface", interface.name, interface.device.name) diff --git a/startup_scripts/250_rirs.py b/startup_scripts/250_rirs.py new file mode 100644 index 0000000..0e0df20 --- /dev/null +++ b/startup_scripts/250_rirs.py @@ -0,0 +1,15 @@ +import sys + +from ipam.models import RIR +from startup_script_utils import load_yaml + +rirs = load_yaml("/opt/netbox/initializers/rirs.yml") + +if rirs is None: + sys.exit() + +for params in rirs: + rir, created = RIR.objects.get_or_create(**params) + + if created: + print("πŸ—ΊοΈ Created RIR", rir.name) diff --git a/startup_scripts/260_asns.py b/startup_scripts/260_asns.py new file mode 100644 index 0000000..893f3ba --- /dev/null +++ b/startup_scripts/260_asns.py @@ -0,0 +1,33 @@ +import sys + +from ipam.models import ASN, RIR +from startup_script_utils import load_yaml +from tenancy.models import Tenant + +asns = load_yaml("/opt/netbox/initializers/asns.yml") + +if asns is None: + sys.exit() + +required_assocs = {"rir": (RIR, "name")} + +optional_assocs = {"tenant": (Tenant, "name")} + +for params in asns: + for assoc, details in required_assocs.items(): + model, field = details + query = {field: params.pop(assoc)} + + params[assoc] = model.objects.get(**query) + + for assoc, details in optional_assocs.items(): + if assoc in params: + model, field = details + query = {field: params.pop(assoc)} + + params[assoc] = model.objects.get(**query) + + asn, created = ASN.objects.get_or_create(**params) + + if created: + print(f"πŸ”‘ Created ASN {asn.asn}") diff --git a/startup_scripts/260_ip_addresses.py b/startup_scripts/260_ip_addresses.py deleted file mode 100644 index 3f0aed0..0000000 --- a/startup_scripts/260_ip_addresses.py +++ /dev/null @@ -1,62 +0,0 @@ -import sys - -from dcim.models import Device, Interface -from django.contrib.contenttypes.models import ContentType -from django.db.models import Q -from ipam.models import VRF, IPAddress -from netaddr import IPNetwork -from startup_script_utils import load_yaml, pop_custom_fields, set_custom_fields_values -from tenancy.models import Tenant -from virtualization.models import VirtualMachine, VMInterface - -ip_addresses = load_yaml("/opt/netbox/initializers/ip_addresses.yml") - -if ip_addresses is None: - sys.exit() - -optional_assocs = { - "tenant": (Tenant, "name"), - "vrf": (VRF, "name"), - "interface": (None, None), -} - -vm_interface_ct = ContentType.objects.filter( - Q(app_label="virtualization", model="vminterface") -).first() -interface_ct = ContentType.objects.filter(Q(app_label="dcim", model="interface")).first() - -for params in ip_addresses: - custom_field_data = pop_custom_fields(params) - - vm = params.pop("virtual_machine", None) - device = params.pop("device", None) - params["address"] = IPNetwork(params["address"]) - - if vm and device: - print("IP Address can only specify one of the following: virtual_machine or device.") - sys.exit() - - for assoc, details in optional_assocs.items(): - if assoc in params: - model, field = details - if assoc == "interface": - if vm: - vm_id = VirtualMachine.objects.get(name=vm).id - query = {"name": params.pop(assoc), "virtual_machine_id": vm_id} - params["assigned_object_type"] = vm_interface_ct - params["assigned_object_id"] = VMInterface.objects.get(**query).id - elif device: - dev_id = Device.objects.get(name=device).id - query = {"name": params.pop(assoc), "device_id": dev_id} - params["assigned_object_type"] = interface_ct - params["assigned_object_id"] = Interface.objects.get(**query).id - else: - query = {field: params.pop(assoc)} - params[assoc] = model.objects.get(**query) - - ip_address, created = IPAddress.objects.get_or_create(**params) - - if created: - set_custom_fields_values(ip_address, custom_field_data) - - print("🧬 Created IP Address", ip_address.address) diff --git a/startup_scripts/270_aggregates.py b/startup_scripts/270_aggregates.py new file mode 100644 index 0000000..c638e6f --- /dev/null +++ b/startup_scripts/270_aggregates.py @@ -0,0 +1,42 @@ +import sys + +from ipam.models import RIR, Aggregate +from netaddr import IPNetwork +from startup_script_utils import load_yaml, pop_custom_fields, set_custom_fields_values +from tenancy.models import Tenant + +aggregates = load_yaml("/opt/netbox/initializers/aggregates.yml") + +if aggregates is None: + sys.exit() + +required_assocs = {"rir": (RIR, "name")} + +optional_assocs = { + "tenant": (Tenant, "name"), +} + +for params in aggregates: + custom_field_data = pop_custom_fields(params) + + params["prefix"] = IPNetwork(params["prefix"]) + + for assoc, details in required_assocs.items(): + model, field = details + query = {field: params.pop(assoc)} + + params[assoc] = model.objects.get(**query) + + for assoc, details in optional_assocs.items(): + if assoc in params: + model, field = details + query = {field: params.pop(assoc)} + + params[assoc] = model.objects.get(**query) + + aggregate, created = Aggregate.objects.get_or_create(**params) + + if created: + set_custom_fields_values(aggregate, custom_field_data) + + print("πŸ—žοΈ Created Aggregate", aggregate.prefix) diff --git a/startup_scripts/270_primary_ips.py b/startup_scripts/270_primary_ips.py deleted file mode 100644 index 11c3179..0000000 --- a/startup_scripts/270_primary_ips.py +++ /dev/null @@ -1,47 +0,0 @@ -import sys - -from dcim.models import Device -from ipam.models import IPAddress -from startup_script_utils import load_yaml -from virtualization.models import VirtualMachine - - -def link_primary_ip(assets, asset_model): - for params in assets: - primary_ip_fields = set(params) & {"primary_ip4", "primary_ip6"} - if not primary_ip_fields: - continue - - for assoc, details in optional_assocs.items(): - if assoc in params: - model, field = details - query = {field: params.pop(assoc)} - - try: - params[assoc] = model.objects.get(**query) - except model.DoesNotExist: - primary_ip_fields -= {assoc} - print(f"⚠️ IP Address '{query[field]}' not found") - - asset = asset_model.objects.get(name=params["name"]) - for field in primary_ip_fields: - if getattr(asset, field) != params[field]: - setattr(asset, field, params[field]) - print(f"πŸ”— Define primary IP '{params[field].address}' on '{asset.name}'") - asset.save() - - -devices = load_yaml("/opt/netbox/initializers/devices.yml") -virtual_machines = load_yaml("/opt/netbox/initializers/virtual_machines.yml") - -optional_assocs = { - "primary_ip4": (IPAddress, "address"), - "primary_ip6": (IPAddress, "address"), -} - -if devices is None and virtual_machines is None: - sys.exit() -if devices is not None: - link_primary_ip(devices, Device) -if virtual_machines is not None: - link_primary_ip(virtual_machines, VirtualMachine) diff --git a/startup_scripts/280_custom_links.py b/startup_scripts/280_custom_links.py deleted file mode 100644 index 40144bd..0000000 --- a/startup_scripts/280_custom_links.py +++ /dev/null @@ -1,33 +0,0 @@ -import sys - -from django.contrib.contenttypes.models import ContentType -from extras.models import CustomLink -from startup_script_utils import load_yaml - -custom_links = load_yaml("/opt/netbox/initializers/custom_links.yml") - -if custom_links is None: - sys.exit() - - -def get_content_type_id(content_type): - try: - return ContentType.objects.get(model=content_type).id - except ContentType.DoesNotExist: - pass - - -for link in custom_links: - content_type = link.pop("content_type") - link["content_type_id"] = get_content_type_id(content_type) - if link["content_type_id"] is None: - print( - "⚠️ Unable to create Custom Link '{0}': The content_type '{1}' is unknown".format( - link.get("name"), content_type - ) - ) - continue - - custom_link, created = CustomLink.objects.get_or_create(**link) - if created: - print("πŸ”— Created Custom Link '{0}'".format(custom_link.name)) diff --git a/startup_scripts/280_prefix_vlan_roles.py b/startup_scripts/280_prefix_vlan_roles.py new file mode 100644 index 0000000..ec359fb --- /dev/null +++ b/startup_scripts/280_prefix_vlan_roles.py @@ -0,0 +1,15 @@ +import sys + +from ipam.models import Role +from startup_script_utils import load_yaml + +roles = load_yaml("/opt/netbox/initializers/prefix_vlan_roles.yml") + +if roles is None: + sys.exit() + +for params in roles: + role, created = Role.objects.get_or_create(**params) + + if created: + print("⛹️‍ Created Prefix/VLAN Role", role.name) diff --git a/startup_scripts/280_providers.py b/startup_scripts/280_providers.py deleted file mode 100644 index 5c4330a..0000000 --- a/startup_scripts/280_providers.py +++ /dev/null @@ -1,19 +0,0 @@ -import sys - -from circuits.models import Provider -from startup_script_utils import load_yaml, pop_custom_fields, set_custom_fields_values - -providers = load_yaml("/opt/netbox/initializers/providers.yml") - -if providers is None: - sys.exit() - -for params in providers: - custom_field_data = pop_custom_fields(params) - - provider, created = Provider.objects.get_or_create(**params) - - if created: - set_custom_fields_values(provider, custom_field_data) - - print("πŸ“‘ Created provider", provider.name) diff --git a/startup_scripts/290_circuit_types.py b/startup_scripts/290_circuit_types.py deleted file mode 100644 index 071793c..0000000 --- a/startup_scripts/290_circuit_types.py +++ /dev/null @@ -1,19 +0,0 @@ -import sys - -from circuits.models import CircuitType -from startup_script_utils import load_yaml, pop_custom_fields, set_custom_fields_values - -circuit_types = load_yaml("/opt/netbox/initializers/circuit_types.yml") - -if circuit_types is None: - sys.exit() - -for params in circuit_types: - custom_field_data = pop_custom_fields(params) - - circuit_type, created = CircuitType.objects.get_or_create(**params) - - if created: - set_custom_fields_values(circuit_type, custom_field_data) - - print("⚑ Created Circuit Type", circuit_type.name) diff --git a/startup_scripts/290_cluster_types.py b/startup_scripts/290_cluster_types.py new file mode 100644 index 0000000..9f361b1 --- /dev/null +++ b/startup_scripts/290_cluster_types.py @@ -0,0 +1,15 @@ +import sys + +from startup_script_utils import load_yaml +from virtualization.models import ClusterType + +cluster_types = load_yaml("/opt/netbox/initializers/cluster_types.yml") + +if cluster_types is None: + sys.exit() + +for params in cluster_types: + cluster_type, created = ClusterType.objects.get_or_create(**params) + + if created: + print("🧰 Created Cluster Type", cluster_type.name) diff --git a/startup_scripts/290_webhooks.py b/startup_scripts/290_webhooks.py deleted file mode 100644 index 8787f5f..0000000 --- a/startup_scripts/290_webhooks.py +++ /dev/null @@ -1,34 +0,0 @@ -import sys - -from django.contrib.contenttypes.models import ContentType -from extras.models import Webhook -from startup_script_utils import load_yaml - -webhooks = load_yaml("/opt/netbox/initializers/webhooks.yml") - -if webhooks is None: - sys.exit() - - -def get_content_type_id(hook_name, content_type): - try: - return ContentType.objects.get(model=content_type).id - except ContentType.DoesNotExist as ex: - print("⚠️ Webhook '{0}': The object_type '{1}' is unknown.".format(hook_name, content_type)) - raise ex - - -for hook in webhooks: - obj_types = hook.pop("object_types") - - try: - obj_type_ids = [get_content_type_id(hook["name"], obj) for obj in obj_types] - except ContentType.DoesNotExist: - continue - - webhook, created = Webhook.objects.get_or_create(**hook) - if created: - webhook.content_types.set(obj_type_ids) - webhook.save() - - print("πŸͺ Created Webhook {0}".format(webhook.name)) diff --git a/startup_scripts/300_circuits.py b/startup_scripts/300_circuits.py deleted file mode 100644 index f82d3b7..0000000 --- a/startup_scripts/300_circuits.py +++ /dev/null @@ -1,37 +0,0 @@ -import sys - -from circuits.models import Circuit, CircuitType, Provider -from startup_script_utils import load_yaml, pop_custom_fields, set_custom_fields_values -from tenancy.models import Tenant - -circuits = load_yaml("/opt/netbox/initializers/circuits.yml") - -if circuits is None: - sys.exit() - -required_assocs = {"provider": (Provider, "name"), "type": (CircuitType, "name")} - -optional_assocs = {"tenant": (Tenant, "name")} - -for params in circuits: - custom_field_data = pop_custom_fields(params) - - for assoc, details in required_assocs.items(): - model, field = details - query = {field: params.pop(assoc)} - - params[assoc] = model.objects.get(**query) - - for assoc, details in optional_assocs.items(): - if assoc in params: - model, field = details - query = {field: params.pop(assoc)} - - params[assoc] = model.objects.get(**query) - - circuit, created = Circuit.objects.get_or_create(**params) - - if created: - set_custom_fields_values(circuit, custom_field_data) - - print("⚑ Created Circuit", circuit.cid) diff --git a/startup_scripts/300_cluster_groups.py b/startup_scripts/300_cluster_groups.py new file mode 100644 index 0000000..fedd292 --- /dev/null +++ b/startup_scripts/300_cluster_groups.py @@ -0,0 +1,15 @@ +import sys + +from startup_script_utils import load_yaml +from virtualization.models import ClusterGroup + +cluster_groups = load_yaml("/opt/netbox/initializers/cluster_groups.yml") + +if cluster_groups is None: + sys.exit() + +for params in cluster_groups: + cluster_group, created = ClusterGroup.objects.get_or_create(**params) + + if created: + print("πŸ—„οΈ Created Cluster Group", cluster_group.name) diff --git a/startup_scripts/310_clusters.py b/startup_scripts/310_clusters.py new file mode 100644 index 0000000..2748f20 --- /dev/null +++ b/startup_scripts/310_clusters.py @@ -0,0 +1,42 @@ +import sys + +from dcim.models import Site +from startup_script_utils import load_yaml, pop_custom_fields, set_custom_fields_values +from tenancy.models import Tenant +from virtualization.models import Cluster, ClusterGroup, ClusterType + +clusters = load_yaml("/opt/netbox/initializers/clusters.yml") + +if clusters is None: + sys.exit() + +required_assocs = {"type": (ClusterType, "name")} + +optional_assocs = { + "site": (Site, "name"), + "group": (ClusterGroup, "name"), + "tenant": (Tenant, "name"), +} + +for params in clusters: + custom_field_data = pop_custom_fields(params) + + for assoc, details in required_assocs.items(): + model, field = details + query = {field: params.pop(assoc)} + + params[assoc] = model.objects.get(**query) + + for assoc, details in optional_assocs.items(): + if assoc in params: + model, field = details + query = {field: params.pop(assoc)} + + params[assoc] = model.objects.get(**query) + + cluster, created = Cluster.objects.get_or_create(**params) + + if created: + set_custom_fields_values(cluster, custom_field_data) + + print("πŸ—„οΈ Created cluster", cluster.name) diff --git a/startup_scripts/320_services.py b/startup_scripts/320_services.py deleted file mode 100644 index a28eb09..0000000 --- a/startup_scripts/320_services.py +++ /dev/null @@ -1,30 +0,0 @@ -import sys - -from dcim.models import Device -from ipam.models import Service -from startup_script_utils import load_yaml -from virtualization.models import VirtualMachine - -services = load_yaml("/opt/netbox/initializers/services.yml") - -if services is None: - sys.exit() - -optional_assocs = { - "device": (Device, "name"), - "virtual_machine": (VirtualMachine, "name"), -} - -for params in services: - - for assoc, details in optional_assocs.items(): - if assoc in params: - model, field = details - query = {field: params.pop(assoc)} - - params[assoc] = model.objects.get(**query) - - service, created = Service.objects.get_or_create(**params) - - if created: - print("🧰 Created Service", service.name) diff --git a/startup_scripts/320_vlan_groups.py b/startup_scripts/320_vlan_groups.py new file mode 100644 index 0000000..2a4a33d --- /dev/null +++ b/startup_scripts/320_vlan_groups.py @@ -0,0 +1,40 @@ +import sys + +from django.contrib.contenttypes.models import ContentType +from ipam.models import VLANGroup +from startup_script_utils import load_yaml, pop_custom_fields, set_custom_fields_values + +vlan_groups = load_yaml("/opt/netbox/initializers/vlan_groups.yml") + +if vlan_groups is None: + sys.exit() + +optional_assocs = {"scope": (None, "name")} + +for params in vlan_groups: + custom_field_data = pop_custom_fields(params) + + for assoc, details in optional_assocs.items(): + if assoc in params: + model, field = details + query = {field: params.pop(assoc)} + # Get model from Contenttype + scope_type = params.pop("scope_type", None) + if not scope_type: + print(f"VLAN Group '{params['name']}': scope_type is missing from VLAN Group") + continue + app_label, model = str(scope_type).split(".") + ct = ContentType.objects.filter(app_label=app_label, model=model).first() + if not ct: + print( + f"VLAN Group '{params['name']}': ContentType for " + + f"app_label = '{app_label}' and model = '{model}' not found" + ) + continue + params["scope_id"] = ct.model_class().objects.get(**query).id + vlan_group, created = VLANGroup.objects.get_or_create(**params) + + if created: + set_custom_fields_values(vlan_group, custom_field_data) + + print("🏘️ Created VLAN Group", vlan_group.name) diff --git a/startup_scripts/330_power_panels.py b/startup_scripts/330_power_panels.py deleted file mode 100644 index 8542435..0000000 --- a/startup_scripts/330_power_panels.py +++ /dev/null @@ -1,36 +0,0 @@ -import sys - -from dcim.models import Location, PowerPanel, Site -from startup_script_utils import load_yaml, pop_custom_fields, set_custom_fields_values - -power_panels = load_yaml("/opt/netbox/initializers/power_panels.yml") - -if power_panels is None: - sys.exit() - -required_assocs = {"site": (Site, "name")} - -optional_assocs = {"location": (Location, "name")} - -for params in power_panels: - custom_field_data = pop_custom_fields(params) - - for assoc, details in required_assocs.items(): - model, field = details - query = {field: params.pop(assoc)} - - params[assoc] = model.objects.get(**query) - - for assoc, details in optional_assocs.items(): - if assoc in params: - model, field = details - query = {field: params.pop(assoc)} - - params[assoc] = model.objects.get(**query) - - power_panel, created = PowerPanel.objects.get_or_create(**params) - - if created: - set_custom_fields_values(power_panel, custom_field_data) - - print("⚑ Created Power Panel", power_panel.site, power_panel.name) diff --git a/startup_scripts/330_vlans.py b/startup_scripts/330_vlans.py new file mode 100644 index 0000000..e8ebb94 --- /dev/null +++ b/startup_scripts/330_vlans.py @@ -0,0 +1,36 @@ +import sys + +from dcim.models import Site +from ipam.models import VLAN, Role, VLANGroup +from startup_script_utils import load_yaml, pop_custom_fields, set_custom_fields_values +from tenancy.models import Tenant, TenantGroup + +vlans = load_yaml("/opt/netbox/initializers/vlans.yml") + +if vlans is None: + sys.exit() + +optional_assocs = { + "site": (Site, "name"), + "tenant": (Tenant, "name"), + "tenant_group": (TenantGroup, "name"), + "group": (VLANGroup, "name"), + "role": (Role, "name"), +} + +for params in vlans: + custom_field_data = pop_custom_fields(params) + + for assoc, details in optional_assocs.items(): + if assoc in params: + model, field = details + query = {field: params.pop(assoc)} + + params[assoc] = model.objects.get(**query) + + vlan, created = VLAN.objects.get_or_create(**params) + + if created: + set_custom_fields_values(vlan, custom_field_data) + + print("🏠 Created VLAN", vlan.name) diff --git a/startup_scripts/340_power_feeds.py b/startup_scripts/340_power_feeds.py deleted file mode 100644 index f5aa5b5..0000000 --- a/startup_scripts/340_power_feeds.py +++ /dev/null @@ -1,36 +0,0 @@ -import sys - -from dcim.models import PowerFeed, PowerPanel, Rack -from startup_script_utils import load_yaml, pop_custom_fields, set_custom_fields_values - -power_feeds = load_yaml("/opt/netbox/initializers/power_feeds.yml") - -if power_feeds is None: - sys.exit() - -required_assocs = {"power_panel": (PowerPanel, "name")} - -optional_assocs = {"rack": (Rack, "name")} - -for params in power_feeds: - custom_field_data = pop_custom_fields(params) - - for assoc, details in required_assocs.items(): - model, field = details - query = {field: params.pop(assoc)} - - params[assoc] = model.objects.get(**query) - - for assoc, details in optional_assocs.items(): - if assoc in params: - model, field = details - query = {field: params.pop(assoc)} - - params[assoc] = model.objects.get(**query) - - power_feed, created = PowerFeed.objects.get_or_create(**params) - - if created: - set_custom_fields_values(power_feed, custom_field_data) - - print("⚑ Created Power Feed", power_feed.name) diff --git a/startup_scripts/340_virtual_machines.py b/startup_scripts/340_virtual_machines.py new file mode 100644 index 0000000..2e3f428 --- /dev/null +++ b/startup_scripts/340_virtual_machines.py @@ -0,0 +1,46 @@ +import sys + +from dcim.models import DeviceRole, Platform +from startup_script_utils import load_yaml, pop_custom_fields, set_custom_fields_values +from tenancy.models import Tenant +from virtualization.models import Cluster, VirtualMachine + +virtual_machines = load_yaml("/opt/netbox/initializers/virtual_machines.yml") + +if virtual_machines is None: + sys.exit() + +required_assocs = {"cluster": (Cluster, "name")} + +optional_assocs = { + "tenant": (Tenant, "name"), + "platform": (Platform, "name"), + "role": (DeviceRole, "name"), +} + +for params in virtual_machines: + custom_field_data = pop_custom_fields(params) + + # primary ips are handled later in `270_primary_ips.py` + params.pop("primary_ip4", None) + params.pop("primary_ip6", None) + + for assoc, details in required_assocs.items(): + model, field = details + query = {field: params.pop(assoc)} + + params[assoc] = model.objects.get(**query) + + for assoc, details in optional_assocs.items(): + if assoc in params: + model, field = details + query = {field: params.pop(assoc)} + + params[assoc] = model.objects.get(**query) + + virtual_machine, created = VirtualMachine.objects.get_or_create(**params) + + if created: + set_custom_fields_values(virtual_machine, custom_field_data) + + print("πŸ–₯️ Created virtual machine", virtual_machine.name) diff --git a/startup_scripts/350_virtualization_interfaces.py b/startup_scripts/350_virtualization_interfaces.py new file mode 100644 index 0000000..6ee6347 --- /dev/null +++ b/startup_scripts/350_virtualization_interfaces.py @@ -0,0 +1,27 @@ +import sys + +from startup_script_utils import load_yaml, pop_custom_fields, set_custom_fields_values +from virtualization.models import VirtualMachine, VMInterface + +interfaces = load_yaml("/opt/netbox/initializers/virtualization_interfaces.yml") + +if interfaces is None: + sys.exit() + +required_assocs = {"virtual_machine": (VirtualMachine, "name")} + +for params in interfaces: + custom_field_data = pop_custom_fields(params) + + for assoc, details in required_assocs.items(): + model, field = details + query = {field: params.pop(assoc)} + + params[assoc] = model.objects.get(**query) + + interface, created = VMInterface.objects.get_or_create(**params) + + if created: + set_custom_fields_values(interface, custom_field_data) + + print("🧷 Created interface", interface.name, interface.virtual_machine.name) diff --git a/startup_scripts/360_prefixes.py b/startup_scripts/360_prefixes.py new file mode 100644 index 0000000..4e2b0d0 --- /dev/null +++ b/startup_scripts/360_prefixes.py @@ -0,0 +1,39 @@ +import sys + +from dcim.models import Site +from ipam.models import VLAN, VRF, Prefix, Role +from netaddr import IPNetwork +from startup_script_utils import load_yaml, pop_custom_fields, set_custom_fields_values +from tenancy.models import Tenant, TenantGroup + +prefixes = load_yaml("/opt/netbox/initializers/prefixes.yml") + +if prefixes is None: + sys.exit() + +optional_assocs = { + "site": (Site, "name"), + "tenant": (Tenant, "name"), + "tenant_group": (TenantGroup, "name"), + "vlan": (VLAN, "name"), + "role": (Role, "name"), + "vrf": (VRF, "name"), +} + +for params in prefixes: + custom_field_data = pop_custom_fields(params) + + params["prefix"] = IPNetwork(params["prefix"]) + + for assoc, details in optional_assocs.items(): + if assoc in params: + model, field = details + query = {field: params.pop(assoc)} + params[assoc] = model.objects.get(**query) + + prefix, created = Prefix.objects.get_or_create(**params) + + if created: + set_custom_fields_values(prefix, custom_field_data) + + print("πŸ“Œ Created Prefix", prefix.prefix) diff --git a/startup_scripts/370_ip_addresses.py b/startup_scripts/370_ip_addresses.py new file mode 100644 index 0000000..7f166f0 --- /dev/null +++ b/startup_scripts/370_ip_addresses.py @@ -0,0 +1,63 @@ +import sys + +from dcim.models import Device, Interface +from django.contrib.contenttypes.models import ContentType +from django.db.models import Q +from ipam.models import VRF, IPAddress +from netaddr import IPNetwork +from startup_script_utils import load_yaml, pop_custom_fields, set_custom_fields_values +from tenancy.models import Tenant +from virtualization.models import VirtualMachine, VMInterface + +ip_addresses = load_yaml("/opt/netbox/initializers/ip_addresses.yml") + +if ip_addresses is None: + sys.exit() + +optional_assocs = { + "tenant": (Tenant, "name"), + "vrf": (VRF, "name"), + "interface": (None, None), +} + +vm_interface_ct = ContentType.objects.filter( + Q(app_label="virtualization", model="vminterface") +).first() +interface_ct = ContentType.objects.filter(Q(app_label="dcim", model="interface")).first() + +for params in ip_addresses: + custom_field_data = pop_custom_fields(params) + + vm = params.pop("virtual_machine", None) + device = params.pop("device", None) + params["address"] = IPNetwork(params["address"]) + + if vm and device: + print("IP Address can only specify one of the following: virtual_machine or device.") + sys.exit() + + for assoc, details in optional_assocs.items(): + if assoc in params: + model, field = details + if assoc == "interface": + if vm: + vm_id = VirtualMachine.objects.get(name=vm).id + query = {"name": params.pop(assoc), "virtual_machine_id": vm_id} + params["assigned_object_type"] = vm_interface_ct + params["assigned_object_id"] = VMInterface.objects.get(**query).id + elif device: + dev_id = Device.objects.get(name=device).id + query = {"name": params.pop(assoc), "device_id": dev_id} + params["assigned_object_type"] = interface_ct + params["assigned_object_id"] = Interface.objects.get(**query).id + else: + query = {field: params.pop(assoc)} + + params[assoc] = model.objects.get(**query) + + ip_address, created = IPAddress.objects.get_or_create(**params) + + if created: + set_custom_fields_values(ip_address, custom_field_data) + + print("🧬 Created IP Address", ip_address.address) diff --git a/startup_scripts/380_primary_ips.py b/startup_scripts/380_primary_ips.py new file mode 100644 index 0000000..11c3179 --- /dev/null +++ b/startup_scripts/380_primary_ips.py @@ -0,0 +1,47 @@ +import sys + +from dcim.models import Device +from ipam.models import IPAddress +from startup_script_utils import load_yaml +from virtualization.models import VirtualMachine + + +def link_primary_ip(assets, asset_model): + for params in assets: + primary_ip_fields = set(params) & {"primary_ip4", "primary_ip6"} + if not primary_ip_fields: + continue + + for assoc, details in optional_assocs.items(): + if assoc in params: + model, field = details + query = {field: params.pop(assoc)} + + try: + params[assoc] = model.objects.get(**query) + except model.DoesNotExist: + primary_ip_fields -= {assoc} + print(f"⚠️ IP Address '{query[field]}' not found") + + asset = asset_model.objects.get(name=params["name"]) + for field in primary_ip_fields: + if getattr(asset, field) != params[field]: + setattr(asset, field, params[field]) + print(f"πŸ”— Define primary IP '{params[field].address}' on '{asset.name}'") + asset.save() + + +devices = load_yaml("/opt/netbox/initializers/devices.yml") +virtual_machines = load_yaml("/opt/netbox/initializers/virtual_machines.yml") + +optional_assocs = { + "primary_ip4": (IPAddress, "address"), + "primary_ip6": (IPAddress, "address"), +} + +if devices is None and virtual_machines is None: + sys.exit() +if devices is not None: + link_primary_ip(devices, Device) +if virtual_machines is not None: + link_primary_ip(virtual_machines, VirtualMachine) diff --git a/startup_scripts/400_services.py b/startup_scripts/400_services.py new file mode 100644 index 0000000..a28eb09 --- /dev/null +++ b/startup_scripts/400_services.py @@ -0,0 +1,30 @@ +import sys + +from dcim.models import Device +from ipam.models import Service +from startup_script_utils import load_yaml +from virtualization.models import VirtualMachine + +services = load_yaml("/opt/netbox/initializers/services.yml") + +if services is None: + sys.exit() + +optional_assocs = { + "device": (Device, "name"), + "virtual_machine": (VirtualMachine, "name"), +} + +for params in services: + + for assoc, details in optional_assocs.items(): + if assoc in params: + model, field = details + query = {field: params.pop(assoc)} + + params[assoc] = model.objects.get(**query) + + service, created = Service.objects.get_or_create(**params) + + if created: + print("🧰 Created Service", service.name) diff --git a/startup_scripts/420_providers.py b/startup_scripts/420_providers.py new file mode 100644 index 0000000..5c4330a --- /dev/null +++ b/startup_scripts/420_providers.py @@ -0,0 +1,19 @@ +import sys + +from circuits.models import Provider +from startup_script_utils import load_yaml, pop_custom_fields, set_custom_fields_values + +providers = load_yaml("/opt/netbox/initializers/providers.yml") + +if providers is None: + sys.exit() + +for params in providers: + custom_field_data = pop_custom_fields(params) + + provider, created = Provider.objects.get_or_create(**params) + + if created: + set_custom_fields_values(provider, custom_field_data) + + print("πŸ“‘ Created provider", provider.name) diff --git a/startup_scripts/440_circuit_types.py b/startup_scripts/440_circuit_types.py new file mode 100644 index 0000000..071793c --- /dev/null +++ b/startup_scripts/440_circuit_types.py @@ -0,0 +1,19 @@ +import sys + +from circuits.models import CircuitType +from startup_script_utils import load_yaml, pop_custom_fields, set_custom_fields_values + +circuit_types = load_yaml("/opt/netbox/initializers/circuit_types.yml") + +if circuit_types is None: + sys.exit() + +for params in circuit_types: + custom_field_data = pop_custom_fields(params) + + circuit_type, created = CircuitType.objects.get_or_create(**params) + + if created: + set_custom_fields_values(circuit_type, custom_field_data) + + print("⚑ Created Circuit Type", circuit_type.name) diff --git a/startup_scripts/450_circuits.py b/startup_scripts/450_circuits.py new file mode 100644 index 0000000..f82d3b7 --- /dev/null +++ b/startup_scripts/450_circuits.py @@ -0,0 +1,37 @@ +import sys + +from circuits.models import Circuit, CircuitType, Provider +from startup_script_utils import load_yaml, pop_custom_fields, set_custom_fields_values +from tenancy.models import Tenant + +circuits = load_yaml("/opt/netbox/initializers/circuits.yml") + +if circuits is None: + sys.exit() + +required_assocs = {"provider": (Provider, "name"), "type": (CircuitType, "name")} + +optional_assocs = {"tenant": (Tenant, "name")} + +for params in circuits: + custom_field_data = pop_custom_fields(params) + + for assoc, details in required_assocs.items(): + model, field = details + query = {field: params.pop(assoc)} + + params[assoc] = model.objects.get(**query) + + for assoc, details in optional_assocs.items(): + if assoc in params: + model, field = details + query = {field: params.pop(assoc)} + + params[assoc] = model.objects.get(**query) + + circuit, created = Circuit.objects.get_or_create(**params) + + if created: + set_custom_fields_values(circuit, custom_field_data) + + print("⚑ Created Circuit", circuit.cid)