Skip to content

Commit

Permalink
adds syncing of vCenter Custom Attributes #114
Browse files Browse the repository at this point in the history
  • Loading branch information
bb-Ricardo committed Oct 31, 2021
1 parent 3152368 commit ce5eb04
Show file tree
Hide file tree
Showing 5 changed files with 107 additions and 32 deletions.
6 changes: 4 additions & 2 deletions module/netbox/object_classes.py
Original file line number Diff line number Diff line change
Expand Up @@ -1013,7 +1013,8 @@ class NBCustomField(NetBoxObject):
"dcim.interface",
"dcim.inventoryitem",
"dcim.powerport",
"virtualization.vminterface"
"virtualization.vminterface",
"virtualization.virtualmachine"
]

def __init__(self, *args, **kwargs):
Expand Down Expand Up @@ -1424,7 +1425,8 @@ def __init__(self, *args, **kwargs):
"primary_ip4": object,
"primary_ip6": object,
"tags": NBTagList,
"tenant": NBTenant
"tenant": NBTenant,
"custom_fields": NBCustomField
}
super().__init__(*args, **kwargs)

Expand Down
25 changes: 0 additions & 25 deletions module/sources/check_redfish/import_inventory.py
Original file line number Diff line number Diff line change
Expand Up @@ -1028,31 +1028,6 @@ def update_item(self, item_data: dict, inventory_object: NBInventoryItem = None)

return

def add_update_custom_field(self, data):
"""
Adds/updates a NBCustomField object with data.
Update will only update the 'content_types' attribute.
Parameters
----------
data: dict
dictionary with NBCustomField attributes
Returns
-------
custom_field: NBCustomField
new or updated NBCustomField
"""

custom_field = self.inventory.get_by_data(NBCustomField, data={"name": data.get("name")})

if custom_field is None:
custom_field = self.inventory.add_object(NBCustomField, data=data, source=self)
else:
custom_field.update(data={"content_types": data.get("content_types")}, source=self)

return custom_field

def add_necessary_base_objects(self):
"""
Adds/updates source tag and all custom fields necessary for this source.
Expand Down
28 changes: 27 additions & 1 deletion module/sources/common/source_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@
NBSite,
NBPrefix,
NBIPAddress,
NBVLAN
NBVLAN,
NBCustomField
)
from module.common.logging import get_logger
from module.common.misc import grab
Expand Down Expand Up @@ -613,4 +614,29 @@ def get_vlan_object_if_exists(self, vlan_data=None, vlan_site=None):

return return_data

def add_update_custom_field(self, data):
"""
Adds/updates a NBCustomField object with data.
Update will only update the 'content_types' attribute.
Parameters
----------
data: dict
dictionary with NBCustomField attributes
Returns
-------
custom_field: NBCustomField
new or updated NBCustomField
"""

custom_field = self.inventory.get_by_data(NBCustomField, data={"name": data.get("name")})

if custom_field is None:
custom_field = self.inventory.add_object(NBCustomField, data=data, source=self)
else:
custom_field.update(data={"content_types": data.get("content_types")}, source=self)

return custom_field

# EOF
75 changes: 72 additions & 3 deletions module/sources/vmware/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
from module.common.misc import grab, dump, get_string_or_none, plural
from module.common.support import normalize_mac_address, ip_valid_to_add_to_netbox
from module.netbox.object_classes import (
NetBoxObject,
NetBoxInterfaceType,
NBTag,
NBManufacturer,
Expand All @@ -43,7 +44,8 @@
NBPrefix,
NBTenant,
NBVRF,
NBVLAN
NBVLAN,
NBCustomField
)

vsphere_automation_sdk_available = True
Expand Down Expand Up @@ -82,7 +84,8 @@ class VMWareHandler(SourceBase):
NBPrefix,
NBTenant,
NBVRF,
NBVLAN
NBVLAN,
NBCustomField
]

settings = {
Expand Down Expand Up @@ -120,7 +123,8 @@ class VMWareHandler(SourceBase):
"strip_host_domain_name": False,
"strip_vm_domain_name": False,
"sync_tags": False,
"sync_parent_tags": False
"sync_parent_tags": False,
"sync_custom_attributes": False
}

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

return tag_list

def get_object_custom_fields(self, obj):
"""
Get custom attributes from vCenter for submitted object and as NetBox custom fields
Parameters
----------
obj
pyvmomi object to retrieve custom attributes from
Returns
-------
custom_fields: dict
dictionary with assigned custom fields
"""

return_custom_fields = dict()

custom_value = grab(obj, "customValue", fallback=list())

if self.sync_custom_attributes is False or len(custom_value) == 0:
return return_custom_fields

if grab(obj, "_wsdlName") == "VirtualMachine":
content_type = "virtualization.virtualmachine"
else:
content_type = "dcim.device"

field_definition = {grab(k, "key"): grab(k, "name") for k in grab(obj, "availableField", fallback=list())}

for obj_custom_field in custom_value:
key = grab(obj_custom_field, "key")
value = grab(obj_custom_field, "value")

if key is None or value is None:
continue

label = field_definition.get(key)

if label is None:
continue

name = NetBoxObject.format_slug(f"vcsa-{label}", 50).replace("--", "-").strip("-")

self.add_update_custom_field({
"name": name,
"label": label,
"content_types": [content_type],
"type": "text",
"description": f"vCenter '{self.name}' synced custom attribute '{label}'"
})

return_custom_fields[name] = value

return return_custom_fields

def get_object_relation(self, name, relation, fallback=None):
"""
Expand Down Expand Up @@ -1365,6 +1424,11 @@ def add_host(self, obj):
if len(host_tags) > 0:
host_data["tags"] = host_tags

# add custom fields if present and configured
host_custom_fields = self.get_object_custom_fields(obj)
if len(host_custom_fields) > 0:
host_data["custom_fields"] = host_custom_fields

# iterate over hosts virtual switches, needed to enrich data on physical interfaces
self.network_data["vswitch"][name] = dict()
for vswitch in grab(obj, "config.network.vswitch", fallback=list()):
Expand Down Expand Up @@ -1824,6 +1888,11 @@ def add_virtual_machine(self, obj):
if len(vm_tags) > 0:
vm_data["tags"] = vm_tags

# add custom fields if present and configured
vm_custom_fields = self.get_object_custom_fields(obj)
if len(vm_custom_fields) > 0:
vm_data["custom_fields"] = vm_custom_fields

vm_primary_ip4 = None
vm_primary_ip6 = None
vm_default_gateway_ip4 = None
Expand Down
5 changes: 4 additions & 1 deletion settings-example.ini
Original file line number Diff line number Diff line change
Expand Up @@ -225,14 +225,17 @@ permitted_subnets = 172.16.0.0/12, 10.0.0.0/8, 192.168.0.0/16, fd00::/8
# strip domain part from VM name before syncing VM to NetBox
#strip_vm_domain_name = False

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

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

# sync custom attributes defined for hosts and VMs in vCenter to NetBox as custom fields
#sync_custom_attributes = False


[source/my-redfish-example]

Expand Down

0 comments on commit ce5eb04

Please sign in to comment.