mirror of
https://github.com/netbox-community/devicetype-library.git
synced 2025-08-19 03:06:21 +02:00
Add rack-types (#3026)
* feat: add front image
* feat: startech 4post rack
* feat: add digitus DN-19 07U-I-OD
* feat: add digitus DN-19 07U-I-OD
* Revert "feat: add front image"
This reverts commit bdd27607f8
.
* fix: change form_factor
* feat: add racktype schema
* feat: add racktype schema
* feat: upload generated known-racks.pickle
* fix: change filename
* feat: add rack type
* refactor: change tests to work with racks
* refactor: use the correct device class
* fix: rename file correctly
* Update racktype.json
* fix: add missing desc_units schema property
* fix: add missing desc_units value
* chore: update readme with rack-types documentation
---------
Co-authored-by: Harry <Harry@cadby.co.uk>
This commit is contained in:
42
README.md
42
README.md
@@ -103,6 +103,48 @@ The following fields may **optionally** be declared:
|
||||
For further detail on these attributes and those listed below, please reference the
|
||||
[schema definitions](schema/) and the [Component Definitions](#component-definitions) below.
|
||||
|
||||
## Rack Type Definitions
|
||||
|
||||
Each definition **must** include at minimum the following fields:
|
||||
|
||||
- `manufacturer`: The name of the manufacturer which produces this rack type.
|
||||
- Type: String
|
||||
- `model`: The model number of the rack type. This must be unique per manufacturer.
|
||||
- Type: String
|
||||
- `slug`: A URL-friendly representation of the model number. Like the model number, this must be unique per
|
||||
manufacturer. All slugs should have the manufacturers name prepended to it with a dash, please see the example below.
|
||||
- Type: String
|
||||
- Pattern: `"^[-a-z0-9_]+$"`. Must match the following characters: `-`, Lowercase `a` to `z`, Numbers `0` to `9`.
|
||||
- `form_factor`: The form factor of the rack type. This is used to indicate the physical characteristics of the rack, such as whether it is a 4-post frame or a wall-cabinet etc.
|
||||
- Type: String
|
||||
- :test_tube: Example: `form_factor: 4-post-frame`
|
||||
- `width`: The width of the rack type in zoll/inches. This is used to indicate the physical width of the rack, such as whether it is a 19" or 23" rack.
|
||||
- Type: Integer
|
||||
- :test_tube: Example: `width: 19`
|
||||
- `u_height`: The height of the rack type in rack units.
|
||||
- Type: Number
|
||||
- :test_tube: Example: `u_height: 42`
|
||||
- `starting_unit`: The unit number at which the rack starts. This is used to indicate the starting unit number of the rack, such as whether it starts at 1 or 42. The starting unit is normally defined from bottom to top, with the bottom unit being 1.
|
||||
- Type: Number
|
||||
- :test_tube: Example: `starting_unit: 1`
|
||||
|
||||
:test_tube: Example:
|
||||
|
||||
```yaml
|
||||
manufacturer: Startech
|
||||
model: 4 Post 42U
|
||||
slug: startech-4postrack42
|
||||
form_factor: 4-post-frame
|
||||
width: 19
|
||||
u_height: 42
|
||||
starting_unit: 1
|
||||
```
|
||||
|
||||
**Note: We are asking that all new racks also include the following optional fields: `outer_width`, `outer_height`, `outer_depth`, `outer_unit`, `weight`, `max_weight`, `weight_unit`, `mounting_depth`, and `desc_units`.**
|
||||
|
||||
For further detail on these attributes and those listed below, please reference the
|
||||
[racktype schema definition](schema/racktype.json)
|
||||
|
||||
### Component Definitions
|
||||
|
||||
Valid component types are listed below. Each type of component must declare a list of the individual component templates
|
||||
|
16
rack-types/Digitus/dn-19-07u-i-od.yml
Normal file
16
rack-types/Digitus/dn-19-07u-i-od.yml
Normal file
@@ -0,0 +1,16 @@
|
||||
---
|
||||
manufacturer: Digitus
|
||||
model: DN-19 07U-I-OD
|
||||
slug: digitus-dn-19-07u-i-od
|
||||
width: 19
|
||||
u_height: 7
|
||||
form_factor: wall-cabinet
|
||||
description: '[Datasheet](https://www.assmann.com/product-pdf/4016032360971?PL=de)'
|
||||
starting_unit: 1
|
||||
outer_width: 600
|
||||
outer_unit: mm
|
||||
mounting_depth: 450
|
||||
weight: 31
|
||||
max_weight: 100
|
||||
weight_unit: kg
|
||||
desc_units: false
|
24
rack-types/Startech/4-post-42u.yaml
Normal file
24
rack-types/Startech/4-post-42u.yaml
Normal file
@@ -0,0 +1,24 @@
|
||||
---
|
||||
manufacturer: Startech
|
||||
model: 4 Post 42U
|
||||
slug: startech-4postrack42
|
||||
width: 19
|
||||
u_height: 42
|
||||
form_factor: 4-post-frame
|
||||
description: Startech 4 Post 42U 19in rack with optional casters
|
||||
starting_unit: 1
|
||||
outer_width: 600
|
||||
outer_unit: mm
|
||||
# Adjustable depth, do we want the minimum or maximum depth?
|
||||
# Minimum adjusted depth
|
||||
mounting_depth: 560
|
||||
# Maximum adjusted depth
|
||||
# mounting_depth: 1017
|
||||
weight: 38.5
|
||||
# Different weights between stationary and on casters, which one?
|
||||
# Stationary
|
||||
# max_weight: 600
|
||||
# Rolling
|
||||
max_weight: 360
|
||||
weight_unit: kg
|
||||
desc_units: false
|
100
schema/racktype.json
Normal file
100
schema/racktype.json
Normal file
@@ -0,0 +1,100 @@
|
||||
{
|
||||
"type": "object",
|
||||
"$id": "urn:devicetype-library:rack-type",
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"properties": {
|
||||
"manufacturer": {
|
||||
"type": "string"
|
||||
},
|
||||
"model": {
|
||||
"type": "string"
|
||||
},
|
||||
"slug": {
|
||||
"type": "string",
|
||||
"pattern": "^[-a-z0-9_]+$"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"form_factor": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"wall-cabinet",
|
||||
"4-post-frame",
|
||||
"2-post-frame",
|
||||
"4-post-cabinet",
|
||||
"wall-frame",
|
||||
"wall-frame-vertical",
|
||||
"wall-cabinet-vertical"
|
||||
]
|
||||
},
|
||||
"width": {
|
||||
"type": "integer",
|
||||
"enum": [
|
||||
10,
|
||||
19,
|
||||
20,
|
||||
23
|
||||
]
|
||||
},
|
||||
"u_height": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"multipleOf": 1
|
||||
},
|
||||
"outer_width": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"multipleOf": 0.01
|
||||
},
|
||||
"outer_height": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"multipleOf": 0.01
|
||||
},
|
||||
"outer_depth": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"multipleOf": 0.01
|
||||
},
|
||||
"outer_unit": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"mm",
|
||||
"in"
|
||||
]
|
||||
},
|
||||
"weight": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"multipleOf": 0.01
|
||||
},
|
||||
"max_weight": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"multipleOf": 0.01
|
||||
},
|
||||
"weight_unit": {
|
||||
"$ref": "urn:devicetype-library:generated-schema#/definitions/weight-unit"
|
||||
},
|
||||
"mounting_depth": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"multipleOf": 0.01
|
||||
},
|
||||
"starting_unit": {
|
||||
"type": "number",
|
||||
"minimum": 1,
|
||||
"multipleOf": 1
|
||||
},
|
||||
"desc_units": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"comments": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["manufacturer", "model", "slug", "form_factor", "width", "u_height", "starting_unit"],
|
||||
"additionalProperties": false
|
||||
}
|
@@ -1,7 +1,7 @@
|
||||
from test_configuration import COMPONENT_TYPES, IMAGE_FILETYPES, SCHEMAS, SCHEMAS_BASEPATH, KNOWN_SLUGS, ROOT_DIR, USE_LOCAL_KNOWN_SLUGS, NETBOX_DT_LIBRARY_URL, KNOWN_MODULES, USE_UPSTREAM_DIFF, PRECOMMIT_ALL_SWITCHES
|
||||
import pickle_operations
|
||||
from yaml_loader import DecimalSafeLoader
|
||||
from device_types import DeviceType, ModuleType, verify_filename, validate_components
|
||||
from device_types import DeviceType, ModuleType, RackType, verify_filename, validate_components
|
||||
import decimal
|
||||
import glob
|
||||
import json
|
||||
@@ -134,11 +134,13 @@ image_files = _get_image_files()
|
||||
if USE_LOCAL_KNOWN_SLUGS:
|
||||
KNOWN_SLUGS = pickle_operations.read_pickle_data(f'{ROOT_DIR}/tests/known-slugs.pickle')
|
||||
KNOWN_MODULES = pickle_operations.read_pickle_data(f'{ROOT_DIR}/tests/known-modules.pickle')
|
||||
KNOWN_RACKS = pickle_operations.read_pickle_data(f'{ROOT_DIR}/tests/known-racks.pickle')
|
||||
else:
|
||||
temp_dir = tempfile.TemporaryDirectory()
|
||||
repo = Repo.clone_from(url=NETBOX_DT_LIBRARY_URL, to_path=temp_dir.name)
|
||||
KNOWN_SLUGS = pickle_operations.read_pickle_data(f'{temp_dir.name}/tests/known-slugs.pickle')
|
||||
KNOWN_MODULES = pickle_operations.read_pickle_data(f'{temp_dir.name}/tests/known-modules.pickle')
|
||||
KNOWN_RACKS = pickle_operations.read_pickle_data(f'{ROOT_DIR}/tests/known-racks.pickle')
|
||||
|
||||
SCHEMA_REGISTRY = _generate_schema_registry()
|
||||
|
||||
@@ -181,6 +183,12 @@ def test_definitions(file_path, schema, change_type):
|
||||
if "device-types" in file_path:
|
||||
# A device
|
||||
this_device = DeviceType(definition, file_path, change_type)
|
||||
elif "module-types" in file_path:
|
||||
# A module type
|
||||
this_device = ModuleType(definition, file_path, change_type)
|
||||
elif "rack-types" in file_path:
|
||||
# A rack type
|
||||
this_device = RackType(definition, file_path, change_type)
|
||||
else:
|
||||
# A module
|
||||
this_device = ModuleType(definition, file_path, change_type)
|
||||
|
@@ -179,6 +179,28 @@ class ModuleType:
|
||||
slugified = slugified[:-1]
|
||||
return slugified
|
||||
|
||||
class RackType:
|
||||
def __new__(cls, *args, **kwargs):
|
||||
return super().__new__(cls)
|
||||
|
||||
def __init__(self, definition, file_path, change_type):
|
||||
self.file_path = file_path
|
||||
self.isDevice = False
|
||||
self.definition = definition
|
||||
self.manufacturer = definition.get('manufacturer')
|
||||
self.model = definition.get('model')
|
||||
self._slug_model = self._slugify_model()
|
||||
self.change_type = change_type
|
||||
|
||||
def get_filepath(self):
|
||||
return self.file_path
|
||||
|
||||
def _slugify_model(self):
|
||||
slugified = self.model.casefold().replace(" ", "-").replace("sfp+", "sfpp").replace("poe+", "poep").replace("-+", "-plus").replace("+", "-plus-").replace("_", "-").replace("&", "-and-").replace("!", "").replace("/", "-").replace(",", "").replace("'", "").replace("*", "-")
|
||||
if slugified.endswith("-"):
|
||||
slugified = slugified[:-1]
|
||||
return slugified
|
||||
|
||||
def validate_component_names(component_names: (set or None)):
|
||||
if len(component_names) > 1:
|
||||
verify_name = list(component_names[0])
|
||||
@@ -197,10 +219,17 @@ def validate_component_names(component_names: (set or None)):
|
||||
return False
|
||||
return True
|
||||
|
||||
def verify_filename(device: (DeviceType or ModuleType), KNOWN_MODULES: (set or None)):
|
||||
def verify_filename(device: (DeviceType or ModuleType or RackType), KNOWN_MODULES: (set or None)):
|
||||
head, tail = os.path.split(device.get_filepath())
|
||||
filename = tail.rsplit(".", 1)[0].casefold()
|
||||
|
||||
# Check if file is RackType
|
||||
if "rack-types" in device.file_path:
|
||||
if not filename == device._slug_model:
|
||||
device.failureMessage = f'{device.file_path} file name is invalid. Must be the model "{device._slug_model}"'
|
||||
return False
|
||||
return True
|
||||
|
||||
if not (filename == device._slug_model or filename == device._slug_part_number or filename == device.part_number.casefold()):
|
||||
device.failureMessage = f'{device.file_path} file name is invalid. Must be either the model "{device._slug_model}" or part_number "{device.part_number} / {device._slug_part_number}"'
|
||||
return False
|
||||
|
@@ -107,3 +107,6 @@ pickle_operations.write_pickle_data(KNOWN_SLUGS, f'{ROOT_DIR}/tests/known-slugs.
|
||||
|
||||
_generate_knowns('module')
|
||||
pickle_operations.write_pickle_data(KNOWN_MODULES, f'{ROOT_DIR}/tests/known-modules.pickle')
|
||||
|
||||
_generate_knowns('rack')
|
||||
pickle_operations.write_pickle_data(KNOWN_MODULES, f'{ROOT_DIR}/tests/known-racks.pickle')
|
||||
|
BIN
tests/known-racks.pickle
Normal file
BIN
tests/known-racks.pickle
Normal file
Binary file not shown.
@@ -3,6 +3,7 @@ import os
|
||||
SCHEMAS = (
|
||||
('device-types', 'devicetype.json'),
|
||||
('module-types', 'moduletype.json'),
|
||||
('rack-types', 'racktype.json'),
|
||||
)
|
||||
SCHEMAS_BASEPATH = f"{os.getcwd()}/schema/"
|
||||
|
||||
|
Reference in New Issue
Block a user