diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 9297268..2369637 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -2,12 +2,12 @@ name: "CodeQL" on: push: - branches: [ "main" ] + branches: ["main"] pull_request: # The branches below must be a subset of the branches above - branches: [ "main" ] + branches: ["main"] schedule: - - cron: '38 4 * * 2' + - cron: "38 4 * * 2" jobs: analyze: @@ -20,15 +20,15 @@ jobs: strategy: fail-fast: false matrix: - language: [ 'python' ] + language: ["python"] steps: - - name: Checkout repository - uses: actions/checkout@v4 - - name: Initialize CodeQL - uses: github/codeql-action/init@v3 - with: - languages: ${{ matrix.language }} - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v3 - with: - category: "/language:${{matrix.language}}" + - name: Checkout repository + uses: actions/checkout@v4 + - name: Initialize CodeQL + uses: github/codeql-action/init@v3 + with: + languages: ${{ matrix.language }} + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v3 + with: + category: "/language:${{matrix.language}}" diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml index 39ed617..16efaaf 100644 --- a/.github/workflows/linter.yml +++ b/.github/workflows/linter.yml @@ -17,16 +17,20 @@ jobs: # list of changed files within `super-linter` fetch-depth: 0 - name: Lint Code Base - uses: github/super-linter@v5 + uses: github/super-linter@v7 env: DEFAULT_BRANCH: main GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SUPPRESS_POSSUM: true VALIDATE_ALL_CODEBASE: false + VALIDATE_CHECKOV: false + VALIDATE_JSCPD: false + VALIDATE_PYTHON_BLACK: false + VALIDATE_PYTHON_ISORT: false VALIDATE_PYTHON_MYPY: false + VALIDATE_PYTHON_PYINK: false + VALIDATE_PYTHON_PYLINT: false LINTER_RULES_PATH: / - PYTHON_BLACK_CONFIG_FILE: pyproject.toml FILTER_REGEX_EXCLUDE: (.*/)?(LICENSE) YAML_CONFIG_FILE: .yamllint.yaml PYTHON_FLAKE8_CONFIG_FILE: .flake8 - PYTHON_ISORT_CONFIG_FILE: pyproject.toml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a376cf6..b7f68f6 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -20,8 +20,17 @@ jobs: - id: git-checkout name: Checkout uses: actions/checkout@v4 + - uses: actions/setup-python@v4 + with: + python-version: "3.12" + - name: Install uv + run: pip install uv - id: build-and-publish name: Build and publish to pypi - uses: JRubics/poetry-publish@v2.0 - with: - pypi_token: ${{ secrets.PYPI_TOKEN }} + env: + TWINE_USERNAME: __token__ + TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }} + TWINE_NON_INTERACTIVE: "true" + run: | + uvx --from build pyproject-build + uvx twine upload dist/* diff --git a/README.md b/README.md index e4e1841..8565255 100644 --- a/README.md +++ b/README.md @@ -5,10 +5,13 @@ Load data from YAML files into Netbox ## Installation First activate your virtual environment where Netbox is installed, the install the plugin version correspondig to your Netbox version. + ```bash -pip install "netbox-initializers==4.0.*" +pip install "netbox-initializers==4.1.*" ``` + Then you need to add the plugin to the `PLUGINS` array in the Netbox configuration. + ```python PLUGINS = [ 'netbox_initializers', @@ -29,13 +32,12 @@ After you filled in the data you want to import, the import can be started with ./manage.py load_initializer_data --path /path/for/example/files ``` - ## Netbox Docker image The initializers where a part of the Docker image and where then extracted into a Netbox plugin. This was done to split the release cycle of the initializers and the image. To use the new plugin in a the Netbox Docker image, it musst be installad into the image. To this, the following example can be used as a starting point: ```dockerfile -FROM netboxcommunity/netbox:v4.0 -RUN /opt/netbox/venv/bin/pip install "netbox-initializers==4.0.*" +FROM netboxcommunity/netbox:v4.1 +RUN /opt/netbox/venv/bin/pip install "netbox-initializers==4.1.*" ``` diff --git a/docs/dev/Release.md b/docs/dev/Release.md index 6851c37..f29db66 100644 --- a/docs/dev/Release.md +++ b/docs/dev/Release.md @@ -12,7 +12,7 @@ Checkout the branch for which the release is to be build. If no branch exists fo ### Set version number -For patch releases the version number in `pyproject.toml` and the `NetBoxInitializersConfig` needs to be updated. If the release is for a new Netbox version additional changes need to be made in `README.md` and `Dockerfile` (for tests). +For patch releases the version number in `src/netbox_initializers/version.py` needs to be updated. If the release is for a new Netbox version additional changes need to be made in `README.md` and `Dockerfile` (for tests). ### Build the release automatically @@ -25,17 +25,17 @@ After changing the version numbers and committing them create a new release with Install the needed Python packages for the build: ```bash -pip install --upgrade poetry +pip install --upgrade uv ``` Then run the build for the wheel and source distributions: ```bash -poetry build +uvx --from build pyproject-build --installer uv ``` #### Upload packages to PyPi ```bash -poetry publish +uvx twine upload dist/* ``` diff --git a/pyproject.toml b/pyproject.toml index de16a09..553f1fc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,34 +1,49 @@ -[tool.poetry] -authors = ["Tobias Genannt "] +[project] +name = "netbox-initializers" +authors = [{ name = "Tobias Genannt", email = "tobias.genannt@gmail.com" }] classifiers = [ "Framework :: Django", "Environment :: Plugins", "Topic :: System :: Networking", - "Topic :: System :: Systems Administration" + "Topic :: System :: Systems Administration", ] description = "Load initial data into Netbox" -license = "Apache-2.0" -name = "netbox-initializers" readme = "README.md" repository = "https://github.com/tobiasge/netbox-initializers" -version = "4.0.0" +license = "Apache-2.0" +dynamic = ["version"] -[tool.poetry.dependencies] -python = "^3.8" -"ruamel.yaml" = "0.18.6" +requires-python = ">=3.10" +dependencies = ["ruamel-yaml>=0.18.6"] [build-system] -build-backend = "poetry.core.masonry.api" -requires = ["poetry-core"] +requires = ["hatchling"] +build-backend = "hatchling.build" + -[tool.black] -line_length = 100 -target-version = ['py310'] +[tool.hatch.version] +path = "src/netbox_initializers/version.py" -[tool.isort] -line_length = 100 -multi_line_output = 3 -profile = "black" +[tool.uv] +dev-dependencies = ["ruff==0.6.3"] + +[tool.ruff] +line-length = 100 +target-version = "py311" + +[tool.ruff.lint] +extend-select = ["I", "PL", "W191", "W291", "W292", "W293"] +ignore = ["PLR0912", "PLR0915"] + +[tool.ruff.lint.isort] +section-order = [ + "future", + "standard-library", + "third-party", + "first-party", + "local-folder", +] -[tool.pylint.format] -max-line-length = "100" +[tool.ruff.format] +docstring-code-format = true +docstring-code-line-length = "dynamic" diff --git a/src/netbox_initializers/__init__.py b/src/netbox_initializers/__init__.py index 2099aa0..d8f0437 100644 --- a/src/netbox_initializers/__init__.py +++ b/src/netbox_initializers/__init__.py @@ -1,14 +1,16 @@ from netbox.plugins import PluginConfig +from netbox_initializers.version import VERSION + class NetBoxInitializersConfig(PluginConfig): name = "netbox_initializers" verbose_name = "NetBox Initializers" description = "Load initial data into Netbox" - version = "4.0.0" + version = VERSION base_url = "initializers" - min_version = "4.0-beta1" - max_version = "4.0.99" + min_version = "4.1-beta1" + max_version = "4.1.99" config = NetBoxInitializersConfig diff --git a/src/netbox_initializers/initializers/__init__.py b/src/netbox_initializers/initializers/__init__.py index b7a2499..b4e185e 100644 --- a/src/netbox_initializers/initializers/__init__.py +++ b/src/netbox_initializers/initializers/__init__.py @@ -1,172 +1,4 @@ -from pathlib import Path -from typing import Tuple - -from core.models import ObjectType -from django.core.exceptions import ObjectDoesNotExist -from extras.models import CustomField, Tag -from ruamel.yaml import YAML - -INITIALIZER_ORDER = ( - "users", - "groups", - "object_permissions", - "custom_fields", - "custom_links", - "tags", - "config_templates", - "webhooks", - "tenant_groups", - "tenants", - "site_groups", - "regions", - "rirs", - "asns", - "sites", - "locations", - "rack_roles", - "racks", - "power_panels", - "power_feeds", - "manufacturers", - "platforms", - "device_roles", - "device_types", - "cluster_types", - "cluster_groups", - "clusters", - "prefix_vlan_roles", - "vlan_groups", - "vlans", - "devices", - "interfaces", - "route_targets", - "vrfs", - "aggregates", - "virtual_machines", - "virtualization_interfaces", - "prefixes", - "ip_addresses", - "primary_ips", - "services", - "service_templates", - "providers", - "circuit_types", - "circuits", - "cables", - "config_contexts", - "contact_groups", - "contact_roles", - "contacts", -) - -INITIALIZER_REGISTRY = dict() - - -class BaseInitializer: - # File name for import; Musst be set in subclass - data_file_name = "" - - def __init__(self, data_file_path: str) -> None: - self.data_file_path = data_file_path - - def load_data(self): - # Must be implemented by specific subclass - pass - - def load_yaml(self, data_file_name=None): - if data_file_name: - yf = Path(f"{self.data_file_path}/{data_file_name}") - else: - yf = Path(f"{self.data_file_path}/{self.data_file_name}") - if not yf.is_file(): - return None - with yf.open("r") as stream: - yaml = YAML(typ="safe") - return yaml.load(stream) - - def pop_custom_fields(self, params): - if "custom_field_data" in params: - return params.pop("custom_field_data") - elif "custom_fields" in params: - print("⚠️ Please rename 'custom_fields' to 'custom_field_data'!") - return params.pop("custom_fields") - - return None - - def set_custom_fields_values(self, entity, custom_field_data): - if not custom_field_data: - return - - missing_cfs = [] - save = False - for key, value in custom_field_data.items(): - try: - cf = CustomField.objects.get(name=key) - except ObjectDoesNotExist: - missing_cfs.append(key) - else: - ct = ObjectType.objects.get_for_model(entity) - if ct not in cf.object_types.all(): - print( - f"⚠️ Custom field {key} is not enabled for {entity}'s model!" - "Please check the 'on_objects' for that custom field in custom_fields.yml" - ) - elif key not in entity.custom_field_data: - entity.custom_field_data[key] = value - save = True - - if missing_cfs: - raise Exception( - f"⚠️ Custom field(s) '{missing_cfs}' requested for {entity} but not found in Netbox!" - "Please chceck the custom_fields.yml" - ) - - if save: - entity.save() - - def set_tags(self, entity, tags): - if not tags: - return - - if not hasattr(entity, "tags"): - raise Exception(f"⚠️ Tags cannot be applied to {entity}'s model") - - ct = ObjectType.objects.get_for_model(entity) - - save = False - for tag in Tag.objects.filter(name__in=tags): - restricted_cts = tag.object_types.all() - if restricted_cts and ct not in restricted_cts: - raise Exception(f"⚠️ Tag {tag} cannot be applied to {entity}'s model") - - entity.tags.add(tag) - save = True - - if save: - entity.save() - - def split_params(self, params: dict, unique_params: list = None) -> Tuple[dict, dict]: - """Split params dict into dict with matching params and a dict with default values""" - - if unique_params is None: - unique_params = ["name", "slug"] - - matching_params = {} - for unique_param in unique_params: - param = params.pop(unique_param, "__not_set__") - if param != "__not_set__": - matching_params[unique_param] = param - return matching_params, params - - -class InitializationError(Exception): - pass - - -def register_initializer(name: str, initializer): - INITIALIZER_REGISTRY[name] = initializer - - +# ruff: noqa: F401 # All initializers must be imported here, to be registered from .aggregates import AggregateInitializer from .asns import ASNInitializer @@ -200,6 +32,7 @@ def register_initializer(name: str, initializer): from .primary_ips import PrimaryIPInitializer from .providers import ProviderInitializer from .rack_roles import RackRoleInitializer +from .rack_types import RackTypeInitializer from .racks import RackInitializer from .regions import RegionInitializer from .rirs import RIRInitializer diff --git a/src/netbox_initializers/initializers/aggregates.py b/src/netbox_initializers/initializers/aggregates.py index 76d33c3..b9dc53b 100644 --- a/src/netbox_initializers/initializers/aggregates.py +++ b/src/netbox_initializers/initializers/aggregates.py @@ -2,7 +2,7 @@ from netaddr import IPNetwork from tenancy.models import Tenant -from . import BaseInitializer, register_initializer +from netbox_initializers.initializers.base import BaseInitializer, register_initializer MATCH_PARAMS = ["prefix", "rir"] REQUIRED_ASSOCS = {"rir": (RIR, "name")} diff --git a/src/netbox_initializers/initializers/asns.py b/src/netbox_initializers/initializers/asns.py index 02350e3..4442a04 100644 --- a/src/netbox_initializers/initializers/asns.py +++ b/src/netbox_initializers/initializers/asns.py @@ -1,7 +1,7 @@ from ipam.models import ASN, RIR from tenancy.models import Tenant -from . import BaseInitializer, register_initializer +from netbox_initializers.initializers.base import BaseInitializer, register_initializer MATCH_PARAMS = ["asn", "rir"] REQUIRED_ASSOCS = {"rir": (RIR, "name")} diff --git a/src/netbox_initializers/initializers/base.py b/src/netbox_initializers/initializers/base.py new file mode 100644 index 0000000..d7d659c --- /dev/null +++ b/src/netbox_initializers/initializers/base.py @@ -0,0 +1,170 @@ +from pathlib import Path +from typing import Tuple + +from core.models import ObjectType +from django.core.exceptions import ObjectDoesNotExist +from extras.models import CustomField, Tag +from ruamel.yaml import YAML + + +class BaseInitializer: + # File name for import; Musst be set in subclass + data_file_name = "" + + def __init__(self, data_file_path: str) -> None: + self.data_file_path = data_file_path + + def load_data(self): + # Must be implemented by specific subclass + pass + + def load_yaml(self, data_file_name=None): + if data_file_name: + yf = Path(f"{self.data_file_path}/{data_file_name}") + else: + yf = Path(f"{self.data_file_path}/{self.data_file_name}") + if not yf.is_file(): + return None + with yf.open("r") as stream: + yaml = YAML(typ="safe") + return yaml.load(stream) + + def pop_custom_fields(self, params): + if "custom_field_data" in params: + return params.pop("custom_field_data") + elif "custom_fields" in params: + print("⚠️ Please rename 'custom_fields' to 'custom_field_data'!") + return params.pop("custom_fields") + + return None + + def set_custom_fields_values(self, entity, custom_field_data): + if not custom_field_data: + return + + missing_cfs = [] + save = False + for key, value in custom_field_data.items(): + try: + cf = CustomField.objects.get(name=key) + except ObjectDoesNotExist: + missing_cfs.append(key) + else: + ct = ObjectType.objects.get_for_model(entity) + if ct not in cf.object_types.all(): + print( + f"⚠️ Custom field {key} is not enabled for {entity}'s model!" + "Please check the 'on_objects' for that custom field in custom_fields.yml" + ) + elif key not in entity.custom_field_data: + entity.custom_field_data[key] = value + save = True + + if missing_cfs: + raise Exception( + f"⚠️ Custom field(s) '{missing_cfs}' requested for {entity} but not found in Netbox!" + "Please chceck the custom_fields.yml" + ) + + if save: + entity.save() + + def set_tags(self, entity, tags): + if not tags: + return + + if not hasattr(entity, "tags"): + raise Exception(f"⚠️ Tags cannot be applied to {entity}'s model") + + ct = ObjectType.objects.get_for_model(entity) + + save = False + for tag in Tag.objects.filter(name__in=tags): + restricted_cts = tag.object_types.all() + if restricted_cts and ct not in restricted_cts: + raise Exception(f"⚠️ Tag {tag} cannot be applied to {entity}'s model") + + entity.tags.add(tag) + save = True + + if save: + entity.save() + + def split_params(self, params: dict, unique_params: list = None) -> Tuple[dict, dict]: + """Split params dict into dict with matching params and a dict with default values""" + + if unique_params is None: + unique_params = ["name", "slug"] + + matching_params = {} + for unique_param in unique_params: + param = params.pop(unique_param, "__not_set__") + if param != "__not_set__": + matching_params[unique_param] = param + return matching_params, params + + +class InitializationError(Exception): + pass + + +INITIALIZER_ORDER = ( + "users", + "groups", + "object_permissions", + "custom_fields", + "custom_links", + "tags", + "config_templates", + "webhooks", + "tenant_groups", + "tenants", + "site_groups", + "regions", + "rirs", + "asns", + "sites", + "locations", + "manufacturers", + "rack_roles", + "rack_types", + "racks", + "power_panels", + "power_feeds", + "platforms", + "device_roles", + "device_types", + "cluster_types", + "cluster_groups", + "clusters", + "prefix_vlan_roles", + "vlan_groups", + "vlans", + "devices", + "interfaces", + "route_targets", + "vrfs", + "aggregates", + "virtual_machines", + "virtualization_interfaces", + "prefixes", + "ip_addresses", + "primary_ips", + "services", + "service_templates", + "providers", + "circuit_types", + "circuits", + "cables", + "config_contexts", + "contact_groups", + "contact_roles", + "contacts", +) + + +INITIALIZER_REGISTRY = dict() + + +def register_initializer(name: str, initializer): + INITIALIZER_REGISTRY[name] = initializer diff --git a/src/netbox_initializers/initializers/cables.py b/src/netbox_initializers/initializers/cables.py index ef4f32e..5053a69 100644 --- a/src/netbox_initializers/initializers/cables.py +++ b/src/netbox_initializers/initializers/cables.py @@ -18,7 +18,7 @@ from django.contrib.contenttypes.models import ContentType from django.db.models import Q -from . import BaseInitializer, register_initializer +from netbox_initializers.initializers.base import BaseInitializer, register_initializer CONSOLE_PORT_TERMINATION = ContentType.objects.get_for_model(ConsolePort) CONSOLE_SERVER_PORT_TERMINATION = ContentType.objects.get_for_model(ConsoleServerPort) diff --git a/src/netbox_initializers/initializers/circuit_types.py b/src/netbox_initializers/initializers/circuit_types.py index 2e1aa3b..bdc5ef0 100644 --- a/src/netbox_initializers/initializers/circuit_types.py +++ b/src/netbox_initializers/initializers/circuit_types.py @@ -1,6 +1,6 @@ from circuits.models import CircuitType -from . import BaseInitializer, register_initializer +from netbox_initializers.initializers.base import BaseInitializer, register_initializer class CircuitTypeInitializer(BaseInitializer): diff --git a/src/netbox_initializers/initializers/circuits.py b/src/netbox_initializers/initializers/circuits.py index 125f17c..fa7f53c 100644 --- a/src/netbox_initializers/initializers/circuits.py +++ b/src/netbox_initializers/initializers/circuits.py @@ -1,7 +1,7 @@ from circuits.models import Circuit, CircuitType, Provider from tenancy.models import Tenant -from . import BaseInitializer, register_initializer +from netbox_initializers.initializers.base import BaseInitializer, register_initializer MATCH_PARAMS = ["cid", "provider", "type"] REQUIRED_ASSOCS = {"provider": (Provider, "name"), "type": (CircuitType, "name")} diff --git a/src/netbox_initializers/initializers/cluster_groups.py b/src/netbox_initializers/initializers/cluster_groups.py index f56490a..21b8f2a 100644 --- a/src/netbox_initializers/initializers/cluster_groups.py +++ b/src/netbox_initializers/initializers/cluster_groups.py @@ -1,6 +1,6 @@ from virtualization.models import ClusterGroup -from . import BaseInitializer, register_initializer +from netbox_initializers.initializers.base import BaseInitializer, register_initializer class ClusterGroupInitializer(BaseInitializer): diff --git a/src/netbox_initializers/initializers/cluster_types.py b/src/netbox_initializers/initializers/cluster_types.py index cd9d811..d66edba 100644 --- a/src/netbox_initializers/initializers/cluster_types.py +++ b/src/netbox_initializers/initializers/cluster_types.py @@ -1,6 +1,6 @@ from virtualization.models import ClusterType -from . import BaseInitializer, register_initializer +from netbox_initializers.initializers.base import BaseInitializer, register_initializer class ClusterTypesInitializer(BaseInitializer): diff --git a/src/netbox_initializers/initializers/clusters.py b/src/netbox_initializers/initializers/clusters.py index 46d9df9..328ffc0 100644 --- a/src/netbox_initializers/initializers/clusters.py +++ b/src/netbox_initializers/initializers/clusters.py @@ -2,7 +2,7 @@ from tenancy.models import Tenant from virtualization.models import Cluster, ClusterGroup, ClusterType -from . import BaseInitializer, register_initializer +from netbox_initializers.initializers.base import BaseInitializer, register_initializer MATCH_PARAMS = ["name", "type"] REQUIRED_ASSOCS = {"type": (ClusterType, "name")} diff --git a/src/netbox_initializers/initializers/config_contexts.py b/src/netbox_initializers/initializers/config_contexts.py index 36eacde..30b90f4 100644 --- a/src/netbox_initializers/initializers/config_contexts.py +++ b/src/netbox_initializers/initializers/config_contexts.py @@ -3,7 +3,7 @@ from tenancy import models as tenancy from virtualization import models as virtualization -from . import BaseInitializer, register_initializer +from netbox_initializers.initializers.base import BaseInitializer, register_initializer MATCH_PARAMS = ["name"] OPTIONAL_MANY_ASSOCS = { diff --git a/src/netbox_initializers/initializers/config_templates.py b/src/netbox_initializers/initializers/config_templates.py index b82c237..1c25058 100644 --- a/src/netbox_initializers/initializers/config_templates.py +++ b/src/netbox_initializers/initializers/config_templates.py @@ -1,7 +1,7 @@ from django.contrib.contenttypes.models import ContentType from extras.models import ConfigTemplate -from . import BaseInitializer, register_initializer +from netbox_initializers.initializers.base import BaseInitializer, register_initializer MATCH_PARAMS = ["name", "description", "template_code", "environment_params"] diff --git a/src/netbox_initializers/initializers/contact_groups.py b/src/netbox_initializers/initializers/contact_groups.py index fc0a88a..4433c8a 100644 --- a/src/netbox_initializers/initializers/contact_groups.py +++ b/src/netbox_initializers/initializers/contact_groups.py @@ -1,6 +1,6 @@ from tenancy.models import ContactGroup -from . import BaseInitializer, register_initializer +from netbox_initializers.initializers.base import BaseInitializer, register_initializer OPTIONAL_ASSOCS = {"parent": (ContactGroup, "name")} diff --git a/src/netbox_initializers/initializers/contact_roles.py b/src/netbox_initializers/initializers/contact_roles.py index a43316f..314c5a5 100644 --- a/src/netbox_initializers/initializers/contact_roles.py +++ b/src/netbox_initializers/initializers/contact_roles.py @@ -1,6 +1,6 @@ from tenancy.models import ContactRole -from . import BaseInitializer, register_initializer +from netbox_initializers.initializers.base import BaseInitializer, register_initializer class ContactRoleInitializer(BaseInitializer): diff --git a/src/netbox_initializers/initializers/contacts.py b/src/netbox_initializers/initializers/contacts.py index 64ce5c1..fa71bd4 100644 --- a/src/netbox_initializers/initializers/contacts.py +++ b/src/netbox_initializers/initializers/contacts.py @@ -1,6 +1,6 @@ from tenancy.models import Contact, ContactGroup -from . import BaseInitializer, register_initializer +from netbox_initializers.initializers.base import BaseInitializer, register_initializer OPTIONAL_ASSOCS = {"group": (ContactGroup, "name")} diff --git a/src/netbox_initializers/initializers/custom_fields.py b/src/netbox_initializers/initializers/custom_fields.py index 7fa8307..4bc8724 100644 --- a/src/netbox_initializers/initializers/custom_fields.py +++ b/src/netbox_initializers/initializers/custom_fields.py @@ -1,6 +1,6 @@ from extras.models import CustomField, CustomFieldChoiceSet -from . import BaseInitializer, register_initializer +from netbox_initializers.initializers.base import BaseInitializer, register_initializer def get_class_for_class_path(class_path): diff --git a/src/netbox_initializers/initializers/custom_links.py b/src/netbox_initializers/initializers/custom_links.py index 7b149f1..d9795fd 100644 --- a/src/netbox_initializers/initializers/custom_links.py +++ b/src/netbox_initializers/initializers/custom_links.py @@ -1,7 +1,7 @@ from core.models import ObjectType from extras.models import CustomLink -from . import BaseInitializer, register_initializer +from netbox_initializers.initializers.base import BaseInitializer, register_initializer def get_content_type(content_type): diff --git a/src/netbox_initializers/initializers/device_roles.py b/src/netbox_initializers/initializers/device_roles.py index 544b49a..af961a5 100644 --- a/src/netbox_initializers/initializers/device_roles.py +++ b/src/netbox_initializers/initializers/device_roles.py @@ -1,7 +1,7 @@ from dcim.models import DeviceRole from netbox.choices import ColorChoices -from . import BaseInitializer, register_initializer +from netbox_initializers.initializers.base import BaseInitializer, register_initializer class DeviceRoleInitializer(BaseInitializer): diff --git a/src/netbox_initializers/initializers/device_types.py b/src/netbox_initializers/initializers/device_types.py index 7ea87d5..c946058 100644 --- a/src/netbox_initializers/initializers/device_types.py +++ b/src/netbox_initializers/initializers/device_types.py @@ -14,7 +14,7 @@ from tenancy.models import Tenant from utilities.forms.utils import expand_alphanumeric_pattern -from . import BaseInitializer, register_initializer +from netbox_initializers.initializers.base import BaseInitializer, register_initializer MATCH_PARAMS = ["manufacturer", "model", "slug"] REQUIRED_ASSOCS = {"manufacturer": (Manufacturer, "name")} diff --git a/src/netbox_initializers/initializers/devices.py b/src/netbox_initializers/initializers/devices.py index c73a925..40025dd 100644 --- a/src/netbox_initializers/initializers/devices.py +++ b/src/netbox_initializers/initializers/devices.py @@ -3,7 +3,7 @@ from tenancy.models import Tenant from virtualization.models import Cluster -from . import BaseInitializer, register_initializer +from netbox_initializers.initializers.base import BaseInitializer, register_initializer MATCH_PARAMS = ["device_type", "name", "site"] REQUIRED_ASSOCS = { diff --git a/src/netbox_initializers/initializers/groups.py b/src/netbox_initializers/initializers/groups.py index 7280d66..d70363c 100644 --- a/src/netbox_initializers/initializers/groups.py +++ b/src/netbox_initializers/initializers/groups.py @@ -1,6 +1,6 @@ from users.models import Group, User -from . import BaseInitializer, register_initializer +from netbox_initializers.initializers.base import BaseInitializer, register_initializer class GroupInitializer(BaseInitializer): diff --git a/src/netbox_initializers/initializers/interfaces.py b/src/netbox_initializers/initializers/interfaces.py index 81f226a..c3fcb36 100644 --- a/src/netbox_initializers/initializers/interfaces.py +++ b/src/netbox_initializers/initializers/interfaces.py @@ -1,7 +1,7 @@ from dcim.models import Device, Interface from ipam.models import VLAN -from . import BaseInitializer, register_initializer +from netbox_initializers.initializers.base import BaseInitializer, register_initializer MATCH_PARAMS = ["device", "name"] REQUIRED_ASSOCS = {"device": (Device, "name")} diff --git a/src/netbox_initializers/initializers/ip_addresses.py b/src/netbox_initializers/initializers/ip_addresses.py index db67b8f..6be8a23 100644 --- a/src/netbox_initializers/initializers/ip_addresses.py +++ b/src/netbox_initializers/initializers/ip_addresses.py @@ -6,7 +6,11 @@ from tenancy.models import Tenant from virtualization.models import VirtualMachine, VMInterface -from . import BaseInitializer, InitializationError, register_initializer +from netbox_initializers.initializers.base import ( + BaseInitializer, + InitializationError, + register_initializer, +) MATCH_PARAMS = ["address", "vrf", "vrf_id", "assigned_object_id", "assigned_object_type"] OPTIONAL_ASSOCS = { diff --git a/src/netbox_initializers/initializers/locations.py b/src/netbox_initializers/initializers/locations.py index 30ffce6..f35c050 100644 --- a/src/netbox_initializers/initializers/locations.py +++ b/src/netbox_initializers/initializers/locations.py @@ -1,6 +1,6 @@ from dcim.models import Location, Site -from . import BaseInitializer, register_initializer +from netbox_initializers.initializers.base import BaseInitializer, register_initializer OPTIONAL_ASSOCS = {"site": (Site, "name"), "parent": (Location, "name")} diff --git a/src/netbox_initializers/initializers/manufacturers.py b/src/netbox_initializers/initializers/manufacturers.py index 820ee9f..394e3a6 100644 --- a/src/netbox_initializers/initializers/manufacturers.py +++ b/src/netbox_initializers/initializers/manufacturers.py @@ -1,6 +1,6 @@ from dcim.models import Manufacturer -from . import BaseInitializer, register_initializer +from netbox_initializers.initializers.base import BaseInitializer, register_initializer class ManufacturerInitializer(BaseInitializer): diff --git a/src/netbox_initializers/initializers/object_permissions.py b/src/netbox_initializers/initializers/object_permissions.py index 3ad2a5b..606c0aa 100644 --- a/src/netbox_initializers/initializers/object_permissions.py +++ b/src/netbox_initializers/initializers/object_permissions.py @@ -1,7 +1,7 @@ from core.models import ObjectType from users.models import Group, ObjectPermission, User -from . import BaseInitializer, register_initializer +from netbox_initializers.initializers.base import BaseInitializer, register_initializer class ObjectPermissionInitializer(BaseInitializer): diff --git a/src/netbox_initializers/initializers/platforms.py b/src/netbox_initializers/initializers/platforms.py index 092c29b..6bcb069 100644 --- a/src/netbox_initializers/initializers/platforms.py +++ b/src/netbox_initializers/initializers/platforms.py @@ -1,7 +1,7 @@ from dcim.models import Manufacturer, Platform from extras.models import ConfigTemplate -from . import BaseInitializer, register_initializer +from netbox_initializers.initializers.base import BaseInitializer, register_initializer OPTIONAL_ASSOCS = { "manufacturer": (Manufacturer, "name"), diff --git a/src/netbox_initializers/initializers/power_feeds.py b/src/netbox_initializers/initializers/power_feeds.py index 6badd0e..e85018f 100644 --- a/src/netbox_initializers/initializers/power_feeds.py +++ b/src/netbox_initializers/initializers/power_feeds.py @@ -1,6 +1,6 @@ from dcim.models import PowerFeed, PowerPanel, Rack -from . import BaseInitializer, register_initializer +from netbox_initializers.initializers.base import BaseInitializer, register_initializer MATCH_PARAMS = ["name", "power_panel"] OPTIONAL_ASSOCS = {"rack": (Rack, "name")} diff --git a/src/netbox_initializers/initializers/power_panels.py b/src/netbox_initializers/initializers/power_panels.py index 89b92e7..60119a0 100644 --- a/src/netbox_initializers/initializers/power_panels.py +++ b/src/netbox_initializers/initializers/power_panels.py @@ -1,6 +1,6 @@ from dcim.models import Location, PowerPanel, Site -from . import BaseInitializer, register_initializer +from netbox_initializers.initializers.base import BaseInitializer, register_initializer MATCH_PARAMS = ["name", "site"] REQUIRED_ASSOCS = {"site": (Site, "name")} diff --git a/src/netbox_initializers/initializers/prefix_vlan_roles.py b/src/netbox_initializers/initializers/prefix_vlan_roles.py index 9bf0470..46be77f 100644 --- a/src/netbox_initializers/initializers/prefix_vlan_roles.py +++ b/src/netbox_initializers/initializers/prefix_vlan_roles.py @@ -1,6 +1,6 @@ from ipam.models import Role -from . import BaseInitializer, register_initializer +from netbox_initializers.initializers.base import BaseInitializer, register_initializer class RoleInitializer(BaseInitializer): diff --git a/src/netbox_initializers/initializers/prefixes.py b/src/netbox_initializers/initializers/prefixes.py index b4a435f..cdbada2 100644 --- a/src/netbox_initializers/initializers/prefixes.py +++ b/src/netbox_initializers/initializers/prefixes.py @@ -3,7 +3,7 @@ from netaddr import IPNetwork from tenancy.models import Tenant, TenantGroup -from . import BaseInitializer, register_initializer +from netbox_initializers.initializers.base import BaseInitializer, register_initializer MATCH_PARAMS = ["prefix", "site", "vrf", "vlan"] OPTIONAL_ASSOCS = { diff --git a/src/netbox_initializers/initializers/primary_ips.py b/src/netbox_initializers/initializers/primary_ips.py index 8f576bc..e9f6c40 100644 --- a/src/netbox_initializers/initializers/primary_ips.py +++ b/src/netbox_initializers/initializers/primary_ips.py @@ -2,7 +2,7 @@ from ipam.models import VRF, IPAddress from virtualization.models import VirtualMachine -from . import BaseInitializer, register_initializer +from netbox_initializers.initializers.base import BaseInitializer, register_initializer OPTIONAL_ASSOCS = { "primary_ip4": (IPAddress, "address"), diff --git a/src/netbox_initializers/initializers/providers.py b/src/netbox_initializers/initializers/providers.py index 31245f9..bcc050d 100644 --- a/src/netbox_initializers/initializers/providers.py +++ b/src/netbox_initializers/initializers/providers.py @@ -1,7 +1,7 @@ from circuits.models import Provider from ipam.models import ASN -from . import BaseInitializer, register_initializer +from netbox_initializers.initializers.base import BaseInitializer, register_initializer class ProviderInitializer(BaseInitializer): diff --git a/src/netbox_initializers/initializers/rack_roles.py b/src/netbox_initializers/initializers/rack_roles.py index bdbbc6d..d35f7a5 100644 --- a/src/netbox_initializers/initializers/rack_roles.py +++ b/src/netbox_initializers/initializers/rack_roles.py @@ -1,7 +1,7 @@ from dcim.models import RackRole from netbox.choices import ColorChoices -from . import BaseInitializer, register_initializer +from netbox_initializers.initializers.base import BaseInitializer, register_initializer class RackRoleInitializer(BaseInitializer): diff --git a/src/netbox_initializers/initializers/rack_types.py b/src/netbox_initializers/initializers/rack_types.py new file mode 100644 index 0000000..87c9d11 --- /dev/null +++ b/src/netbox_initializers/initializers/rack_types.py @@ -0,0 +1,32 @@ +from dcim.models import Manufacturer, RackType + +from netbox_initializers.initializers.base import BaseInitializer, register_initializer + +MATCH_PARAMS = ["slug"] +REQUIRED_ASSOCS = {"manufacturer": (Manufacturer, "slug")} + + +class RackTypeInitializer(BaseInitializer): + data_file_name = "rack_types.yml" + + def load_data(self): + rack_types = self.load_yaml() + if rack_types is None: + return + for params in rack_types: + for assoc, details in REQUIRED_ASSOCS.items(): + model, field = details + query = {field: params.pop(assoc)} + + params[assoc] = model.objects.get(**query) + + matching_params, defaults = self.split_params(params, MATCH_PARAMS) + rack_type, created = RackType.objects.get_or_create( + **matching_params, defaults=defaults + ) + + if created: + print("🔳 Created rack type", rack_type.model) + + +register_initializer("rack_types", RackTypeInitializer) diff --git a/src/netbox_initializers/initializers/racks.py b/src/netbox_initializers/initializers/racks.py index 3cb3ae3..60fbd44 100644 --- a/src/netbox_initializers/initializers/racks.py +++ b/src/netbox_initializers/initializers/racks.py @@ -1,7 +1,7 @@ -from dcim.models import Location, Rack, RackRole, Site +from dcim.models import Location, Rack, RackRole, RackType, Site from tenancy.models import Tenant -from . import BaseInitializer, register_initializer +from netbox_initializers.initializers.base import BaseInitializer, register_initializer MATCH_PARAMS = ["name", "site"] REQUIRED_ASSOCS = {"site": (Site, "name")} @@ -9,6 +9,7 @@ "role": (RackRole, "name"), "tenant": (Tenant, "name"), "location": (Location, "name"), + "rack_type": (RackType, "slug"), } diff --git a/src/netbox_initializers/initializers/regions.py b/src/netbox_initializers/initializers/regions.py index d6c8e28..a66b1ab 100644 --- a/src/netbox_initializers/initializers/regions.py +++ b/src/netbox_initializers/initializers/regions.py @@ -1,6 +1,6 @@ from dcim.models import Region -from . import BaseInitializer, register_initializer +from netbox_initializers.initializers.base import BaseInitializer, register_initializer OPTIONAL_ASSOCS = {"parent": (Region, "name")} diff --git a/src/netbox_initializers/initializers/rirs.py b/src/netbox_initializers/initializers/rirs.py index 69532f3..e0b2248 100644 --- a/src/netbox_initializers/initializers/rirs.py +++ b/src/netbox_initializers/initializers/rirs.py @@ -1,6 +1,6 @@ from ipam.models import RIR -from . import BaseInitializer, register_initializer +from netbox_initializers.initializers.base import BaseInitializer, register_initializer class RIRInitializer(BaseInitializer): diff --git a/src/netbox_initializers/initializers/route_targets.py b/src/netbox_initializers/initializers/route_targets.py index fdb0caa..955468a 100644 --- a/src/netbox_initializers/initializers/route_targets.py +++ b/src/netbox_initializers/initializers/route_targets.py @@ -1,7 +1,7 @@ from ipam.models import RouteTarget from tenancy.models import Tenant -from . import BaseInitializer, register_initializer +from netbox_initializers.initializers.base import BaseInitializer, register_initializer OPTIONAL_ASSOCS = {"tenant": (Tenant, "name")} diff --git a/src/netbox_initializers/initializers/service_templates.py b/src/netbox_initializers/initializers/service_templates.py index beba486..3ca00c3 100644 --- a/src/netbox_initializers/initializers/service_templates.py +++ b/src/netbox_initializers/initializers/service_templates.py @@ -1,6 +1,6 @@ from ipam.models import ServiceTemplate -from . import BaseInitializer, register_initializer +from netbox_initializers.initializers.base import BaseInitializer, register_initializer MATCH_PARAMS = ["name"] diff --git a/src/netbox_initializers/initializers/services.py b/src/netbox_initializers/initializers/services.py index 38138fb..c4f2e06 100644 --- a/src/netbox_initializers/initializers/services.py +++ b/src/netbox_initializers/initializers/services.py @@ -2,7 +2,7 @@ from ipam.models import Service from virtualization.models import VirtualMachine -from . import BaseInitializer, register_initializer +from netbox_initializers.initializers.base import BaseInitializer, register_initializer MATCH_PARAMS = ["name", "device", "virtual_machine"] OPTIONAL_ASSOCS = { diff --git a/src/netbox_initializers/initializers/site_groups.py b/src/netbox_initializers/initializers/site_groups.py index 17bc95b..f9a03dc 100644 --- a/src/netbox_initializers/initializers/site_groups.py +++ b/src/netbox_initializers/initializers/site_groups.py @@ -1,6 +1,6 @@ from dcim.models import SiteGroup -from . import BaseInitializer, register_initializer +from netbox_initializers.initializers.base import BaseInitializer, register_initializer OPTIONAL_ASSOCS = {"parent": (SiteGroup, "name")} diff --git a/src/netbox_initializers/initializers/sites.py b/src/netbox_initializers/initializers/sites.py index 0aac182..c030343 100644 --- a/src/netbox_initializers/initializers/sites.py +++ b/src/netbox_initializers/initializers/sites.py @@ -2,7 +2,7 @@ from ipam.models import ASN from tenancy.models import Tenant -from . import BaseInitializer, register_initializer +from netbox_initializers.initializers.base import BaseInitializer, register_initializer OPTIONAL_ASSOCS = { "region": (Region, "name"), diff --git a/src/netbox_initializers/initializers/tags.py b/src/netbox_initializers/initializers/tags.py index 72e1894..f6564f0 100644 --- a/src/netbox_initializers/initializers/tags.py +++ b/src/netbox_initializers/initializers/tags.py @@ -2,7 +2,7 @@ from extras.models import Tag from netbox.choices import ColorChoices -from . import BaseInitializer, register_initializer +from netbox_initializers.initializers.base import BaseInitializer, register_initializer class TagInitializer(BaseInitializer): diff --git a/src/netbox_initializers/initializers/tenant_groups.py b/src/netbox_initializers/initializers/tenant_groups.py index 4718542..353b114 100644 --- a/src/netbox_initializers/initializers/tenant_groups.py +++ b/src/netbox_initializers/initializers/tenant_groups.py @@ -1,6 +1,6 @@ from tenancy.models import TenantGroup -from . import BaseInitializer, register_initializer +from netbox_initializers.initializers.base import BaseInitializer, register_initializer class TenantGroupInitializer(BaseInitializer): diff --git a/src/netbox_initializers/initializers/tenants.py b/src/netbox_initializers/initializers/tenants.py index ec6668b..18ef24a 100644 --- a/src/netbox_initializers/initializers/tenants.py +++ b/src/netbox_initializers/initializers/tenants.py @@ -1,6 +1,6 @@ from tenancy.models import Tenant, TenantGroup -from . import BaseInitializer, register_initializer +from netbox_initializers.initializers.base import BaseInitializer, register_initializer OPTIONAL_ASSOCS = {"group": (TenantGroup, "name")} diff --git a/src/netbox_initializers/initializers/users.py b/src/netbox_initializers/initializers/users.py index 895bed3..26aeb95 100644 --- a/src/netbox_initializers/initializers/users.py +++ b/src/netbox_initializers/initializers/users.py @@ -1,6 +1,6 @@ from users.models import Token, User -from . import BaseInitializer, register_initializer +from netbox_initializers.initializers.base import BaseInitializer, register_initializer class UserInitializer(BaseInitializer): diff --git a/src/netbox_initializers/initializers/virtual_machines.py b/src/netbox_initializers/initializers/virtual_machines.py index 77191dd..c34b057 100644 --- a/src/netbox_initializers/initializers/virtual_machines.py +++ b/src/netbox_initializers/initializers/virtual_machines.py @@ -2,7 +2,7 @@ from tenancy.models import Tenant from virtualization.models import Cluster, VirtualMachine -from . import BaseInitializer, register_initializer +from netbox_initializers.initializers.base import BaseInitializer, register_initializer MATCH_PARAMS = ["cluster", "name"] REQUIRED_ASSOCS = {"cluster": (Cluster, "name")} diff --git a/src/netbox_initializers/initializers/virtualization_interfaces.py b/src/netbox_initializers/initializers/virtualization_interfaces.py index 0fe915f..abc5175 100644 --- a/src/netbox_initializers/initializers/virtualization_interfaces.py +++ b/src/netbox_initializers/initializers/virtualization_interfaces.py @@ -1,6 +1,6 @@ from virtualization.models import VirtualMachine, VMInterface -from . import BaseInitializer, register_initializer +from netbox_initializers.initializers.base import BaseInitializer, register_initializer MATCH_PARAMS = ["name", "virtual_machine"] REQUIRED_ASSOCS = {"virtual_machine": (VirtualMachine, "name")} diff --git a/src/netbox_initializers/initializers/vlan_groups.py b/src/netbox_initializers/initializers/vlan_groups.py index 5997ba3..d9d3389 100644 --- a/src/netbox_initializers/initializers/vlan_groups.py +++ b/src/netbox_initializers/initializers/vlan_groups.py @@ -1,7 +1,7 @@ from django.contrib.contenttypes.models import ContentType from ipam.models import VLANGroup -from . import BaseInitializer, register_initializer +from netbox_initializers.initializers.base import BaseInitializer, register_initializer OPTIONAL_ASSOCS = {"scope": (None, "name")} diff --git a/src/netbox_initializers/initializers/vlans.py b/src/netbox_initializers/initializers/vlans.py index 690d44d..17094a6 100644 --- a/src/netbox_initializers/initializers/vlans.py +++ b/src/netbox_initializers/initializers/vlans.py @@ -2,7 +2,7 @@ from ipam.models import VLAN, Role, VLANGroup from tenancy.models import Tenant, TenantGroup -from . import BaseInitializer, register_initializer +from netbox_initializers.initializers.base import BaseInitializer, register_initializer MATCH_PARAMS = ["name", "vid"] OPTIONAL_ASSOCS = { diff --git a/src/netbox_initializers/initializers/vrfs.py b/src/netbox_initializers/initializers/vrfs.py index 4379e9d..6e44a52 100644 --- a/src/netbox_initializers/initializers/vrfs.py +++ b/src/netbox_initializers/initializers/vrfs.py @@ -1,7 +1,7 @@ from ipam.models import VRF from tenancy.models import Tenant -from . import BaseInitializer, register_initializer +from netbox_initializers.initializers.base import BaseInitializer, register_initializer MATCH_PARAMS = ["name", "rd"] OPTIONAL_ASSOCS = {"tenant": (Tenant, "name")} diff --git a/src/netbox_initializers/initializers/webhooks.py b/src/netbox_initializers/initializers/webhooks.py index 26625f9..bee2f08 100644 --- a/src/netbox_initializers/initializers/webhooks.py +++ b/src/netbox_initializers/initializers/webhooks.py @@ -1,7 +1,7 @@ from django.contrib.contenttypes.models import ContentType from extras.models import Webhook -from . import BaseInitializer, register_initializer +from netbox_initializers.initializers.base import BaseInitializer, register_initializer def get_content_type_id(hook_name, content_type): diff --git a/src/netbox_initializers/initializers/yaml/custom_fields.yml b/src/netbox_initializers/initializers/yaml/custom_fields.yml index e2b471d..961a7bc 100644 --- a/src/netbox_initializers/initializers/yaml/custom_fields.yml +++ b/src/netbox_initializers/initializers/yaml/custom_fields.yml @@ -32,6 +32,7 @@ # on_objects: # - dcim.models.Device # - dcim.models.Rack +# - dcim.models.RackType # - dcim.models.Site # - dcim.models.DeviceType # - ipam.models.IPAddress diff --git a/src/netbox_initializers/initializers/yaml/power_panels.yml b/src/netbox_initializers/initializers/yaml/power_panels.yml index a670ba7..80500fc 100644 --- a/src/netbox_initializers/initializers/yaml/power_panels.yml +++ b/src/netbox_initializers/initializers/yaml/power_panels.yml @@ -1,5 +1,5 @@ # - name: power panel AMS 1 -# site: AMS 1 +# site: AMS 1 # - name: power panel SING 1 -# site: SING 1 +# site: SING 1 # location: cage 101 diff --git a/src/netbox_initializers/initializers/yaml/rack_types.yml b/src/netbox_initializers/initializers/yaml/rack_types.yml new file mode 100644 index 0000000..a898773 --- /dev/null +++ b/src/netbox_initializers/initializers/yaml/rack_types.yml @@ -0,0 +1,55 @@ +# # Examples: +# - model: Rack Type 1 +# manufacturer: manufacturer-1 +# slug: rack-type-1 +# form_factor: 4-post-cabinet +# width: 19 +# u_height: 47 +# custom_field_data: +# text_field: Description +# starting_unit: 2 +# desc_units: true +# outer_width: 600 +# outer_depth: 1000 +# outer_unit: mm +# mounting_depth: 800 +# weight: 100.3 +# weight_unit: kg +# description: Description for Rack Type 1 +# comments: Comments for Rack Type 1 +# - model: Rack Type 2 +# manufacturer: manufacturer-2 +# slug: rack-type-2 +# form_factor: 2-post-frame +# width: 23 +# u_height: 24 +# custom_field_data: +# text_field: Description +# starting_unit: 1 +# desc_units: false +# outer_width: 800 +# outer_depth: 1200 +# outer_unit: mm +# mounting_depth: 1000 +# weight: 80.5 +# weight_unit: kg +# description: Description for Rack Type 2 +# comments: Comments for Rack Type 2 +# - model: Rack Type 3 +# manufacturer: no-name +# slug: rack-type-3 +# form_factor: wall-mount +# width: 10 +# u_height: 12 +# custom_field_data: +# text_field: Description +# starting_unit: 1 +# desc_units: true +# outer_width: 500 +# outer_depth: 300 +# outer_unit: mm +# mounting_depth: 250 +# weight: 30.2 +# weight_unit: kg +# description: Description for Rack Type 3 +# comments: Comments for Rack Type 3 diff --git a/src/netbox_initializers/initializers/yaml/racks.yml b/src/netbox_initializers/initializers/yaml/racks.yml index 9071e19..48f44de 100644 --- a/src/netbox_initializers/initializers/yaml/racks.yml +++ b/src/netbox_initializers/initializers/yaml/racks.yml @@ -2,12 +2,6 @@ ## width: ## - 19 ## - 23 -## types: -## - 2-post-frame -## - 4-post-frame -## - 4-post-cabinet -## - wall-frame -## - wall-cabinet ## outer_unit: ## - mm ## - in @@ -17,7 +11,7 @@ # - site: AMS 1 # name: rack-01 # role: Role 1 -# type: 4-post-cabinet +# rack_type: rack-type-1 # width: 19 # u_height: 47 # custom_field_data: @@ -25,7 +19,7 @@ # - site: AMS 2 # name: rack-02 # role: Role 2 -# type: 4-post-cabinet +# rack_type: rack-type-2 # width: 19 # u_height: 47 # custom_field_data: @@ -34,7 +28,7 @@ # name: rack-03 # location: cage 101 # role: Role 3 -# type: 4-post-cabinet +# rack_type: rack-type-3 # width: 19 # u_height: 47 # custom_field_data: diff --git a/src/netbox_initializers/initializers/yaml/service_templates.yml b/src/netbox_initializers/initializers/yaml/service_templates.yml index fdd0562..1a1ab73 100644 --- a/src/netbox_initializers/initializers/yaml/service_templates.yml +++ b/src/netbox_initializers/initializers/yaml/service_templates.yml @@ -8,5 +8,5 @@ # - 53 # - name: MISC # protocol: UDP -# ports: +# ports: # - 4000 diff --git a/src/netbox_initializers/initializers/yaml/services.yml b/src/netbox_initializers/initializers/yaml/services.yml index 8d4441c..b86fdd9 100644 --- a/src/netbox_initializers/initializers/yaml/services.yml +++ b/src/netbox_initializers/initializers/yaml/services.yml @@ -10,6 +10,6 @@ # virtual_machine: virtual machine 1 # - name: MISC # protocol: UDP -# ports: +# ports: # - 4000 # device: server01 diff --git a/src/netbox_initializers/management/commands/load_initializer_data.py b/src/netbox_initializers/management/commands/load_initializer_data.py index 730de02..243484d 100644 --- a/src/netbox_initializers/management/commands/load_initializer_data.py +++ b/src/netbox_initializers/management/commands/load_initializer_data.py @@ -3,7 +3,7 @@ from django.core.management.base import BaseCommand, CommandError -from netbox_initializers.initializers import INITIALIZER_ORDER, INITIALIZER_REGISTRY +from netbox_initializers.initializers.base import INITIALIZER_ORDER, INITIALIZER_REGISTRY class Command(BaseCommand): diff --git a/src/netbox_initializers/version.py b/src/netbox_initializers/version.py new file mode 100644 index 0000000..73f980c --- /dev/null +++ b/src/netbox_initializers/version.py @@ -0,0 +1 @@ +VERSION = "4.1.0" diff --git a/test/docker-compose.yml b/test/docker-compose.yml index 153c478..506d0a7 100644 --- a/test/docker-compose.yml +++ b/test/docker-compose.yml @@ -1,15 +1,14 @@ --- -version: '3.4' services: netbox: depends_on: - - postgres - - redis - - redis-cache - user: 'unit:root' + - postgres + - redis + - redis-cache + user: "unit:root" env_file: env/netbox.env volumes: - - ./initializer-data:/etc/netbox/initializer-data:z,ro + - ./initializer-data:/etc/netbox/initializer-data:z,ro build: context: .. dockerfile: test/Dockerfile @@ -18,24 +17,24 @@ services: image: postgres:15-alpine env_file: env/postgres.env volumes: - - netbox-postgres-data:/var/lib/postgresql/data + - netbox-postgres-data:/var/lib/postgresql/data # redis redis: image: redis:7-alpine command: - - sh - - -c # this is to evaluate the $REDIS_PASSWORD from the env - - redis-server --appendonly yes --requirepass $$REDIS_PASSWORD ## $$ because of docker-compose + - sh + - -c # this is to evaluate the $REDIS_PASSWORD from the env + - redis-server --appendonly yes --requirepass $$REDIS_PASSWORD ## $$ because of docker-compose env_file: env/redis.env volumes: - - netbox-redis-data:/data + - netbox-redis-data:/data redis-cache: image: redis:7-alpine command: - - sh - - -c # this is to evaluate the $REDIS_PASSWORD from the env - - redis-server --requirepass $$REDIS_PASSWORD ## $$ because of docker-compose + - sh + - -c # this is to evaluate the $REDIS_PASSWORD from the env + - redis-server --requirepass $$REDIS_PASSWORD ## $$ because of docker-compose env_file: env/redis-cache.env volumes: diff --git a/uv.lock b/uv.lock new file mode 100644 index 0000000..e17bbf7 --- /dev/null +++ b/uv.lock @@ -0,0 +1,90 @@ +version = 1 +requires-python = ">=3.10" + +[[package]] +name = "netbox-initializers" +version = "4.1.0" +source = { editable = "." } +dependencies = [ + { name = "ruamel-yaml" }, +] + +[package.dev-dependencies] +dev = [ + { name = "ruff" }, +] + +[package.metadata] +requires-dist = [{ name = "ruamel-yaml", specifier = ">=0.18.6" }] + +[package.metadata.requires-dev] +dev = [{ name = "ruff", specifier = "==0.6.3" }] + +[[package]] +name = "ruamel-yaml" +version = "0.18.6" +source = { registry = "https://nexus.scanplus.de/repository/pypi-group/simple" } +dependencies = [ + { name = "ruamel-yaml-clib", marker = "python_full_version < '3.13' and platform_python_implementation == 'CPython'" }, +] +sdist = { url = "https://nexus.scanplus.de/repository/pypi-group/packages/ruamel-yaml/0.18.6/ruamel.yaml-0.18.6.tar.gz", hash = "sha256:8b27e6a217e786c6fbe5634d8f3f11bc63e0f80f6a5890f28863d9c45aac311b" } +wheels = [ + { url = "https://nexus.scanplus.de/repository/pypi-group/packages/ruamel-yaml/0.18.6/ruamel.yaml-0.18.6-py3-none-any.whl", hash = "sha256:57b53ba33def16c4f3d807c0ccbc00f8a6081827e81ba2491691b76882d0c636" }, +] + +[[package]] +name = "ruamel-yaml-clib" +version = "0.2.8" +source = { registry = "https://nexus.scanplus.de/repository/pypi-group/simple" } +sdist = { url = "https://nexus.scanplus.de/repository/pypi-group/packages/ruamel-yaml-clib/0.2.8/ruamel.yaml.clib-0.2.8.tar.gz", hash = "sha256:beb2e0404003de9a4cab9753a8805a8fe9320ee6673136ed7f04255fe60bb512" } +wheels = [ + { url = "https://nexus.scanplus.de/repository/pypi-group/packages/ruamel-yaml-clib/0.2.8/ruamel.yaml.clib-0.2.8-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b42169467c42b692c19cf539c38d4602069d8c1505e97b86387fcf7afb766e1d" }, + { url = "https://nexus.scanplus.de/repository/pypi-group/packages/ruamel-yaml-clib/0.2.8/ruamel.yaml.clib-0.2.8-cp310-cp310-macosx_13_0_arm64.whl", hash = "sha256:07238db9cbdf8fc1e9de2489a4f68474e70dffcb32232db7c08fa61ca0c7c462" }, + { url = "https://nexus.scanplus.de/repository/pypi-group/packages/ruamel-yaml-clib/0.2.8/ruamel.yaml.clib-0.2.8-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:fff3573c2db359f091e1589c3d7c5fc2f86f5bdb6f24252c2d8e539d4e45f412" }, + { url = "https://nexus.scanplus.de/repository/pypi-group/packages/ruamel-yaml-clib/0.2.8/ruamel.yaml.clib-0.2.8-cp310-cp310-manylinux_2_24_aarch64.whl", hash = "sha256:aa2267c6a303eb483de8d02db2871afb5c5fc15618d894300b88958f729ad74f" }, + { url = "https://nexus.scanplus.de/repository/pypi-group/packages/ruamel-yaml-clib/0.2.8/ruamel.yaml.clib-0.2.8-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:840f0c7f194986a63d2c2465ca63af8ccbbc90ab1c6001b1978f05119b5e7334" }, + { url = "https://nexus.scanplus.de/repository/pypi-group/packages/ruamel-yaml-clib/0.2.8/ruamel.yaml.clib-0.2.8-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:024cfe1fc7c7f4e1aff4a81e718109e13409767e4f871443cbff3dba3578203d" }, + { url = "https://nexus.scanplus.de/repository/pypi-group/packages/ruamel-yaml-clib/0.2.8/ruamel.yaml.clib-0.2.8-cp310-cp310-win32.whl", hash = "sha256:c69212f63169ec1cfc9bb44723bf2917cbbd8f6191a00ef3410f5a7fe300722d" }, + { url = "https://nexus.scanplus.de/repository/pypi-group/packages/ruamel-yaml-clib/0.2.8/ruamel.yaml.clib-0.2.8-cp310-cp310-win_amd64.whl", hash = "sha256:cabddb8d8ead485e255fe80429f833172b4cadf99274db39abc080e068cbcc31" }, + { url = "https://nexus.scanplus.de/repository/pypi-group/packages/ruamel-yaml-clib/0.2.8/ruamel.yaml.clib-0.2.8-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:bef08cd86169d9eafb3ccb0a39edb11d8e25f3dae2b28f5c52fd997521133069" }, + { url = "https://nexus.scanplus.de/repository/pypi-group/packages/ruamel-yaml-clib/0.2.8/ruamel.yaml.clib-0.2.8-cp311-cp311-macosx_13_0_arm64.whl", hash = "sha256:b16420e621d26fdfa949a8b4b47ade8810c56002f5389970db4ddda51dbff248" }, + { url = "https://nexus.scanplus.de/repository/pypi-group/packages/ruamel-yaml-clib/0.2.8/ruamel.yaml.clib-0.2.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:25c515e350e5b739842fc3228d662413ef28f295791af5e5110b543cf0b57d9b" }, + { url = "https://nexus.scanplus.de/repository/pypi-group/packages/ruamel-yaml-clib/0.2.8/ruamel.yaml.clib-0.2.8-cp311-cp311-manylinux_2_24_aarch64.whl", hash = "sha256:1707814f0d9791df063f8c19bb51b0d1278b8e9a2353abbb676c2f685dee6afe" }, + { url = "https://nexus.scanplus.de/repository/pypi-group/packages/ruamel-yaml-clib/0.2.8/ruamel.yaml.clib-0.2.8-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:46d378daaac94f454b3a0e3d8d78cafd78a026b1d71443f4966c696b48a6d899" }, + { url = "https://nexus.scanplus.de/repository/pypi-group/packages/ruamel-yaml-clib/0.2.8/ruamel.yaml.clib-0.2.8-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:09b055c05697b38ecacb7ac50bdab2240bfca1a0c4872b0fd309bb07dc9aa3a9" }, + { url = "https://nexus.scanplus.de/repository/pypi-group/packages/ruamel-yaml-clib/0.2.8/ruamel.yaml.clib-0.2.8-cp311-cp311-win32.whl", hash = "sha256:53a300ed9cea38cf5a2a9b069058137c2ca1ce658a874b79baceb8f892f915a7" }, + { url = "https://nexus.scanplus.de/repository/pypi-group/packages/ruamel-yaml-clib/0.2.8/ruamel.yaml.clib-0.2.8-cp311-cp311-win_amd64.whl", hash = "sha256:c2a72e9109ea74e511e29032f3b670835f8a59bbdc9ce692c5b4ed91ccf1eedb" }, + { url = "https://nexus.scanplus.de/repository/pypi-group/packages/ruamel-yaml-clib/0.2.8/ruamel.yaml.clib-0.2.8-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:ebc06178e8821efc9692ea7544aa5644217358490145629914d8020042c24aa1" }, + { url = "https://nexus.scanplus.de/repository/pypi-group/packages/ruamel-yaml-clib/0.2.8/ruamel.yaml.clib-0.2.8-cp312-cp312-macosx_13_0_arm64.whl", hash = "sha256:edaef1c1200c4b4cb914583150dcaa3bc30e592e907c01117c08b13a07255ec2" }, + { url = "https://nexus.scanplus.de/repository/pypi-group/packages/ruamel-yaml-clib/0.2.8/ruamel.yaml.clib-0.2.8-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d176b57452ab5b7028ac47e7b3cf644bcfdc8cacfecf7e71759f7f51a59e5c92" }, + { url = "https://nexus.scanplus.de/repository/pypi-group/packages/ruamel-yaml-clib/0.2.8/ruamel.yaml.clib-0.2.8-cp312-cp312-manylinux_2_24_aarch64.whl", hash = "sha256:1dc67314e7e1086c9fdf2680b7b6c2be1c0d8e3a8279f2e993ca2a7545fecf62" }, + { url = "https://nexus.scanplus.de/repository/pypi-group/packages/ruamel-yaml-clib/0.2.8/ruamel.yaml.clib-0.2.8-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:3213ece08ea033eb159ac52ae052a4899b56ecc124bb80020d9bbceeb50258e9" }, + { url = "https://nexus.scanplus.de/repository/pypi-group/packages/ruamel-yaml-clib/0.2.8/ruamel.yaml.clib-0.2.8-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:aab7fd643f71d7946f2ee58cc88c9b7bfc97debd71dcc93e03e2d174628e7e2d" }, + { url = "https://nexus.scanplus.de/repository/pypi-group/packages/ruamel-yaml-clib/0.2.8/ruamel.yaml.clib-0.2.8-cp312-cp312-win32.whl", hash = "sha256:5c365d91c88390c8d0a8545df0b5857172824b1c604e867161e6b3d59a827eaa" }, + { url = "https://nexus.scanplus.de/repository/pypi-group/packages/ruamel-yaml-clib/0.2.8/ruamel.yaml.clib-0.2.8-cp312-cp312-win_amd64.whl", hash = "sha256:1758ce7d8e1a29d23de54a16ae867abd370f01b5a69e1a3ba75223eaa3ca1a1b" }, +] + +[[package]] +name = "ruff" +version = "0.6.3" +source = { registry = "https://nexus.scanplus.de/repository/pypi-group/simple" } +sdist = { url = "https://nexus.scanplus.de/repository/pypi-group/packages/ruff/0.6.3/ruff-0.6.3.tar.gz", hash = "sha256:183b99e9edd1ef63be34a3b51fee0a9f4ab95add123dbf89a71f7b1f0c991983" } +wheels = [ + { url = "https://nexus.scanplus.de/repository/pypi-group/packages/ruff/0.6.3/ruff-0.6.3-py3-none-linux_armv6l.whl", hash = "sha256:97f58fda4e309382ad30ede7f30e2791d70dd29ea17f41970119f55bdb7a45c3" }, + { url = "https://nexus.scanplus.de/repository/pypi-group/packages/ruff/0.6.3/ruff-0.6.3-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:3b061e49b5cf3a297b4d1c27ac5587954ccb4ff601160d3d6b2f70b1622194dc" }, + { url = "https://nexus.scanplus.de/repository/pypi-group/packages/ruff/0.6.3/ruff-0.6.3-py3-none-macosx_11_0_arm64.whl", hash = "sha256:34e2824a13bb8c668c71c1760a6ac7d795ccbd8d38ff4a0d8471fdb15de910b1" }, + { url = "https://nexus.scanplus.de/repository/pypi-group/packages/ruff/0.6.3/ruff-0.6.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bddfbb8d63c460f4b4128b6a506e7052bad4d6f3ff607ebbb41b0aa19c2770d1" }, + { url = "https://nexus.scanplus.de/repository/pypi-group/packages/ruff/0.6.3/ruff-0.6.3-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ced3eeb44df75353e08ab3b6a9e113b5f3f996bea48d4f7c027bc528ba87b672" }, + { url = "https://nexus.scanplus.de/repository/pypi-group/packages/ruff/0.6.3/ruff-0.6.3-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:47021dff5445d549be954eb275156dfd7c37222acc1e8014311badcb9b4ec8c1" }, + { url = "https://nexus.scanplus.de/repository/pypi-group/packages/ruff/0.6.3/ruff-0.6.3-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:7d7bd20dc07cebd68cc8bc7b3f5ada6d637f42d947c85264f94b0d1cd9d87384" }, + { url = "https://nexus.scanplus.de/repository/pypi-group/packages/ruff/0.6.3/ruff-0.6.3-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:500f166d03fc6d0e61c8e40a3ff853fa8a43d938f5d14c183c612df1b0d6c58a" }, + { url = "https://nexus.scanplus.de/repository/pypi-group/packages/ruff/0.6.3/ruff-0.6.3-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:42844ff678f9b976366b262fa2d1d1a3fe76f6e145bd92c84e27d172e3c34500" }, + { url = "https://nexus.scanplus.de/repository/pypi-group/packages/ruff/0.6.3/ruff-0.6.3-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70452a10eb2d66549de8e75f89ae82462159855e983ddff91bc0bce6511d0470" }, + { url = "https://nexus.scanplus.de/repository/pypi-group/packages/ruff/0.6.3/ruff-0.6.3-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:65a533235ed55f767d1fc62193a21cbf9e3329cf26d427b800fdeacfb77d296f" }, + { url = "https://nexus.scanplus.de/repository/pypi-group/packages/ruff/0.6.3/ruff-0.6.3-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:d2e2c23cef30dc3cbe9cc5d04f2899e7f5e478c40d2e0a633513ad081f7361b5" }, + { url = "https://nexus.scanplus.de/repository/pypi-group/packages/ruff/0.6.3/ruff-0.6.3-py3-none-musllinux_1_2_i686.whl", hash = "sha256:d8a136aa7d228975a6aee3dd8bea9b28e2b43e9444aa678fb62aeb1956ff2351" }, + { url = "https://nexus.scanplus.de/repository/pypi-group/packages/ruff/0.6.3/ruff-0.6.3-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:f92fe93bc72e262b7b3f2bba9879897e2d58a989b4714ba6a5a7273e842ad2f8" }, + { url = "https://nexus.scanplus.de/repository/pypi-group/packages/ruff/0.6.3/ruff-0.6.3-py3-none-win32.whl", hash = "sha256:7a62d3b5b0d7f9143d94893f8ba43aa5a5c51a0ffc4a401aa97a81ed76930521" }, + { url = "https://nexus.scanplus.de/repository/pypi-group/packages/ruff/0.6.3/ruff-0.6.3-py3-none-win_amd64.whl", hash = "sha256:746af39356fee2b89aada06c7376e1aa274a23493d7016059c3a72e3b296befb" }, + { url = "https://nexus.scanplus.de/repository/pypi-group/packages/ruff/0.6.3/ruff-0.6.3-py3-none-win_arm64.whl", hash = "sha256:14a9528a8b70ccc7a847637c29e56fd1f9183a9db743bbc5b8e0c4ad60592a82" }, +]