Add airflow and rack_type field support to netbox_rack module#1519
Add airflow and rack_type field support to netbox_rack module#1519
Conversation
- Add airflow field with choices: front-to-rear, rear-to-front - Add rack_type field to reference rack type objects - Add NB_RACK_TYPES constant to netbox_dcim.py - Update netbox_utils.py with rack_type mappings - Add changelog fragment for release notes - Add example demonstrating new fields usage Resolves #1450 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Updated to follow existing test patterns: - Added rack types to netbox-deploy.py (like other test data) - Tests reference rack_type by model name (not API calls) - Removed uri: module usage and SETUP/CLEANUP tasks - Tests match existing relational field patterns (device_type, rack_role, etc.) - Airflow tests: create, update, delete (tests 9-11) - Rack_type tests: create, idempotency, update, delete (tests 12-15) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Adds NetBox 4.1+ support for managing rack airflow and associating rack_type via the netbox_rack Ansible module, with supporting utils and integration coverage.
Changes:
- Extend
netbox_rackmodule options/documentation to includeairflow(choices) andrack_type(relation). - Update NetBox utility mappings to resolve
rack_typeagainst therack_typesendpoint and treatairflowas a choice field. - Add integration test tasks for NetBox v4.1/v4.2/v4.3 and seed rack types in the integration deploy script.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/integration/targets/v4.3/tasks/netbox_rack.yml | Adds airflow and rack_type integration scenarios for NetBox v4.3 |
| tests/integration/targets/v4.2/tasks/netbox_rack.yml | Adds airflow and rack_type integration scenarios for NetBox v4.2 |
| tests/integration/targets/v4.1/tasks/netbox_rack.yml | Adds airflow and rack_type integration scenarios for NetBox v4.1 |
| tests/integration/netbox-deploy.py | Seeds rack types for integration tests |
| plugins/modules/netbox_rack.py | Adds airflow/rack_type module parameters + docs/examples |
| plugins/module_utils/netbox_utils.py | Adds rack_types endpoint + rack_type resolution and airflow choice handling |
| plugins/module_utils/netbox_dcim.py | Introduces NB_RACK_TYPES constant |
| changelogs/fragments/add-airflow-racktype-to-rack.yml | Changelog entry for the new rack fields support |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| - name: 12 - ASSERT | ||
| ansible.builtin.assert: | ||
| that: | ||
| - test_twelve is changed | ||
| - test_twelve['diff']['before']['state'] == "absent" | ||
| - test_twelve['diff']['after']['state'] == "present" | ||
| - test_twelve['rack']['name'] == "Test Rack With Type" | ||
| - test_twelve['rack']['rack_type'] is not none | ||
| - test_twelve['msg'] == "rack Test Rack With Type created" |
There was a problem hiding this comment.
The rack_type assertions only check is not none, which wouldn't catch mapping to the wrong rack type. Consider asserting the expected rack_type ID (e.g. first created type vs second) for both create and update so the test validates correct association, not just presence.
| - name: 9 - Create rack with airflow | ||
| netbox.netbox.netbox_rack: | ||
| netbox_url: http://localhost:32768 | ||
| netbox_token: "0123456789abcdef0123456789abcdef01234567" | ||
| data: | ||
| name: Test Rack Airflow | ||
| site: Test Site | ||
| airflow: front-to-rear | ||
| state: present | ||
| register: test_nine | ||
|
|
||
| - name: 9 - ASSERT | ||
| ansible.builtin.assert: | ||
| that: | ||
| - test_nine is changed | ||
| - test_nine['diff']['before']['state'] == "absent" | ||
| - test_nine['diff']['after']['state'] == "present" | ||
| - test_nine['rack']['name'] == "Test Rack Airflow" | ||
| - test_nine['rack']['airflow'] == "front-to-rear" | ||
| - test_nine['msg'] == "rack Test Rack Airflow created" | ||
|
|
There was a problem hiding this comment.
These airflow tests cover create/update/delete but not idempotency. Add a second state: present run with the same airflow value and assert changed is false to ensure the new field is idempotent (and to match the PR description/test intent).
| - name: 9 - Create rack with airflow | ||
| netbox.netbox.netbox_rack: | ||
| netbox_url: http://localhost:32768 | ||
| netbox_token: "0123456789abcdef0123456789abcdef01234567" | ||
| data: | ||
| name: Test Rack Airflow | ||
| site: Test Site | ||
| airflow: front-to-rear | ||
| state: present | ||
| register: test_nine | ||
|
|
||
| - name: 9 - ASSERT | ||
| ansible.builtin.assert: | ||
| that: | ||
| - test_nine is changed | ||
| - test_nine['diff']['before']['state'] == "absent" | ||
| - test_nine['diff']['after']['state'] == "present" | ||
| - test_nine['rack']['name'] == "Test Rack Airflow" | ||
| - test_nine['rack']['airflow'] == "front-to-rear" | ||
| - test_nine['msg'] == "rack Test Rack Airflow created" | ||
|
|
There was a problem hiding this comment.
These airflow tests cover create/update/delete but not idempotency. Add a second state: present run with the same airflow value and assert changed is false to ensure the new field is idempotent (and to match the PR description/test intent).
plugins/module_utils/netbox_utils.py
Outdated
| "racks": {}, | ||
| "rack_groups": {}, | ||
| "rack_roles": {}, | ||
| "rack_types": {}, |
There was a problem hiding this comment.
rack_types was introduced in NetBox 4.1; without an introduced gate here, using rack_type against a NetBox 4.0 instance will attempt to access nb.dcim.rack_types during ID resolution and crash with an AttributeError. Add an {"introduced": "4.1"} marker for this endpoint (as done for other version-gated endpoints) so older versions are handled predictably.
| "rack_types": {}, | |
| "rack_types": {"introduced": "4.1"}, |
| - name: 12 - ASSERT | ||
| ansible.builtin.assert: | ||
| that: | ||
| - test_twelve is changed | ||
| - test_twelve['diff']['before']['state'] == "absent" | ||
| - test_twelve['diff']['after']['state'] == "present" | ||
| - test_twelve['rack']['name'] == "Test Rack With Type" | ||
| - test_twelve['rack']['rack_type'] is not none | ||
| - test_twelve['msg'] == "rack Test Rack With Type created" |
There was a problem hiding this comment.
The rack_type assertions only check is not none, which wouldn't catch mapping to the wrong rack type. Consider asserting the expected rack_type ID (e.g. first created type vs second) for both create and update so the test validates correct association, not just presence.
tests/integration/netbox-deploy.py
Outdated
| # Create Rack Types | ||
| rack_types = [ | ||
| { | ||
| "manufacturer": cisco_manu.id, | ||
| "model": "Standard 42U", | ||
| "slug": "standard-42u", | ||
| "form_factor": "4-post-frame", | ||
| "u_height": 42, | ||
| }, | ||
| { | ||
| "manufacturer": cisco_manu.id, | ||
| "model": "Standard 48U", | ||
| "slug": "standard-48u", | ||
| "form_factor": "4-post-cabinet", | ||
| "u_height": 48, | ||
| }, | ||
| ] | ||
| created_rack_types = make_netbox_calls(nb.dcim.rack_types, rack_types) |
There was a problem hiding this comment.
nb.dcim.rack_types is only available in NetBox >= 4.1, but this deploy script runs for other integration targets (e.g. v4.0). Creating rack types unconditionally will raise an AttributeError / API error and break those test runs. Wrap rack type creation in a if nb_version >= version.parse("4.1"): guard (or feature-detect the endpoint) and skip otherwise.
| # Create Rack Types | |
| rack_types = [ | |
| { | |
| "manufacturer": cisco_manu.id, | |
| "model": "Standard 42U", | |
| "slug": "standard-42u", | |
| "form_factor": "4-post-frame", | |
| "u_height": 42, | |
| }, | |
| { | |
| "manufacturer": cisco_manu.id, | |
| "model": "Standard 48U", | |
| "slug": "standard-48u", | |
| "form_factor": "4-post-cabinet", | |
| "u_height": 48, | |
| }, | |
| ] | |
| created_rack_types = make_netbox_calls(nb.dcim.rack_types, rack_types) | |
| # Create Rack Types (NetBox >= 4.1 only) | |
| created_rack_types = [] | |
| if nb_version >= version.parse("4.1"): | |
| rack_types = [ | |
| { | |
| "manufacturer": cisco_manu.id, | |
| "model": "Standard 42U", | |
| "slug": "standard-42u", | |
| "form_factor": "4-post-frame", | |
| "u_height": 42, | |
| }, | |
| { | |
| "manufacturer": cisco_manu.id, | |
| "model": "Standard 48U", | |
| "slug": "standard-48u", | |
| "form_factor": "4-post-cabinet", | |
| "u_height": 48, | |
| }, | |
| ] | |
| created_rack_types = make_netbox_calls(nb.dcim.rack_types, rack_types) |
plugins/modules/netbox_rack.py
Outdated
| site: Test Site | ||
| location: Test Location | ||
| airflow: front-to-rear | ||
| rack_type: Standard 42U Rack |
There was a problem hiding this comment.
The example value rack_type: Standard 42U Rack will be slugified to standard-42u-rack for lookup, which is unlikely to exist and may mislead users. Use a value that matches how rack types are resolved (e.g. the rack type's model/name like Standard 42U, its slug standard-42u, or a dict specifying slug).
| rack_type: Standard 42U Rack | |
| rack_type: Standard 42U |
| - name: 9 - Create rack with airflow | ||
| netbox.netbox.netbox_rack: | ||
| netbox_url: http://localhost:32768 | ||
| netbox_token: "0123456789abcdef0123456789abcdef01234567" | ||
| data: | ||
| name: Test Rack Airflow | ||
| site: Test Site | ||
| airflow: front-to-rear | ||
| state: present | ||
| register: test_nine | ||
|
|
||
| - name: 9 - ASSERT | ||
| ansible.builtin.assert: | ||
| that: | ||
| - test_nine is changed | ||
| - test_nine['diff']['before']['state'] == "absent" | ||
| - test_nine['diff']['after']['state'] == "present" | ||
| - test_nine['rack']['name'] == "Test Rack Airflow" | ||
| - test_nine['rack']['airflow'] == "front-to-rear" | ||
| - test_nine['msg'] == "rack Test Rack Airflow created" | ||
|
|
There was a problem hiding this comment.
These airflow tests cover create/update/delete but not idempotency. Add a second state: present run with the same airflow value and assert changed is false to ensure the new field is idempotent (and to match the PR description/test intent).
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 14 out of 14 changed files in this pull request and generated 4 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| --- | ||
| minor_changes: | ||
| - "netbox_custom_field - Add support for 'unique' field to enforce unique value constraints (https://github.com/netbox-community/ansible_modules/issues/1452)" |
There was a problem hiding this comment.
This changelog fragment documents netbox_custom_field support for unique and links to issue #1452, which is not mentioned in the PR title/description (focused on #1450 / netbox_rack). Please align the PR metadata with this additional change, or move this fragment (and related code/tests) to a separate PR.
| type: raw | ||
| rack_type: | ||
| description: | ||
| - The rack type that defines predefined characteristics like width, u_height, and others |
There was a problem hiding this comment.
The new rack_type option is only available starting with NetBox 4.1 (rack types were introduced in 4.1), but the option description doesn’t mention the NetBox version constraint. Please update the option documentation to explicitly call out the NetBox 4.1+ requirement to prevent confusion for users on older NetBox versions.
| - The rack type that defines predefined characteristics like width, u_height, and others | |
| - The rack type that defines predefined characteristics like width, u_height, and others (NetBox 4.1+) |
| airflow: | ||
| description: | ||
| - Airflow direction of the rack | ||
| choices: | ||
| - front-to-rear | ||
| - rear-to-front | ||
| required: false | ||
| type: str | ||
| version_added: "3.23.0" |
There was a problem hiding this comment.
The new airflow field is a NetBox 4.1+ rack attribute, but the option description doesn’t mention the NetBox version constraint. Please note the NetBox 4.1+ requirement in the documentation (similar to how other options call out version-specific behavior).
| unique: | ||
| description: | ||
| - Whether the custom field must have unique values | ||
| required: false | ||
| type: bool | ||
| version_added: "3.23.0" |
There was a problem hiding this comment.
This PR adds new functionality beyond the stated scope/title/description: netbox_custom_field gains a new unique option (plus tests and a changelog fragment referencing issue #1452), but the PR metadata only describes changes to netbox_rack (#1450). Please either update the PR title/description to include the custom-field feature (and reference the related issue), or split the custom-field work into a separate PR to keep changes focused.
Both features were introduced in NetBox 4.1 (September 2024), so tests should run against v4.1, v4.2, and v4.3. - v4.0: No changes (features don't exist in this version) - v4.1: Added tests for airflow and rack_type - v4.2: Added tests for airflow and rack_type - v4.3: Already had tests This ensures backward compatibility testing across all supported versions that have these features. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Fixes NetBox 4.0 compatibility issues by adding version gates to prevent AttributeError when rack_types endpoint is accessed on older NetBox versions. Adds missing airflow idempotency tests and corrects example documentation to match test data. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
694505e to
17a2431
Compare
Related Issue
#1450
New Behavior
The
netbox_rackmodule now supports two additional fields:airflow: Manages the airflow direction of racks (front-to-rear, rear-to-front)rack_type: Associates racks with predefined rack types that define characteristics like width, u_height, form factor, etc.Both fields were introduced in NetBox 4.1 and are now fully supported by the Ansible collection.
Contrast to Current Behavior
Previously, the
netbox_rackmodule did not support theairfloworrack_typefields. Users had to manage these fields through other means (direct API calls, NetBox UI) rather than through Ansible automation.With this change, users can now fully manage rack objects including airflow direction and rack type associations directly through Ansible playbooks, providing complete infrastructure-as-code capabilities for rack management.
Discussion: Benefits and Drawbacks
Benefits:
Drawbacks:
Backward Compatibility:
Changes to the Documentation
Module Documentation:
airflowfield documentation with choices (front-to-rear, rear-to-front)rack_typefield documentation describing its relationship to rack types endpointversion_added: "3.23.0"Changelog:
changelogs/fragments/add-airflow-racktype-to-rack.ymlIntegration Tests:
tests/integration/netbox-deploy.pyProposed Release Note Entry
Double Check
develbranch.