Skip to content

Commit

Permalink
Resolves 182
Browse files Browse the repository at this point in the history
  • Loading branch information
tsm1th committed Apr 19, 2024
1 parent a4ac963 commit ef06c3c
Show file tree
Hide file tree
Showing 5 changed files with 197 additions and 1 deletion.
33 changes: 32 additions & 1 deletion pynautobot/models/extras.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
This file has been modified by NetworktoCode, LLC.
"""

from pynautobot.core.endpoint import JobsEndpoint
from pynautobot.core.endpoint import JobsEndpoint, DetailEndpoint
from pynautobot.core.response import JsonField, Record


Expand Down Expand Up @@ -44,3 +44,34 @@ class Jobs(Record):
def run(self, **kwargs):
"""Run a job from within a job instance."""
return JobsEndpoint(self.api, self.api.extras, "jobs").run(class_path=self.id, **kwargs)


class DynamicGroups(Record):
def __str__(self):
parent_record_string = super().__str__()
return parent_record_string or str(self.id)

@property
def members(self):
"""Represents the ``members`` detail endpoint.
Returns a list of DetailEndpoint objects that are
related to the dynamic group
:returns: :py:class:`.DetailEndpoint`
:Examples:
Dynamic group of devices:
>>> group = nb.extras.dynamic_groups.get("device-group")
>>> group.members.list()
[<pynautobot.models.extras.DynamicGroups ('testswitch') at 0x7efee4037e80>...]
Dynamic group of IPs:
>>> group = nb.extras.dynamic_groups.get("ip-group")
>>> group.members.list()
[<pynautobot.models.extras.DynamicGroups ('192.168.10.200/32') at 0x7f3e6a980040>...]
"""
return DetailEndpoint(self, "members", custom_return=DynamicGroups)
20 changes: 20 additions & 0 deletions tests/fixtures/extras/dynamic_group.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"id": "5b39ba88-e5ab-4be2-89f5-5a016473b53c",
"object_type": "extras.dynamicgroup",
"display": "test-group",
"url": "http://localhost:8000/api/extras/dynamic-groups/5b39ba88-e5ab-4be2-89f5-5a016473b53c/",
"natural_slug": "test-group_e755",
"content_type": "dcim.device",
"name": "test-group",
"description": "",
"filter": {
"rack": [
"0a372aaf-b25b-4fdc-be09-cc857981a7bb"
]
},
"children": [],
"created": "2024-04-19T12:57:16.695546Z",
"last_updated": "2024-04-19T12:57:49.122196Z",
"notes_url": "http://localhost:8000/api/extras/dynamic-groups/5b39ba88-e5ab-4be2-89f5-5a016473b53c/notes/",
"custom_fields": {}
}
47 changes: 47 additions & 0 deletions tests/fixtures/extras/dynamic_groups.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
{
"count": 2,
"next": null,
"previous": null,
"results": [
{
"id": "5b39ba88-e5ab-4be2-89f5-5a016473b53c",
"object_type": "extras.dynamicgroup",
"display": "test-group",
"url": "http://localhost:8000/api/extras/dynamic-groups/5b39ba88-e5ab-4be2-89f5-5a016473b53c/",
"natural_slug": "test-group_e755",
"content_type": "dcim.device",
"name": "test-group",
"description": "",
"filter": {
"rack": [
"0a372aaf-b25b-4fdc-be09-cc857981a7bb"
]
},
"children": [],
"created": "2024-04-19T12:57:16.695546Z",
"last_updated": "2024-04-19T12:57:49.122196Z",
"notes_url": "http://localhost:8000/api/extras/dynamic-groups/5b39ba88-e5ab-4be2-89f5-5a016473b53c/notes/",
"custom_fields": {}
},
{
"id": "e7555cc1-2224-42f2-ac90-cd4c75f12345",
"object_type": "extras.dynamicgroup",
"display": "test-group-2",
"url": "http://localhost:8000/api/extras/dynamic-groups/e7555cc1-2224-42f2-ac90-cd4c75f12345/",
"natural_slug": "test-group_e789",
"content_type": "dcim.device",
"name": "test-group-2",
"description": "",
"filter": {
"rack": [
"0a372aaf-b25b-4fdc-be09-cc8579812345"
]
},
"children": [],
"created": "2024-04-19T12:57:16.695546Z",
"last_updated": "2024-04-19T12:57:49.122196Z",
"notes_url": "http://localhost:8000/api/extras/dynamic-groups/e7555cc1-2224-42f2-ac90-cd4c75f12345/notes/",
"custom_fields": {}
}
]
}
75 changes: 75 additions & 0 deletions tests/fixtures/extras/members.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
[{
"id": "5b39ba88-e5ab-4be2-89f5-5a016473b53c",
"name": "test1-edge1",
"display_name": "test1-edge1",
"device_type": {
"id": 1,
"url": "http://localhost:8000/api/dcim/device-types/1/",
"manufacturer": {
"id": 1,
"url": "http://localhost:8000/api/dcim/manufacturers/1/",
"name": "Juniper",
"slug": "juniper"
},
"model": "MX960",
"slug": "mx960"
},
"device_role": {
"id": 1,
"url": "http://localhost:8000/api/dcim/device-roles/1/",
"name": "Router",
"slug": "router"
},
"tenant": null,
"platform": {
"id": 1,
"url": "http://localhost:8000/api/dcim/platforms/1/",
"name": "Juniper Junos",
"slug": "juniper-junos"
},
"serial": "5555555555",
"asset_tag": null,
"site": {
"id": 1,
"url": "http://localhost:8000/api/dcim/sites/1/",
"name": "TEST1",
"slug": "test1"
},
"rack": {
"id": 1,
"url": "http://localhost:8000/api/dcim/racks/1/",
"name": "A1R1",
"display_name": "A1R1 (T23A01)"
},
"position": 1,
"face": {
"value": 0,
"label": "Front"
},
"parent_device": null,
"status": {
"value": true,
"label": "Active"
},
"primary_ip": {
"id": 1,
"url": "http://localhost:8000/api/ipam/ip-addresses/1/",
"family": 4,
"address": "10.0.255.1/32"
},
"primary_ip4": {
"id": 1,
"url": "http://localhost:8000/api/ipam/ip-addresses/1/",
"family": 4,
"address": "10.0.255.1/32"
},
"primary_ip6": null,
"comments": "",
"local_context_data": {
"testing": "test"
},
"custom_fields": {},
"config_context": {
"test_key": "test_val"
}
}]
23 changes: 23 additions & 0 deletions tests/test_extras.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from unittest.mock import patch

from . import Generic, HEADERS
from .util import Response


class DynamicGroupTestCase(Generic.Tests):
app = "extras"
name = "dynamic_groups"
name_singular = "dynamic_group"

@patch(
"requests.sessions.Session.get",
side_effect=[Response(fixture="extras/dynamic_group.json"), Response(fixture="extras/members.json")],
)
def test_get_members(self, mock):
dg = self.endpoint.get(self.uuid)
ret = dg.members.list()
mock.assert_called_with(f"{self.detail_uri}members/", params={}, json=None, headers=HEADERS)
self.assertTrue(ret)
self.assertEqual(len(ret), 1)
for record in ret:
self.assertEqual(record.name, str(record))

0 comments on commit ef06c3c

Please sign in to comment.