Skip to content

Commit

Permalink
Sync services tagged "Offnet Ports Open" in netbox to zabbix host mac…
Browse files Browse the repository at this point in the history
…ros TCP_OPEN_PORTS and UDP_OPEN_PORTS.

For SOC-4334.
  • Loading branch information
eric-eisenhart committed Oct 1, 2024
1 parent 4ea95fb commit e408015
Show file tree
Hide file tree
Showing 2 changed files with 128 additions and 7 deletions.
38 changes: 32 additions & 6 deletions src/sonic/netbox_zabbix/netbox.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,38 @@ def get_sites_smart_filter(self) -> list:
sites.append(site)
return sites

@functools.cache
def get_cluster_by_id(self, id):
"""This basically just exists for caching"""
log.debug(id)
return self.api.virtualization.clusters.get(id)

##########################
# Individual Server Info #
##########################

@functools.cache
def get_server_services_all(self, server):
log.warning(server)
server_id = server.id
if self.is_virtual(server):
services = self.api.ipam.services.filter(virtual_machine_id=server_id)
else:
services = self.api.ipam.services.filter(device_id=server_id)
log.warning(f"services count: {len(services)}")
return list(services)

@functools.cache
def get_server_services_offnet(self, server):
log.warning(server)
server_id = server.id
if self.is_virtual(server):
services = self.api.ipam.services.filter(tag="offnet-ports-open", virtual_machine_id=server_id)
else:
services = self.api.ipam.services.filter(tag="offnet-ports-open", device_id=server_id)
log.warning(f"services count: {len(services)}")
return list(services)

@functools.cache
def is_physical(self, server) -> bool:
log.debug(server)
Expand All @@ -116,12 +148,6 @@ def is_virtual(self, server) -> bool:
else:
return False

@functools.cache
def get_cluster_by_id(self, id):
"""This basically just exists for caching"""
log.debug(id)
return self.api.virtualization.clusters.get(id)

@functools.cache
def virt_type(self, server) -> bool:
log.debug(server)
Expand Down
97 changes: 96 additions & 1 deletion src/sonic/netbox_zabbix/netbox_zabbix.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,11 @@ def _parseargs(cls):
action="store_true",
help="Don't update Zabbix Macros from netbox data",
)
argparser.add(
"--skip-services",
action="store_true",
help="Don't update Zabbix ports macros from netbox service data",
)
argparser.add(
"--skip-tags",
action="store_true",
Expand Down Expand Up @@ -515,7 +520,6 @@ def copy_netbox_info_to_zabbix_inventory(self, netbox_servers, zabbix_servers):

@functools.cache
def site_to_path(self, site) -> str:

# region / group / provider / tenant / site

parts = ["Sites"]
Expand Down Expand Up @@ -655,6 +659,94 @@ def copy_netbox_ipmi_to_zabbix(self, netbox_servers, zabbix_servers):
else:
log.debug(f"{name}: no IPMI IP")

def copy_netbox_services_to_zabbix(self, netbox_servers, zabbix_servers):
"""_Copy Netbox Service info to Zabbix_
1. Pull TCP Services tagged offnet-ports-open into {$TCP_OPEN_PORTS}.
2. Pull UDP Services tagged offnet-ports-open into {$UDP_OPEN_PORTS}.
Format of Macros is comma-separated numeric ports, like `22,80,443`.
Sort ports numerically just to reduce change churn.
Args:
netbox_servers (_list_): _Netbox Servers_
zabbix_servers (_list_): _Zabbix Servers_
"""
for name in zabbix_servers:
if name in netbox_servers and netbox_servers[name]:
if config.verbose >= 4: # 4
log.debug(f"TRACE:{name}:Services")
nbsrv = netbox_servers[name]
zbsrv = zabbix_servers[name]

if config.verbose >= 4: # 4
log.debug(pformat(dict(nbsrv)))

services = self.netbox.get_server_services_offnet(nbsrv)
# log.warning(pformat(services))

open_tcp_ports = []
open_udp_ports = []
for service in services:
log.warning(pformat(dict(service)))
if service.protocol.value == "tcp":
open_tcp_ports.extend(service.ports)
elif service.protocol.value == "udp":
open_udp_ports.extend(service.ports)
else:
log.error(f"Unknown port protocol {service.protocol.label}")
log.debug(pformat(service))

# Make sure order stays the same:
open_tcp_ports.sort()
open_udp_ports.sort()

# Stringify those ints
open_tcp_ports = list(map(str, open_tcp_ports))
open_udp_ports = list(map(str, open_udp_ports))

log.warning(f"open_tcp_ports: {open_tcp_ports}")
log.warning(f"open_udp_ports: {open_udp_ports}")

# Pull current macros in, minus {$TCP_OPEN_PORTS} and {$UDP_OPEN_PORTS}
if "macros" in zabbix_servers[name]:
macros = zabbix_servers[name]["macros"]
log.debug(f"macros(pre): {pformat(macros)}")
macros = [item for item in macros if not item["macro"].startswith("{$TCP_OPEN_PORTS}")]
macros = [item for item in macros if not item["macro"].startswith("{$UDP_OPEN_PORTS}")]
else:
macros = []
log.debug(f"macros(post): {pformat(macros)}")

if open_tcp_ports and len(open_tcp_ports) >= 1:
macros.append(
{
"macro": "{$TCP_OPEN_PORTS}",
"value": ",".join(open_tcp_ports),
"description": "Synced from Netbox based on offnet-ports-open tag on services",
}
)

if open_udp_ports and len(open_udp_ports) >= 1:
macros.append(
{
"macro": "{$UDP_OPEN_PORTS}",
"value": ",".join(open_udp_ports),
"description": "Synced from Netbox based on offnet-ports-open tag on services",
}
)

# Actually save changes #
if macros:
log.debug(f"Macros for {name}: {pformat(macros)}")
self.zabbix.host_update_macros(
hostid=zabbix_servers[name]["hostid"],
macros=macros,
)
else:
log.warning(f"No Macros updates for {name}")

def run(self):
"""Run cli app with the given arguments."""
log.debug("Starting run()")
Expand Down Expand Up @@ -705,6 +797,9 @@ def run(self):
if not config.skip_macros:
self.copy_netbox_info_to_zabbix_macros(netbox_server_dict, zabbix_server_dict)

if not config.skip_services:
self.copy_netbox_services_to_zabbix(netbox_server_dict, zabbix_server_dict)

if not config.skip_tags:
self.copy_netbox_info_to_zabbix_tags(netbox_server_dict, zabbix_server_dict)

Expand Down

0 comments on commit e408015

Please sign in to comment.