Verified Commit 47d3f213 authored by Adrian Schollmeyer's avatar Adrian Schollmeyer
Browse files

parser/host: Add support for parsing VMs

parent 6c751a8b
......@@ -10,7 +10,12 @@ import jinja2
LINUX_PLATFORMS=[
"linux",
"debian",
"gentoo"
"gentoo",
"proxmox" # Proxmox is a Debian
]
LINUX_PLATFORMS_RE=[
re.compile(r"^.*-linux$")
]
j2_env = jinja2.Environment(
......@@ -142,10 +147,15 @@ def main():
config = cli_common.get_config_from_args(args)
netbox = cli_common.create_netbox_instance_from_config(config)
if not args.device_name:
if args.device_name:
netbox_parser = NetBoxParser(netbox, args.device_name, False)
elif args.vm_name:
netbox_parser = NetBoxParser(netbox, args.vm_name, True)
else:
raise Exception("You need to specify a device name!")
host = create_icinga2_host_object_from_netbox(netbox, args.device_name)
host = netbox_parser.create_icinga2_host_object_from_netbox()
#host = Icinga2Host("examplehost", "server", "ritalin", "141.24.40.3",
# "2001:638:904:ffcc::3", 22, "Linux")
......@@ -170,190 +180,336 @@ def create_argument_parser():
cli_common.add_parser_default_args(parser)
parser.add_argument("--device-name", "-d", type=str,
help="Device name to generate config for")
parser.add_argument("--vm-name", "-v", type=str,
help="VM name to generate config for")
return parser
def create_icinga2_host_object_from_netbox(netbox, device_name):
device = netbox.dcim.devices.get(name=device_name)
class NetBoxParser:
def __init__(self, netbox, name, is_vm):
self.netbox = netbox
if is_vm:
self.vm = netbox.virtualization.virtual_machines.get(name=name)
self.device = None
else:
self.vm = None
self.device = netbox.dcim.devices.get(name=name)
if device.primary_ip4:
primary_ip4 = device.primary_ip4.address
else:
primary_ip4 = None
if device.primary_ip6:
primary_ip6 = device.primary_ip6.address
else:
primary_ip6 = None
device_interfaces = netbox.dcim.interfaces.filter(
device_id = device.id
)
uplink_interface = None
non_uplink_ip4s = []
non_uplink_ip6s = []
for interface in device_interfaces:
interface_ips = netbox.ipam.ip_addresses.filter(
interface_id = interface.id
def create_icinga2_host_object_from_netbox(self):
self.fetch_primary_ips()
self.fetch_uplink_and_extra_ips()
parent = self.determine_parent()
self.remove_ip_prefix_lengths()
self.fetch_ssh_services()
self.determine_os_family()
host_class = self.determine_host_class()
if self.device:
name = self.device.name
elif self.vm:
name = self.vm.name
else:
assert False, "Object is neither a device nor a VM"
self.host = Icinga2Host(
name,
host_class,
parent,
self.primary_ip4,
self.primary_ip6,
self.ssh_port,
self.os
)
for interface_ip in interface_ips:
if interface_ip.address == primary_ip4 or \
interface_ip.address == primary_ip6:
uplink_interface = interface
else:
if interface_ip.family.value == 4:
non_uplink_ip4s.append(make_ip_without_prefix_length(interface_ip.address))
elif interface_ip.family.value == 6:
non_uplink_ip6s.append(make_ip_without_prefix_length(interface_ip.address))
else:
raise Exception(f"Unknown IP family {interface_ip.family}"
f" for IP {interface_ip}")
if not uplink_interface:
raise Exception(
f"Can't determine uplink interface for device {device_name}")
parent = "bigsister"
if uplink_interface.connected_endpoint:
parent = uplink_interface.connected_endpoint.device.name
if primary_ip4:
primary_ip4 = make_ip_without_prefix_length(primary_ip4)
if primary_ip6:
primary_ip6 = make_ip_without_prefix_length(primary_ip6)
ssh_services = netbox.ipam.services.filter(
device_id = device.id,
name = "SSH"
)
ssh_port = None
ssh_ports = []
for ssh_service in ssh_services:
for p in ssh_service.ports:
if ssh_port is None:
ssh_port = p
if ssh_port == p:
continue
ssh_ports.append(p)
os = None
if device.platform:
device_platform = device.platform.slug
for linux_platform in LINUX_PLATFORMS:
if device_platform == linux_platform:
os = "Linux"
break
host = Icinga2Host(
device_name,
"server",
parent,
primary_ip4,
primary_ip6,
ssh_port,
os
)
if device.device_role.slug == "vm-host":
host.host_class = "vm-host"
for ip4 in non_uplink_ip4s:
host.add_ip(ip4)
for ip6 in non_uplink_ip6s:
host.add_ip6(ip6)
for ssh_port in ssh_ports:
host.add_ssh(ssh_port)
contact_assignments = netbox.tenancy.contact_assignments.filter(
object_id = device.id,
content_type = "dcim.device",
role = "adminc"
)
for contact_assignment in contact_assignments:
contact = netbox.tenancy.contacts.get(id=contact_assignment.contact.id)
if not contact.custom_fields["ldap"]:
continue
if contact.custom_fields["xmpp"]:
host.add_xmpp_notification(contact.custom_fields["ldap"])
host.add_webaccess(contact.custom_fields["ldap"])
monitored_inventory_smart = netbox.dcim.inventory_items.filter(
device_id = device.id,
tag = "monitoring-check-smart"
)
for inventory_item in monitored_inventory_smart:
host.add_smart(inventory_item.name)
monitored_inventory_smart_sectors = netbox.dcim.inventory_items.filter(
device_id = device.id,
tag = "monitoring-check-smart-sectors"
)
for inventory_item in monitored_inventory_smart_sectors:
host.add_smart_sectors(inventory_item.name)
monitored_inventory_diskio = netbox.dcim.inventory_items.filter(
device_id = device.id,
tag = "monitoring-check-diskio"
)
for inventory_item in monitored_inventory_diskio:
host.add_disk_io(inventory_item.name)
monitored_inventory_temp = netbox.dcim.inventory_items.filter(
device_id = device.id,
tag = "monitoring-check-temp"
)
for inventory_item in monitored_inventory_temp:
host.add_disk_temp(inventory_item.name)
try:
apt = device.custom_fields["check_apt"]
if apt == "active":
host.add_apt_active()
elif apt == "passive":
host.add_apt_passive()
self.add_ip_checks()
self.add_ssh_checks()
self.add_notifications()
if self.device:
self.add_check_by_inventory_tag("monitoring-check-smart",
self.host.add_smart)
self.add_check_by_inventory_tag("monitoring-check-smart-sectors",
self.host.add_smart_sectors)
self.add_check_by_inventory_tag("monitoring-check-diskio",
self.host.add_disk_io)
self.add_check_by_inventory_tag("monitoring-check-temp",
self.host.add_disk_temp)
self.add_apt_check()
self.add_checks_from_config_context()
return self.host
def fetch_primary_ips(self):
if self.device:
obj = self.device
elif self.vm:
obj = self.vm
else:
# Not one of the predefined values means APT checking is not
# enabled
pass
except KeyError:
pass
assert False, "Object is neither a device nor a VM"
try:
monitoring_config_context = device.config_context["monitoring"]
if obj.primary_ip4:
self.primary_ip4 = obj.primary_ip4.address
else:
self.primary_ip4 = None
try:
if monitoring_config_context["nrpe_enabled"]:
host.enable_nrpe()
try:
for nrpe_check in monitoring_config_context["nrpe_checks"]:
host.add_nrpe_check(nrpe_check)
except KeyError:
pass
try:
for nrpe_disk in monitoring_config_context["nrpe_disks"]:
host.add_nrpe_disk(nrpe_disk)
except KeyError:
pass
except KeyError:
pass
if obj.primary_ip6:
self.primary_ip6 = obj.primary_ip6.address
else:
self.primary_ip6 = None
def fetch_uplink_and_extra_ips(self):
if self.device:
device_interfaces = self.netbox.dcim.interfaces.filter(
device_id = self.device.id
)
self.uplink_interface = None
self.non_uplink_ip4s = []
self.non_uplink_ip6s = []
for interface in device_interfaces:
interface_ips = self.netbox.ipam.ip_addresses.filter(
interface_id = interface.id
)
for interface_ip in interface_ips:
if interface_ip.address == self.primary_ip4 or \
interface_ip.address == self.primary_ip6:
self.uplink_interface = interface
else:
if interface_ip.family.value == 4:
self.non_uplink_ip4s.append(
self.make_ip_without_prefix_length(interface_ip.address))
elif interface_ip.family.value == 6:
self.non_uplink_ip6s.append(
self.make_ip_without_prefix_length(interface_ip.address))
else:
raise Exception(f"Unknown IP family {interface_ip.family}"
f" for IP {interface_ip}")
if not self.uplink_interface:
raise Exception(
"Can't determine uplink interface for device"
f" {self.device.display}")
elif self.vm:
vm_interfaces = self.netbox.virtualization.interfaces.filter(
virtual_machine_id = self.vm.id
)
self.non_uplink_ip4s = []
self.non_uplink_ip6s = []
for interface in vm_interfaces:
interface_ips = self.netbox.ipam.ip_addresses.filter(
vminterface_id = interface.id
)
for ip in interface_ips:
if ip == self.primary_ip4 or ip == self.primary_ip6:
continue
if ip.family.value == 4:
self.non_uplink_ip4s.append(
self.make_ip_without_prefix_length(ip.address))
elif ip.family.value == 6:
self.non_uplink_ip6s.append(
self.make_ip_without_prefix_length(ip.address))
else:
assert False, f"Unknown IP family {ip.family.value}"
else:
assert False, "Object is neither a device nor a VM"
def determine_parent(self):
if self.device:
parent = "bigsister"
if self.uplink_interface.connected_endpoint:
parent = self.uplink_interface.connected_endpoint.device.name
elif self.vm:
parent = self.vm.cluster.name
else:
assert False, "Object is neither a device nor a VM"
return parent
def remove_ip_prefix_lengths(self):
if self.primary_ip4:
self.primary_ip4 = self.make_ip_without_prefix_length(
self.primary_ip4)
if self.primary_ip6:
self.primary_ip6 = self.make_ip_without_prefix_length(
self.primary_ip6)
def fetch_ssh_services(self):
if self.device:
ssh_services = self.netbox.ipam.services.filter(
device_id = self.device.id,
name = "SSH"
)
elif self.vm:
ssh_services = self.netbox.ipam.services.filter(
virtual_machine_id = self.vm.id
)
else:
assert False, "Object is neither a device nor a VM"
self.ssh_port = None
self.ssh_ports = []
for ssh_service in ssh_services:
for p in ssh_service.ports:
if self.ssh_port is None:
self.ssh_port = p
if self.ssh_port == p:
continue
self.ssh_ports.append(p)
def determine_os_family(self):
self.os = None
if self.device:
platform = self.device.platform
elif self.vm:
platform = self.vm.platform
else:
assert False, "Object is neither a device nor a VM"
if platform:
self.device_platform = platform.slug
for linux_platform in LINUX_PLATFORMS:
if self.device_platform == linux_platform:
self.os = "Linux"
break
for linux_platform_re in LINUX_PLATFORMS_RE:
if linux_platform_re.match(self.device_platform):
self.os = "Linux"
break
def determine_host_class(self):
if self.device:
role_slug = self.device.device_role.slug
elif self.vm:
role_slug = self.vm.role.slug
if role_slug == "vm-host":
return "vm-host"
return "server"
def add_ip_checks(self):
for ip4 in self.non_uplink_ip4s:
self.host.add_ip(ip4)
for ip6 in self.non_uplink_ip6s:
self.host.add_ip6(ip6)
def add_ssh_checks(self):
for ssh_port in self.ssh_ports:
self.host.add_ssh(ssh_port)
def add_notifications(self):
if self.device:
contact_assignments = self.netbox.tenancy.contact_assignments.filter(
object_id = self.device.id,
content_type = "dcim.device",
role = "adminc"
)
elif self.vm:
contact_assignments = self.netbox.tenancy.contact_assignments.filter(
object_id = self.vm.id,
content_type = "virtualization.virtualmachine",
role = "adminc"
)
for contact_assignment in contact_assignments:
contact = self.netbox.tenancy.contacts.get(id=contact_assignment.contact.id)
if not contact.custom_fields["ldap"]:
continue
if contact.custom_fields["xmpp"]:
self.host.add_xmpp_notification(contact.custom_fields["ldap"])
self.host.add_webaccess(contact.custom_fields["ldap"])
def add_check_by_inventory_tag(self, tag, add):
inventory = self.netbox.dcim.inventory_items.filter(
device_id = self.device.id,
tag = tag
)
for inventory_item in inventory:
add(inventory_item)
def add_apt_check(self):
try:
if monitoring_config_context["procs"]:
for proc in monitoring_config_context["procs"]:
host.add_procs_check(proc)
if self.device:
apt = self.device.custom_fields["check_apt"]
elif self.vm:
apt = self.vm.custom_fields["check_apt"]
else:
assert False, "Object is neither a device nor a VM"
if apt == "active":
self.host.add_apt_active()
elif apt == "passive":
self.host.add_apt_passive()
else:
# Not one of the predefined values means APT checking is not
# enabled
pass
except KeyError:
pass
except KeyError as e:
pass # So there is no extra monitoring config. Who cares anyway?
return host
def make_ip_without_prefix_length(ip):
return re.sub(r"^(.*)/(.*)$", "\\1", ip)
def add_checks_from_config_context(self):
try:
if self.device:
monitoring_config_context = self.device.config_context["monitoring"]
elif self.vm:
monitoring_config_context = self.vm.config_context["monitoring"]
else:
assert False, "Object is neither a device nor a VM"
try:
if monitoring_config_context["nrpe_enabled"]:
self.host.enable_nrpe()
try:
for nrpe_check in monitoring_config_context["nrpe_checks"]:
self.host.add_nrpe_check(nrpe_check)
except KeyError:
pass
try:
for nrpe_disk in monitoring_config_context["nrpe_disks"]:
self.host.add_nrpe_disk(nrpe_disk)
except KeyError:
pass
except KeyError:
pass
try:
if monitoring_config_context["procs"]:
for proc in monitoring_config_context["procs"]:
self.host.add_procs_check(proc)
except KeyError:
pass
except KeyError as e:
pass # So there is no extra monitoring config. Who cares anyway?
@staticmethod
def make_ip_without_prefix_length(ip):
return re.sub(r"^(.*)/(.*)$", "\\1", ip)
if __name__ == "__main__":
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment