From f1db89888ec444de2ab5d69f07506a1fafb87e47 Mon Sep 17 00:00:00 2001 From: "Th.L" <thl-cmk@outlook.com> Date: Sun, 11 Jul 2021 20:21:43 +0200 Subject: [PATCH] update project --- agent_based/inv_cisco_wlc_aps_lwap.py | 419 ++++++++++++++++++++ inv_cisco_wlc_aps_lwap.mkp | Bin 6107 -> 6395 bytes packages/inv_cisco_wlc_aps_lwap | 24 +- web/plugins/views/inv_cisco_wlc_aps_lwap.py | 72 ++++ web/plugins/wato/inv_cisco_wlc_aps_lwap.py | 104 +++++ 5 files changed, 610 insertions(+), 9 deletions(-) create mode 100644 agent_based/inv_cisco_wlc_aps_lwap.py create mode 100644 web/plugins/views/inv_cisco_wlc_aps_lwap.py create mode 100644 web/plugins/wato/inv_cisco_wlc_aps_lwap.py diff --git a/agent_based/inv_cisco_wlc_aps_lwap.py b/agent_based/inv_cisco_wlc_aps_lwap.py new file mode 100644 index 0000000..97253c4 --- /dev/null +++ b/agent_based/inv_cisco_wlc_aps_lwap.py @@ -0,0 +1,419 @@ +# !/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# License: GNU General Public License v2 +# +# Author: thl-cmk[at]outlook[dot]com +# URL : https://thl-cmk.hopto.org +# Date : 2016-04-08 +# +# inventory of cisco wlc aps +# +# 2016-08-22 : removed index column +# 2018-08-04 : changed scan function, code cleanup +# 2018-09-04 : changes for CMK 1.5.x (inv_tree --> inv_tree_list) +# 2021-07-11 : rewritten for CMK 2.0 + +import re +import time +import binascii +from typing import List, NamedTuple + +from cmk.base.plugins.agent_based.agent_based_api.v1 import ( + OIDEnd, + OIDBytes, +) +from cmk.base.plugins.agent_based.agent_based_api.v1 import ( + register, + SNMPTree, + TableRow, + contains, +) +from cmk.base.plugins.agent_based.agent_based_api.v1.type_defs import ( + StringTable, + InventoryResult, +) + +_last_reboot_reason = { + 0: 'none', + 1: 'dot11gModeChange', + 2: 'ipAddressSet', + 3: 'ipAddressReset', + 4: 'rebootFromController', + 5: 'dhcpFallbackFail', + 6: 'discoveryFail', + 7: 'noJoinResponse', + 8: 'denyJoin', + 9: 'noConfigResponse', + 10: 'configController', + 11: 'imageUpgradeSuccess', + 12: 'imageOpcodeInvalid', + 13: 'imageCheckSumInvalid', + 14: 'imageDataTimeout', + 15: 'configFileInvalid', + 16: 'imageDownloadError', + 17: 'rebootFromConsole', + 18: 'rapOverAir', + 19: 'powerLow', + 20: 'crash', + 21: 'powerHigh', + 22: 'powerLoss', + 23: 'powerChange', + 24: 'componentFailure', + 25: 'watchdog', +} + +_enable_disable = { + 0: 'N/A', + 1: 'enabled', + 2: 'disabled', +} + +_failover_pirority = { + 0: 'N/A', + 1: 'low', + 2: 'medium', + 3: 'high', + 4: 'critical', +} + +_power_status = { + 0: 'N/A', + 1: 'low', + 2: '15.4W', + 3: '16.8W', + 4: 'full', + 5: 'external', + 6: 'mixedmode', +} + +_pwr_injector_selection = { + 0: 'N/A', + 1: 'unknown', + 2: 'installed', + 3: 'override', +} + +_monitor_mode_optimization = { + 0: 'N/A', + 1: 'all', + 2: 'tracking', + 3: 'wips', + 4: 'none', +} + +_encryption_supported = { + 0: 'N/A', + 1: 'yes', + 2: 'no', +} + +_inet_address_type = { + 0: 'N/A', + 1: 'ipv4', + 2: 'ipv6', + 3: 'ipv4z', + 4: 'ipv6z', + 16: 'dns', +} + +_antenna_band_mode = { + 0: 'N/A', + 1: 'not applicable', + 2: 'single', + 3: 'dual', +} + +_venueconfigvenuegroup = { + 0: 'N/A', + 1: 'unspecified', + 2: 'assembly', + 3: 'business', + 4: 'educational', + 5: 'factory and industrial', + 6: 'institutional', + 7: 'mercantile', + 8: 'residential', + 9: 'storage', + 10: 'utility and misc', + 11: 'vehicular', + 12: 'outdoor', +} + +_venueconfigvenuetype = { + 0: 'N/A', + 1: 'unspecified', + 2: 'unspecified assembly', + 3: 'arena', + 4: 'stadium', + 5: 'passenger terminal', + 6: 'amphitheater', + 7: 'amusement park', + 8: 'place of worship', + 9: 'convention center', + 10: 'library', + 11: 'museum', + 12: 'restaurant', + 13: 'theater', + 14: 'bar', + 15: 'coffee shop', + 16: 'zoo or aquarium', + 17: 'emergency coordination center', + 18: 'unspecified business', + 19: 'doctor or dentist office', + 20: 'bank', + 21: 'firestation', + 22: 'policestation', + 23: 'postoffice', + 24: 'professional office', + 25: 'research and development facility', + 26: 'attorney office', + 27: 'unspecified educational', + 28: 'school primary', + 29: 'school secondary', + 30: 'university or college', + 31: 'unspecified factory and industrial', + 32: 'factory', + 33: 'unspecified institutional', + 34: 'hospital', + 35: 'longterm carefacility', + 36: 'alcohol and drug rehabilitation center', + 37: 'group home', + 38: 'prison or jail', + 39: 'unspecified mercantile', + 40: 'retail store', + 41: 'grocery market', + 42: 'auomotive service station', + 43: 'shoppin gmall', + 44: 'gas station', + 45: 'unspecified residential', + 46: 'privat eresidence', + 47: 'hotel or motel', + 48: 'dormitory', + 49: 'boarding house', + 50: 'unspecified storage', + 51: 'unspecified utility', + 52: 'unspecified vehicular', + 53: 'automobile or truck', + 54: 'airplane', + 55: 'bus', + 56: 'ferry', + 57: 'ship or boat', + 58: 'train', + 59: 'motorbike', + 60: 'unspecified outdoor', + 61: 'muni mesh network', + 62: 'citypark', + 63: 'restarea', + 64: 'traffic control', + 65: 'busstop', + 66: 'kiosk', +} + +_apsubmode = { + 0: 'N/A', + 1: 'none', + 2: 'wips', + 3: 'pppoe', + 4: 'pppoewips', +} + + +def _render_mac_address(bytestring): + return ':'.join(['%02s' % hex(ord(m))[2:] for m in bytestring]).replace(' ', '0').upper() + + +def _render_ip_address(bytestring): + return '.'.join(['%s' % ord(m) for m in bytestring]) + + +def parse_inv_cisco_wlc_aps_lwap(string_table: StringTable): + aps = [] + + for ap in string_table: + wlcprimaryaddress = ap[5] + if _inet_address_type.get(int(ap[4])) == 'ipv4': + wlcprimaryaddress = _render_ip_address(wlcprimaryaddress) + + wlcsecondaryaddress = ap[7] + if _inet_address_type.get(int(ap[6])) == 'ipv4': + wlcsecondaryaddress = _render_ip_address(wlcsecondaryaddress) + + wlctertiaryaddress = ap[9] + if _inet_address_type.get(int(ap[8])) == 'ipv4': + wlctertiaryaddress = _render_ip_address(wlctertiaryaddress) + + aps.append({ + 'if_mac_address': _render_mac_address(ap[0]), + 'max_#_of_dot11_slots': ap[1], + 'name': ap[2], + 'max_#_of_ethernet_slots': ap[3], + 'encryption_supported': _encryption_supported.get(int(ap[23])), + 'tcp_mss': ap[25], + 'data_encryption': _enable_disable.get(int(ap[26])), + 'port_number': ap[28], + 'venue_config_venue_group': _venueconfigvenuegroup.get(int(ap[29])), + 'venue_config_venue_type': _venueconfigvenuetype.get(int(ap[30])), + 'venue_config_venue_name': ap[31], + 'venue_config_language': ap[32], + 'trunk_vlan': ap[34], + 'location': ap[36], + 'floor_label': ap[45], + 'module_inserted': ap[49], + 'status_columns': { + 'antenna_band_mode': _antenna_band_mode.get(int(ap[48])), + 'encryption': _enable_disable.get(int(ap[11])), + 'failover_priority': _failover_pirority.get(int(ap[12])), + 'power_status': _power_status.get(int(ap[13])), + 'telnet': _enable_disable.get(int(ap[14])), + 'ssh': _enable_disable.get(int(ap[15])), + 'pwr_pre_std_state': _enable_disable.get(int(ap[16])), + 'pwr_injector_state': _enable_disable.get(int(ap[17])), + 'pwr_injector_selection': _pwr_injector_selection.get(int(ap[18])), + 'pwr_injector_sw_mac_addr': _render_mac_address(ap[19]), + 'wips': _enable_disable.get(int(ap[20])), + 'monitor_mode_optimization': _monitor_mode_optimization.get(int(ap[18])), + 'amsdu': _enable_disable.get(int(ap[22])), + 'admin': _enable_disable.get(int(ap[27])), + 'rogue_detection': _enable_disable.get(int(ap[24])), + 'led_state': _enable_disable.get(int(ap[33])), + 'trunk_vlan_status': _enable_disable.get(int(ap[35])), + 'submode': _apsubmode.get(int(ap[37])), + 'real_time_stats_mode_enabled': _enable_disable.get(int(ap[38])), + 'upgrade_from_version': ap[39], + 'upgrade_to_version': ap[40], + 'upgrade_failure_cause': ap[41], + 'adj_channel_rogue_enabled': ap[46], + 'sys_net_id': ap[47], + 'enable_module': _enable_disable.get(int(ap[50])), + 'is_universal': _enable_disable.get(int(ap[51])), + 'universal_prime_status': ap[52], + 'is_master': _enable_disable.get(int(ap[53])), + 'ble_fw_download_status': _enable_disable.get(int(ap[54])), + 'max_client_limit_number_trap': ap[42], + 'max_client_limit_cause': ap[43], + 'max_client_limit_set': _enable_disable.get(int(ap[44])), + 'wlc_primary_address': wlcprimaryaddress, + 'wlc_secondary_address': wlcsecondaryaddress, + 'wlc_tertiary_address': wlctertiaryaddress, + 'last_reboot_reason': _last_reboot_reason.get(int(ap[10])), + } + }) + + return aps + + +def inventory_wlc_aps_lwap(params, section) -> InventoryResult: + removecolumns = [] + + if params: + removecolumns = params.get('removecolumns', removecolumns) + + path = ['networking', 'wlan', 'controller', 'accesspoints_lwap'] + + for ap in section: + key_columns = {'if_mac_address': ap['if_mac_address']} + + for key in key_columns.keys(): + ap.pop(key) + + for entry in removecolumns: + try: + ap.pop(entry) + except KeyError: + pass + + status_columns = ap.get('status_columns', None) + for entry in removecolumns: + try: + status_columns.pop(entry) + except KeyError: + pass + + try: + ap.pop('status_columns') + except KeyError: + pass + + yield TableRow( + path=path, + key_columns=key_columns, + inventory_columns=ap, + status_columns=status_columns, + ) + +register.snmp_section( + name='inv_cisco_wlc_aps_lwap', + parse_function=parse_inv_cisco_wlc_aps_lwap, + fetch= + SNMPTree( + base='.1.3.6.1.4.1.9.9.513.1.1.1.1', # CISCO-LWAPP-AP-MIB::cLApEntry + oids=[ + '2', # cLApIfMacAddress (2) + '3', # cLApMaxNumberOfDot11Slots (3) + '5', # cLApName (5) + '9', # cLApMaxNumberOfEthernetSlots (9) + '10', # cLApPrimaryControllerAddressType (10) + '11', # cLApPrimaryControllerAddress (11) + '12', # cLApSecondaryControllerAddressType (12) + '13', # cLApSecondaryControllerAddress (13) + '14', # cLApTertiaryControllerAddressType (14) + '15', # cLApTertiaryControllerAddress (15) + '16', # cLApLastRebootReason (16) + '18', # cLApEncryptionEnable (18) + '19', # cLApFailoverPriority (19) + '20', # cLApPowerStatus (20) + '21', # cLApTelnetEnable (21) + '22', # cLApSshEnable (22) + '23', # cLApPreStdStateEnabled (23) + '24', # cLApPwrInjectorStateEnabled (24) + '25', # cLApPwrInjectorSelection (25) + '26', # cLApPwrInjectorSwMacAddr (26) + '27', # cLApWipsEnable (27) + '28', # cLApMonitorModeOptimization (28) + '32', # cLApAMSDUEnable (32) + '33', # cLApEncryptionSupported (33) + '34', # cLApRogueDetectionEnabled (34) + '35', # cLApTcpMss (35) + '36', # cLApDataEncryptionStatus (36) + '38', # cLApAdminStatus (38) + '39', # cLApPortNumber (39) + + '42', # cLApVenueConfigVenueGroup + '43', # cLApVenueConfigVenueType + '44', # cLApVenueConfigVenueName + '45', # cLApVenueConfigLanguage + '46', # cLApLEDState + '47', # cLApTrunkVlan + '48', # cLApTrunkVlanStatus + '49', # cLApLocation + '50', # cLApSubMode + '53', # cLApRealTimeStatsModeEnabled + '59', # cLApUpgradeFromVersion + '60', # cLApUpgradeToVersion + '61', # cLApUpgradeFailureCause + '62', # cLApMaxClientLimitNumberTrap + '63', # cLApMaxClientLimitCause + '64', # cLApMaxClientLimitSet + '65', # cLApFloorLabel + '69', # cLAdjChannelRogueEnabled + '74', # cLApSysNetId + '76', # cLApAntennaBandMode + '80', # cLApModuleInserted + '81', # cLApEnableModule + '82', # cLApIsUniversal + '83', # cLApUniversalPrimeStatus + '84', # cLApIsMaster + '85', # cLApBleFWDownloadStatus + ] + ), + detect=contains('.1.3.6.1.2.1.1.1.0', 'Cisco Controller'), # sysDescr +) + +register.inventory_plugin( + name='inv_cisco_wlc_aps_lwap', + inventory_function=inventory_wlc_aps_lwap, + inventory_default_parameters={}, + inventory_ruleset_name='inv_cisco_wlc_ap_cdp_cache', +) + diff --git a/inv_cisco_wlc_aps_lwap.mkp b/inv_cisco_wlc_aps_lwap.mkp index c544e9ee70eca43847305a4e6fe0333ade3b9315..60fe55d3ee0184f91851bac43d5010ea6ef68849 100644 GIT binary patch literal 6395 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 W{ofz^KUU${bi?Sw8NwI>!v6#8$(We{ literal 6107 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 F{Xd7C+iw5> diff --git a/packages/inv_cisco_wlc_aps_lwap b/packages/inv_cisco_wlc_aps_lwap index ef6b7aa..0a56736 100644 --- a/packages/inv_cisco_wlc_aps_lwap +++ b/packages/inv_cisco_wlc_aps_lwap @@ -1,12 +1,18 @@ -{'author': u'Th.L. (thl-cmk[at]outlook[dot]com)', - 'description': u'SNMP inventory for Cisco WLC APs (CISCO-LWAPP-AP-MIB).\nVia WATO you can:\n - enable/disable this inventory\n - can add/remove some fields\n\n2020-03.15: added support for CMK1.6x\n', +{'author': 'Th.L. (thl-cmk[at]outlook[dot]com)', + 'description': 'SNMP inventory for Cisco WLC APs (CISCO-LWAPP-AP-MIB).\n' + 'Via WATO you can:\n' + ' - can add/remove some fields\n' + '\n' + '2020-03.15: added support for CMK1.6x\n' + '2021-07-11: rewritten for CMK 2.0\n', 'download_url': 'http://thl-cmk.hopto.org', - 'files': {'inventory': ['snmp_cisco_wlc_aps_lwap'], - 'web': ['plugins/views/inv_wlc_aps_lwap.py', - 'plugins/wato/inv_wlc_aps_lwap.py']}, + 'files': {'agent_based': ['inv_cisco_wlc_aps_lwap.py'], + 'web': ['plugins/views/inv_cisco_wlc_aps_lwap.py', + 'plugins/wato/inv_cisco_wlc_aps_lwap.py']}, 'name': 'inv_cisco_wlc_aps_lwap', 'num_files': 3, - 'title': u'inventory for CISCO-LWAPP-AP-MIB', - 'version': '20200513.v0.3c', - 'version.min_required': '1.2.8b8', - 'version.packaged': '1.6.0p8'} \ No newline at end of file + 'title': 'inventory for CISCO-LWAPP-AP-MIB', + 'version': '20210711.v0.4', + 'version.min_required': '2.0.0', + 'version.packaged': '2021.04.10', + 'version.usable_until': None} \ No newline at end of file diff --git a/web/plugins/views/inv_cisco_wlc_aps_lwap.py b/web/plugins/views/inv_cisco_wlc_aps_lwap.py new file mode 100644 index 0000000..0317984 --- /dev/null +++ b/web/plugins/views/inv_cisco_wlc_aps_lwap.py @@ -0,0 +1,72 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import cmk.gui.utils +from cmk.gui.plugins.views import ( + inventory_displayhints,) +from cmk.gui.i18n import _ + + +inventory_displayhints.update({ + '.networking.wlan.controller.accesspoints_lwap:': {'title' : _('Access Points LWAP info'), + 'keyorder': ['name', 'if_mac_address', ], + 'view' : 'invwlcapslwap_of_host', + }, + '.networking.wlan.controller.accesspoints_lwap:*.name' : {'title': _('Name')}, + '.networking.wlan.controller.accesspoints_lwap:*.if_mac_address' : {'title': _('MAC Address')}, + '.networking.wlan.controller.accesspoints_lwap:*.admin' : {'title': _('Admin state')}, + '.networking.wlan.controller.accesspoints_lwap:*.last_reboot_reason' : {'title': _('Last reboot reason')}, + '.networking.wlan.controller.accesspoints_lwap:*.power_status' : {'title': _('Power status')}, + '.networking.wlan.controller.accesspoints_lwap:*.telnet' : {'title': _('Telnet enabled'), 'short': _('Telnet')}, + '.networking.wlan.controller.accesspoints_lwap:*.ssh' : {'title': _('SSH enabled'), 'short': _('SSH')}, + '.networking.wlan.controller.accesspoints_lwap:*.encryption_supported' : {'title': _('Encryption supported')}, + '.networking.wlan.controller.accesspoints_lwap:*.encryption' : {'title': _('Encryption enabled')}, + '.networking.wlan.controller.accesspoints_lwap:*.data_encryption' : {'title': _('Data encryption')}, + '.networking.wlan.controller.accesspoints_lwap:*.rogue_detection' : {'title': _('Rogue detection enabled'), 'short': _('Rouge detection')}, + '.networking.wlan.controller.accesspoints_lwap:*.pwr_injector_state' : {'title': _('Pow. inj. state')}, + '.networking.wlan.controller.accesspoints_lwap:*.pwr_injector_selection' : {'title': _('Pow. inj. selection')}, + '.networking.wlan.controller.accesspoints_lwap:*.pwr_pre_std_state' : {'title': _('PoE pre standard')}, + '.networking.wlan.controller.accesspoints_lwap:*.pwr_injector_sw_mac_addr' : {'title': _('Pow. inj. MAC address')}, + '.networking.wlan.controller.accesspoints_lwap:*.wlc_primary_address' : {'title': _('primary WLC')}, + '.networking.wlan.controller.accesspoints_lwap:*.wlc_secondary_address' : {'title': _('secondary WLC')}, + '.networking.wlan.controller.accesspoints_lwap:*.wlc_tertiary_address' : {'title': _('tertiary WLC')}, + + '.networking.wlan.controller.accesspoints_lwap:*.max_#_of_dot11_slots' : {'title': _('max # of dot11 slots')}, + '.networking.wlan.controller.accesspoints_lwap:*.max_#_of_ethernet_slots' : {'title': _('max # of ethernet slots')}, + '.networking.wlan.controller.accesspoints_lwap:*.failover_priority' : {'title': _('failover priority')}, + '.networking.wlan.controller.accesspoints_lwap:*.wips' : {'title': _('wireless IPS,')}, + '.networking.wlan.controller.accesspoints_lwap:*.monitor_mode_optimization' : {'title': _('monitor mode optimization')}, + '.networking.wlan.controller.accesspoints_lwap:*.amsdu' : {'title': _('Aggregate MAC Service Data Unit'), 'short': _('AMSDU')}, + '.networking.wlan.controller.accesspoints_lwap:*.tcp_mss' : {'title': _('TCP MSS')}, + '.networking.wlan.controller.accesspoints_lwap:*.port_number' : {'title': _('Port number'), 'short': _('Port #')}, + '.networking.wlan.controller.accesspoints_lwap:*.venue_config_venue_group' : {'title': _('Venue group')}, + '.networking.wlan.controller.accesspoints_lwap:*.venue_config_venue_type' : {'title': _('Venue type')}, + '.networking.wlan.controller.accesspoints_lwap:*.venue_config_venue_name' : {'title': _('Venue name')}, + '.networking.wlan.controller.accesspoints_lwap:*.venue_config_language' : {'title': _('Venue language')}, + '.networking.wlan.controller.accesspoints_lwap:*.led_state' : {'title': _('LED state')}, + '.networking.wlan.controller.accesspoints_lwap:*.trunk_vlan' : {'title': _('Mgmt VLAN ID')}, + '.networking.wlan.controller.accesspoints_lwap:*.trunk_vlan_status' : {'title': _('Mgmt VLAN tagged state')}, + '.networking.wlan.controller.accesspoints_lwap:*.location' : {'title': _('Location')}, + '.networking.wlan.controller.accesspoints_lwap:*.submode' : {'title': _('AP submode')}, + '.networking.wlan.controller.accesspoints_lwap:*.real_time_stats_mode_enabled' : {'title': _('Real time stats')}, + '.networking.wlan.controller.accesspoints_lwap:*.upgrade_from_version' : {'title': _('Upgrade from version')}, + '.networking.wlan.controller.accesspoints_lwap:*.upgrade_to_version' : {'title': _('Upgrade to version')}, + '.networking.wlan.controller.accesspoints_lwap:*.upgrade_failure_cause' : {'title': _('Upgrade failure cause')}, + '.networking.wlan.controller.accesspoints_lwap:*.max_client_limit_number_trap' : {'title': _('Max client limit')}, + '.networking.wlan.controller.accesspoints_lwap:*.max_client_limit_cause' : {'title': _('Max client cause')}, + '.networking.wlan.controller.accesspoints_lwap:*.max_client_limit_set' : {'title': _('Max client set')}, + '.networking.wlan.controller.accesspoints_lwap:*.floor_label' : {'title': _('Floor label')}, + '.networking.wlan.controller.accesspoints_lwap:*.adj_channel_rogue_enabled' : {'title': _('Adj. channel rogue')}, + '.networking.wlan.controller.accesspoints_lwap:*.sys_net_id' : {'title': _('Sys net ID')}, + '.networking.wlan.controller.accesspoints_lwap:*.antenna_band_mode' : {'title': _('Antenna band mode')}, + '.networking.wlan.controller.accesspoints_lwap:*.module_inserted' : {'title': _('Module inserted')}, + '.networking.wlan.controller.accesspoints_lwap:*.enable_module' : {'title': _('Module enabled')}, + '.networking.wlan.controller.accesspoints_lwap:*.is_universal' : {'title': _('AP is universal')}, + '.networking.wlan.controller.accesspoints_lwap:*.universal_prime_status' : {'title': _('AP universal prime status')}, + '.networking.wlan.controller.accesspoints_lwap:*.is_master' : {'title': _('AP is master')}, + '.networking.wlan.controller.accesspoints_lwap:*.ble_fw_download_status' : {'title': _('Ble FW downaload status')}, +}) + +from cmk.gui.plugins.views.inventory import declare_invtable_view + +declare_invtable_view('invwlcapslwap', '.networking.wlan.controller.accesspoints_lwap:', _('Cisco WLC APs LWAP info'), _('Cisco WLC APs LWAP info)')) diff --git a/web/plugins/wato/inv_cisco_wlc_aps_lwap.py b/web/plugins/wato/inv_cisco_wlc_aps_lwap.py new file mode 100644 index 0000000..e2bb151 --- /dev/null +++ b/web/plugins/wato/inv_cisco_wlc_aps_lwap.py @@ -0,0 +1,104 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# +from cmk.gui.i18n import _ +from cmk.gui.plugins.wato import ( + HostRulespec, + rulespec_registry, +) +from cmk.gui.valuespec import ( + Dictionary, + ListChoice, +) + +from cmk.gui.plugins.wato.inventory import ( + RulespecGroupInventory, +) + +removecolumns = [ + ('adj_channel_rogue_enabled', 'Adj. channel rogue'), + ('admin', 'Admin state'), + ('amsdu', 'Aggregate MAC Service Data Unit'), + ('antenna_band_mode', 'Antenna band mode'), + ('is_master', 'AP is master'), + ('is_universal', 'AP is universal'), + ('submode', 'AP submode'), + ('universal_prime_status', 'AP universal prime status'), + ('ble_fw_download_status', 'Ble FW downaload status'), + ('data_encryption', 'Data encryption'), + ('encryption', 'Encryption enabled'), + ('encryption_supported', 'Encryption supported'), + ('failover_priority', 'failover priority'), + ('floor_label', 'Floor label'), + ('last_reboot_reason', 'Last reboot reason'), + ('led_state', 'LED state'), + ('location', 'Location'), + ('max_#_of_dot11_slots', 'max # of dot11 slots'), + ('max_#_of_ethernet_slots', 'max # of ethernet slots'), + ('max_client_limit_cause', 'Max client cause'), + ('max_client_limit_number_trap', 'Max client limit'), + ('max_client_limit_set', 'Max client set'), + ('trunk_vlan', 'Mgmt VLAN ID'), + ('trunk_vlan_status', 'Mgmt VLAN tagged state'), + ('enable_module', 'Module enabled'), + ('module_inserted', 'Module inserted'), + ('monitor_mode_optimization', 'monitor mode optimization'), + ('port_number', 'Port number'), + ('power_status', 'Power status'), + ('pwr_injector_selection', 'Pow. inj. selection'), + ('pwr_injector_state', 'Pow. inj. state'), + ('pwr_injector_sw_mac_addr', 'Pow. inj. MAC address'), + ('pwr_pre_std_state', 'PoE pre standard'), + ('real_time_stats_mode_enabled', 'Real time stats'), + ('rogue_detection', 'Rogue detection enabled'), + ('ssh', 'SSH enabled'), + ('sys_net_id', 'Sys net ID'), + ('tcp_mss', 'TCP MSS'), + ('telnet', 'Telnet enabled'), + ('upgrade_failure_cause', 'Upgrade failure cause'), + ('upgrade_from_version', 'Upgrade from version'), + ('upgrade_to_version', 'Upgrade to version'), + ('venue_config_language', 'Venue language'), + ('venue_config_venue_group', 'Venue group'), + ('venue_config_venue_name', 'Venue name'), + ('venue_config_venue_type', 'Venue type'), + ('wips', 'wireless IPS,'), + ('wlc_primary_address', 'primary WLC'), + ('wlc_secondary_address', 'secondary WLC'), + ('wlc_tertiary_address', 'tertiary WLC'), +] + + +def _valuespec_inv_cisco_wlc_aps_lwap(): + return Dictionary( + title=_('Cisco WLC AP LWAP info'), + elements=[ + ('removecolumns', + ListChoice( + title=_('list of columns to remove'), + help=_('information to remove from inventory'), + choices=removecolumns, + default_value=[ + 'adj_channel_rogue_enabled', 'amsdu', 'is_master', 'is_universal', 'submode', + 'universal_prime_status', 'max_client_limit_cause', 'ble_fw_download_status', 'antenna_band_mode', + 'module_inserted', 'floor_label', 'max_client_limit_set', 'enable_module', + 'pwr_injector_sw_mac_addr', 'pwr_injector_selection', 'pwr_injector_state', 'pwr_pre_std_state', + 'trunk_vlan', 'trunk_vlan_status', 'tcp_mss', 'monitor_mode_optimization', 'sys_net_id', + 'upgrade_failure_cause', 'upgrade_from_version', 'upgrade_to_version', 'venue_config_language', + 'venue_config_venue_group', 'venue_config_venue_name', 'port_number', 'venue_config_venue_type', + 'max_#_of_dot11_slots', 'max_#_of_ethernet_slots', 'failover_priority', 'wlc_primary_address', + 'wlc_secondary_address', 'wlc_tertiary_address' + ], + )), + ], + ) + + +rulespec_registry.register( + HostRulespec( + group=RulespecGroupInventory, + match_type='dict', + name='inv_parameters:inv_cisco_wlc_aps_lwap', + valuespec=_valuespec_inv_cisco_wlc_aps_lwap, + )) -- GitLab