Skip to content

Commit ce5eb04

Browse files
committed
adds syncing of vCenter Custom Attributes #114
1 parent 3152368 commit ce5eb04

5 files changed

Lines changed: 107 additions & 32 deletions

File tree

module/netbox/object_classes.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1013,7 +1013,8 @@ class NBCustomField(NetBoxObject):
10131013
"dcim.interface",
10141014
"dcim.inventoryitem",
10151015
"dcim.powerport",
1016-
"virtualization.vminterface"
1016+
"virtualization.vminterface",
1017+
"virtualization.virtualmachine"
10171018
]
10181019

10191020
def __init__(self, *args, **kwargs):
@@ -1424,7 +1425,8 @@ def __init__(self, *args, **kwargs):
14241425
"primary_ip4": object,
14251426
"primary_ip6": object,
14261427
"tags": NBTagList,
1427-
"tenant": NBTenant
1428+
"tenant": NBTenant,
1429+
"custom_fields": NBCustomField
14281430
}
14291431
super().__init__(*args, **kwargs)
14301432

module/sources/check_redfish/import_inventory.py

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1028,31 +1028,6 @@ def update_item(self, item_data: dict, inventory_object: NBInventoryItem = None)
10281028

10291029
return
10301030

1031-
def add_update_custom_field(self, data):
1032-
"""
1033-
Adds/updates a NBCustomField object with data.
1034-
Update will only update the 'content_types' attribute.
1035-
1036-
Parameters
1037-
----------
1038-
data: dict
1039-
dictionary with NBCustomField attributes
1040-
1041-
Returns
1042-
-------
1043-
custom_field: NBCustomField
1044-
new or updated NBCustomField
1045-
"""
1046-
1047-
custom_field = self.inventory.get_by_data(NBCustomField, data={"name": data.get("name")})
1048-
1049-
if custom_field is None:
1050-
custom_field = self.inventory.add_object(NBCustomField, data=data, source=self)
1051-
else:
1052-
custom_field.update(data={"content_types": data.get("content_types")}, source=self)
1053-
1054-
return custom_field
1055-
10561031
def add_necessary_base_objects(self):
10571032
"""
10581033
Adds/updates source tag and all custom fields necessary for this source.

module/sources/common/source_base.py

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@
1818
NBSite,
1919
NBPrefix,
2020
NBIPAddress,
21-
NBVLAN
21+
NBVLAN,
22+
NBCustomField
2223
)
2324
from module.common.logging import get_logger
2425
from module.common.misc import grab
@@ -613,4 +614,29 @@ def get_vlan_object_if_exists(self, vlan_data=None, vlan_site=None):
613614

614615
return return_data
615616

617+
def add_update_custom_field(self, data):
618+
"""
619+
Adds/updates a NBCustomField object with data.
620+
Update will only update the 'content_types' attribute.
621+
622+
Parameters
623+
----------
624+
data: dict
625+
dictionary with NBCustomField attributes
626+
627+
Returns
628+
-------
629+
custom_field: NBCustomField
630+
new or updated NBCustomField
631+
"""
632+
633+
custom_field = self.inventory.get_by_data(NBCustomField, data={"name": data.get("name")})
634+
635+
if custom_field is None:
636+
custom_field = self.inventory.add_object(NBCustomField, data=data, source=self)
637+
else:
638+
custom_field.update(data={"content_types": data.get("content_types")}, source=self)
639+
640+
return custom_field
641+
616642
# EOF

module/sources/vmware/connection.py

Lines changed: 72 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
from module.common.misc import grab, dump, get_string_or_none, plural
2626
from module.common.support import normalize_mac_address, ip_valid_to_add_to_netbox
2727
from module.netbox.object_classes import (
28+
NetBoxObject,
2829
NetBoxInterfaceType,
2930
NBTag,
3031
NBManufacturer,
@@ -43,7 +44,8 @@
4344
NBPrefix,
4445
NBTenant,
4546
NBVRF,
46-
NBVLAN
47+
NBVLAN,
48+
NBCustomField
4749
)
4850

4951
vsphere_automation_sdk_available = True
@@ -82,7 +84,8 @@ class VMWareHandler(SourceBase):
8284
NBPrefix,
8385
NBTenant,
8486
NBVRF,
85-
NBVLAN
87+
NBVLAN,
88+
NBCustomField
8689
]
8790

8891
settings = {
@@ -120,7 +123,8 @@ class VMWareHandler(SourceBase):
120123
"strip_host_domain_name": False,
121124
"strip_vm_domain_name": False,
122125
"sync_tags": False,
123-
"sync_parent_tags": False
126+
"sync_parent_tags": False,
127+
"sync_custom_attributes": False
124128
}
125129

126130
deprecated_settings = {}
@@ -772,6 +776,61 @@ def get_object_tags(self, obj, parent=False):
772776

773777
return tag_list
774778

779+
def get_object_custom_fields(self, obj):
780+
"""
781+
Get custom attributes from vCenter for submitted object and as NetBox custom fields
782+
783+
Parameters
784+
----------
785+
obj
786+
pyvmomi object to retrieve custom attributes from
787+
788+
Returns
789+
-------
790+
custom_fields: dict
791+
dictionary with assigned custom fields
792+
"""
793+
794+
return_custom_fields = dict()
795+
796+
custom_value = grab(obj, "customValue", fallback=list())
797+
798+
if self.sync_custom_attributes is False or len(custom_value) == 0:
799+
return return_custom_fields
800+
801+
if grab(obj, "_wsdlName") == "VirtualMachine":
802+
content_type = "virtualization.virtualmachine"
803+
else:
804+
content_type = "dcim.device"
805+
806+
field_definition = {grab(k, "key"): grab(k, "name") for k in grab(obj, "availableField", fallback=list())}
807+
808+
for obj_custom_field in custom_value:
809+
key = grab(obj_custom_field, "key")
810+
value = grab(obj_custom_field, "value")
811+
812+
if key is None or value is None:
813+
continue
814+
815+
label = field_definition.get(key)
816+
817+
if label is None:
818+
continue
819+
820+
name = NetBoxObject.format_slug(f"vcsa-{label}", 50).replace("--", "-").strip("-")
821+
822+
self.add_update_custom_field({
823+
"name": name,
824+
"label": label,
825+
"content_types": [content_type],
826+
"type": "text",
827+
"description": f"vCenter '{self.name}' synced custom attribute '{label}'"
828+
})
829+
830+
return_custom_fields[name] = value
831+
832+
return return_custom_fields
833+
775834
def get_object_relation(self, name, relation, fallback=None):
776835
"""
777836
@@ -1365,6 +1424,11 @@ def add_host(self, obj):
13651424
if len(host_tags) > 0:
13661425
host_data["tags"] = host_tags
13671426

1427+
# add custom fields if present and configured
1428+
host_custom_fields = self.get_object_custom_fields(obj)
1429+
if len(host_custom_fields) > 0:
1430+
host_data["custom_fields"] = host_custom_fields
1431+
13681432
# iterate over hosts virtual switches, needed to enrich data on physical interfaces
13691433
self.network_data["vswitch"][name] = dict()
13701434
for vswitch in grab(obj, "config.network.vswitch", fallback=list()):
@@ -1824,6 +1888,11 @@ def add_virtual_machine(self, obj):
18241888
if len(vm_tags) > 0:
18251889
vm_data["tags"] = vm_tags
18261890

1891+
# add custom fields if present and configured
1892+
vm_custom_fields = self.get_object_custom_fields(obj)
1893+
if len(vm_custom_fields) > 0:
1894+
vm_data["custom_fields"] = vm_custom_fields
1895+
18271896
vm_primary_ip4 = None
18281897
vm_primary_ip6 = None
18291898
vm_default_gateway_ip4 = None

settings-example.ini

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -225,14 +225,17 @@ permitted_subnets = 172.16.0.0/12, 10.0.0.0/8, 192.168.0.0/16, fd00::/8
225225
# strip domain part from VM name before syncing VM to NetBox
226226
#strip_vm_domain_name = False
227227

228-
# sync tags assigned to Hosts and VMs in vCenter to NetBox
228+
# sync tags assigned to hosts and VMs in vCenter to NetBox
229229
# INFO: this requires the installation of the 'vsphere-automation-sdk', ses docs about installation
230230
#sync_tags = False
231231

232232
# sync tags assigned to parent objects to NetBox
233233
# in vCenter this could be a Folder where VMs are grouped in or a cluster a Host belongs to.
234234
#sync_parent_tags = False
235235

236+
# sync custom attributes defined for hosts and VMs in vCenter to NetBox as custom fields
237+
#sync_custom_attributes = False
238+
236239

237240
[source/my-redfish-example]
238241

0 commit comments

Comments
 (0)