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
zcmai#RX8LJz;JaBUNP+IZidypaz}SJtGnB3tDBXpjac0stGk=gRu79+^Z(ED-GATB
zxjA>|=1|39V6^g|n<2sNoV`sg?K~`9Onn?JP0d|BOdWm9T{(C_Jlr4wZf;I*5GOCE
zlY=Y5rSYZ9rr^T$$t!W70l6a;`D){9D#{q*dh_<B@dBE1*V`O6ifpkHUt{T_qQ-SG
z{N<B$EP<?gtH8`dN0+?j#RxEDh$i~bHLBE>D?57j-RdKf@~Gtl$(J{W`04demZEtH
z<>f*-Dun=mFMpt1)NC-qSFru4T6#rgsZj?U|GCG~=8Pv^gsJq-O{kqT*}3x`FMoNP
zM5G6^X$fzri_1BCM-W=IdPbF;s7T24P`reVeApT6<0sp_SAb?mS~o5lKi-igNb@hy
zO=ad6!Gc&wK+ya9&Hml`@-lRN8G5u?=pP<}mXBPlcA`7WSU4-*%XAK+OQguNRX@aE
zjJfROvh2jVW&sZpGk7FDI~O0#iIW55hlYxTK#WY;BwpZDS#{EiZmcXg2yM|tId25&
z>TOHPL|=~AkX6o$Z)C+wibSHR^@RUabZMY}QBt01_c6aa@W;7NJx&QPdBkm4=t+Sp
zq2%XqcFByD+I%&V-jK6z&K&4`_F_+oU**3aNvzFN8~8XsyF-QX?lZY%f?IFG4v%`|
zsZz71FWwB6K_mljW))Dh<J@b#Km8`^H93@{tUxO^MXi}(bV$~782E~}#bj{p+Ai-<
z4DeSx@59JmupsH=_wWo7J?=N%<KId)6t>|5^<goNC%8oCv4LnqxBZn;jl;cvAsMKU
z=;^<lIH!*`@XN!{H>yD8!9Dogd(u>q1-$5oP3;?;<^e9$2A@?OySsdV`xT02O-b;G
zt-Lxoz5$2cXU*i(dcuROiBqONt(1<7(q(=CA%u1+oa5~FiMli=&$@iWQ{s`nv`tlC
za(;LeS~G=_Pjdl{@rJgt8>VT<5;(#<6k~2;Ycm#D%QF$@mnIO*?PNK(7A7#(=a5*(
z0;$evk1>6%-XF<!LI_hk?+^gcq&7I=Lx(+Fp3ZV>15Wh`E<l=H;S6WdOyDM)ecBzT
z*Ui9$$3D%HPVaSabB~lzt-nWzc1?@!Zhza%e5X?28iRLFr9K_il6032h<#t#1E3ra
zV7ou*W+zIoVgs4z6;Gn&pAPp>OO1SS0R;Y1!NHH;UzLzQZi;tII0w!CXLlGp{L^Nt
zLy%@#9QB)cQ2V$3gNQwpyi;ql{_aN2*zEbaY)ahG=pnky5TWWwkHKf|&|syXR83Zi
z;=<$!7@bI`n(h4u3odGW5{9Vc9ue74Qqar-F7Q<MCmqi$68d(Y_@7XM(F*TmS=7mf
zsZ^r(NbYQ$-V{#U8s74Ba?1CF7_Q7~2D_vqY9peBy%KVAU$*0oVXZ)g9_`x?8<Q&J
zvm)7}(Ad&*jE(Pyb|loLsym@Bd%;t*g_N%NRYZU{>PHY-<7Jk3IPneIW7JsfWbyE$
zi)jz;R`1j6qHq}){__z<Xw(z&sEm7-Y<oQEC(HXKoiG;FAo}|>X82On1r?hQf_-tO
z;t99~Wz`O6!?LmcXIrsu&`<Dj1@m=3?2;aJ_JkkjHVHsOD8$hB=@mb00%7pCXfawF
zp#^*i1k9RqnbC)jrOA;#$l3fNTcqzOw|ieprwX5=HOIj;Iwq^U5n`ss4JsV*gP|~R
z<ew&7zO?Q6^fb_T9)UHL1`!cWRt@~cEx*16oT5@QVVTz)W6F<7hVwBVB_)0Umd^A<
zhVj?W;3`5gu->i`+rrSEh&U`Z%T|9JNdA_AeWCA5ay1KWb=viitzyxb&06Z{n$b~s
z)+-GM*Gmj0BZSi~Fv=F~d}D%uRIo?3ZbK+W&DD>8RGrb^$4wMFTZs7Mb&B3$0ku?#
z#OI!91Mx2>mk2h;HAF!urz9@wqU0HQkp^<*zIvD3mO4zQb%^(1$1!%!h5BB6CP77k
zVeQiEIc2;4JO^9<SHrX7Ym)-7SUR#X#PV3wxnPmp%KW;47VrMB>>TjpUm4mS87U=~
zAvh>Ne<fcV-TjVya~8Eh!4QO3q2JhqW647rk|{&FI52Mm9w9HrvP++HF|$B2q@-ZG
zCiBvrLzLyFw3x*1)j*f)%}^`kIp`~r)ORJ3)J=`{MrgTFthE?Wi)_&Sq8}L=jigqO
zN|@IM3vOz|XpF1+namrNf{Uh@db=n4UF&fRczd-s>;SAW^sB*XGHfd4Q>F)h&OX^k
z<!y0vE?{piCTqMYesTM~v8~Fca~1rWtEHv%u1s0voO~#CiBLY=k48w@u4GIWfo6`C
z7K}oP@n8lHM2cmlG(+5~IrT9+{4_C*`qCaV#J;h%1D2t1xzd(P$fx)8I<I5+(DosQ
z13<Zw*7;*7XFW6EXv;hM4v9~u4JB}Xt@>X5Ld_&co7BcJ;`d&W<SV<Oi!H^e%}w*S
z;z$L_u%5~_r?J`5+jt9Iko=hUO97`C)7_<B>x!AhcJjJH{!XhWM$blRg-nT*2-*w%
z8Qw^Sm8P1{f9|3A@tE-!8M+jk53C0MXQ^SUq>A=Ux*xtE5vPnLUehnj_Fk&p(@+fx
z>iegZN>noYBMV9mv~b*6=G^yet|hKEBB{%$tCfq{W-ZNF*mC(LR%a$EJG7Op{8QpD
z3`hR)jfy=fd3P}RTcItSt?596!4WCE^Y`9^pu<hZAZehFq2?8x?2CfS*Toz%i%}Ww
z8fgZWQ)}E`J)+YC?cHfM9UY^r6AzKBcjWO3e4(>mb9`(a#kj?SdD7;3(Yg^T?VJz_
z5ycfBV}I2*kOcrs`n#7sqIC~-qyma(?cpa)A~mX9x+V2}_Mtf@bsQDx`QefS9)^L>
zdzp5OWQL)mD;;LOp%3Kuaj^q7tV5xW<nZIlX8ipWh}F*~JjN=w4~!{UnX`<JNC2Rq
zP7HF1;(XTl{gDWifOW)^%m({rI_rUBkoRp&hR;2%14mbuc-=Nu%rmLz-BfXOQB-Hb
zq{;k%#=-37_H&!s`F_U$gV5eMfo)vZf|xa$AhxdgAE-Nb!gWzTxTPsU-A*uuT8=hO
zTj)okx;nOq`YmDEPp>ZF0+_+hCQFf@`+VQXr*e4ub7d%TFh0xFDDHp(*hyHfXDf;y
zcNMjghb{18T#e<+a=Pl$PI|6aN{xa3a-(W?{<Ov%Wi$8h!E(3b7;dr8mun_C<qa{8
zjD+G{-|H%)gxUonr#@)5keFMmG0m%_(OtC>rTj)=15{xi7+$L!iff-6s)(@vFkI~q
zFGyp@Y^OJ?k+rMPGeo!N`tSf@iRT)2*k8}iLIEIQGt;>L2lhLXoE+RyX$bQ%$=<>&
zq*rL%tnK|m9YCGxGEze+Xs(sBw)RMlOn^%*%7AZ*#@Rm1w)vll?jw-S8CdzC0&5qV
z-v8#QA{<_a-{{rn`OZVmKmj9ZEZyxid+Vw;xt=^djH+d=>DNl;Ny^=!E_Ylw_x@6$
zDm<j(g78k0&?Q!eZ_?a@6W)kZgJRTa;#wfqtSQCu2D8kvtR>3tAQTdxJwn3&xHmbC
z_!4DtfpMhu6ua#-CM>Y;C;M$Ru~*3%D*}DF_FsEAs&bb}vNxhg@7dq6GrOzp0xkX-
zuXTrX-SEG-hXlYha9Mnlgxbj2F^@gUsUifa`X~Yu0jEe~>Oewms$}|i%}E_sSy&nt
zX1*mt0|Lk^r0#I%_86A@C(joBBaxf$Vs$~nY0ZVp3N~Awp`-Dr!YfENxc{R77Ow;W
zBDf^C+=y8)gqsySF{U-&IR}`m3E*V&wF-;M=+<Cr)B$ta@v6&qc-t%fb7z4GOEJLh
z#6s93iLI&)Kc4U;YJFhWs`p*%m&S<m!(&z=`>t(8x%$<fXSla~QuQ+Y*tOzfqMSD&
zVL6n=Jq0>7HP8|j?Z?;NbcL8nH^MrI*MXf=p}KtEfk#L))=?%N9q*8Uv8Zue0!9^x
z@ga_&s0Q`USls?~@!qct9)tk>OEett*wA2=<?3aGE>~JnMJHS&MHWdMQs(?E84v{(
zx*!!8E1@-QNZn1Yf3WL;*|0O@x87_n{Uk?xT9lN8*)$8$;#b)+!^R){HkzDHm&vn^
zS%Jd@9~R5`%TiC~IsL?mTHDt}$wmb_<Fg4{*4+VrWo?bphAuu5`atq}6t)}{i#|SA
zU;gTL%4{$CvG1A!m6JDUosClZ_*|pv^T*wK(UnE1fcKc+Y7vCs?vuMt1r5-B%F&W^
z+8qRZVibecGG%rPWR(`NeCo|Iht8yF7bwW!E|2Kk*y+h8Md!|W^!B?5@sEV&4YbdD
zC)EL+#n6`8d;_vtq{|_REc#5qPKpA_Y3FAC+_R`zrrZoZJ5qHMiz95B);@-4v?0^_
zlB3yN?n#R5@l!c2kFN(R`@m2D1rU0NUM)!6s#urL8&BbRPrf?@_(F9N>6*ZfAzET|
zx52vfbm(k$HJsv@TQUOpI)cECr$&$00c_!Q1%8&!&`n_Y*dF=G^sA0hV17c?<+#Q6
zxhh+E=g!wYlHJ}DHyO&ceIX>uUqEy~RVb@WgW3K|J5fw#t2{2e{E9N}%LhEFLzOI|
zE`N4{DA5VYFOe`$ok$f1!2ZL;WA{Z$KBu}AlPQh4p=_nijrfbBSl8Mw)K7!n)^r#<
zi?37OVwJ~UY}mf?t2+AKyXWS_w)#Q7cRe_BAcryJyUfOq{U@cH)o2mEL@e>0$xGF+
z@F>enX<1}#YstK&XQcwVgKKS#Gl6J1mVfBRO$kt8wkyH(vdZUqcHCp9Qo*$#@6_%`
z-m<#mHyJ(%c*3i6rIe^qU6SvPuV9A**WHuYs#EkgTsyjCiAAMsR$EPo8g(hLD#rdy
zwc1pX*^}K3<!drZ_1MIV2p4PAw+b>77qgcB40boYQ_sagpiTDTl74|sVpqEV05V%e
zekeBxUGoV}`YsX`LO2wmdO>y143qK*dpsQO5R5ai^kH_#784M9(*PjIiz1`+<(qD(
z1YbmW$}gKNaVzeXy<Jk|4(`mFLb1m9ei<hJg19Ov;ED#zbP}Sv)=a~^ddX8y{A)na
zfRAD4v8r-MKhnDIsod}y9dNXDEJfJrKd|POmN;-n@{MaPTW5EHkV~q>ERA@Ar%rkq
zi!3vI8j-nfAOH&`#a`@e0f~CMJ7kI7CBAaj*UE@KPN|pGsda>>6s)X`7iG$3)1y$)
z{^cmjaX<p}AD;x_0tMt!nCI}1g&F4rNMqBTzU^xxyQ_Uuf>KBI-1(C1S^9yonOd#`
zJ>TlG^ecaoIWcETksP6zuG>zjh{mQZ?{bsqVK|B2lK01Hh0Ixe5|Wkzh$Q4QmtSdI
z^vcd8x@IR`i?K4e!X|6APW=1pbPj;qi{iLbFm{1YyCo;pK*G%IPGPtqQbSoAQoi+)
ze@f8R38|V-Uy89AE!{udp3+*jRoD<3^6i#f;dN*C*%mx12Yee%Js3>31pD;u)6z<q
zj*7p>pBG?lIYyOmsLdT%^BP#8ip>{u!IqU!*$rb?>+}S4@ii)5VxaK4J$Ke*IzR-Q
zHlo6F_t>gjMu!{^aCM#I!2p%o4i_gU$p%$jD{QWti-kOO?)8+G674l3`da(KQ*S63
z=kJ%20=6XBEO)17f5`-n-;7ijcKn5J(lf??rGw`DZl{e@0-<$wRgz^hw`jVBT&}nJ
z1L;^EeFb;R82r{PfAYbDb*tkdIlbEdX;6tAOioLzhZ?$UmJ~U*y5{dY^<LEO;jF)!
z{SY+xJkF^O1J{T$Q-fzwQG&3l&imvog(ekSIg6<2-`)=w1qy#RXfcTNwq(lJ1S(%^
z<waa&Chjx);Hh&{yrUI(g4#x97|sugdwYDSU%Jcard8FiFCH`FBd@EIQndw#7x_^}
zfY^>jQf}_gFFwRX(rgU8E%&Gm<RtG+`3%lw(oP#B9R~K0vdsS#@W*>e7kG0373$mV
z3sp3s$HET$iOzO3&hF6#KJr49Fm5Hxc@>fuFE{tzw7%qc9rF6${eF@$ocR~kaPA}U
zhd@6YQ!0!{Jdpls-%_l~f4;yIWmu7R*M#e~B|Nw;C)9=<HEdQGA;sX=XJCi7!kuon
zNI2|kG-B@=h}qPGbZN&;(ERb@F5q;1I!&j|V?^>Wwg{u3n$cIlzoMdtA%x`5*1Q*K
z*F{h%*K5m7@Fm5)c!ysz!op_?O8`cnG8Gy}ynYQ$uT?KjTJzo5)ZKw#h+1t3MZE$4
zv4MR)gdC6F+dql8jM=@Za<a)Il`1T_TjpKvI5ER=R2DNN6gE%5cP+rDIDD`f5e~);
zZr+=iT-dCdNVGqxGZZzkdJq2Vym4gH``!1bVbw<9br_QO{8YSmzG1a$5*YNRs3}B!
zb{jco0-w{0fw6yL8BnF}Z0dPWJ(U6^5!dWUH>iUOpo|1h^BT*mWdaIcM-9P<&i2oE
z=B>$Q0rA7n)h}f7`v~Q=b>Tq()uFg|!!qDl552C7=$fsc2_b@|(=7+tBZQTGTdKZe
zP_S<8WrnR&z=f<j5Bc_l?;%Yu#Io(P1>%;e^`+QuxdE0L4a|+FW%Yq~90lYT>LbYm
zg6_%dww?VdoGwQ7H9h<5pvfOki^z!jbej<G<9Z?NA@0k)hV9z9YhwKPIOlnANg=H4
z0W$Y#*X~d9!Ct4J>gtS)lT{+|{UMf<c>X#l#h(!rmI_(K2<WiKD`f3^uoEc!^BQYp
zVtReRo0%n<a;ZWW;UlC6;Z^j%eRAjB;VolB54iq*b6=4@_N$n7nn3?q6DwVctG3^)
z&Q>vGTU&b5JrwoNEfjD0AA&M;_FVVHUu=QTc=O1ZQ-|f>-~9^;zn4EOGJlF|<x(I$
zW)hkWHoh#J6q~<AW7=*WFsfl)f!?3eb!GObuGd^TQ7Vtukh9;0(H8$udel7>|17sZ
z=0YK8MPlp^h|9bpw_mBp&yP}NYWEMCZx#0V|9N^uYey!%?WHk9IdB<qUL!2nyqtkA
zOD)QWvT4>0<Koz~u*+~mdCma+bk`e72PfrKL%Y=tYNE;ch@wZ3#u2f;NX=UfVRy7|
z-G`sStNV=AV*`ho#@l^aZd!G5TcYdSAeR0Bc8+nMIHz2Tj-{Tg4A!=kOVF(^Cd+M7
z+xKU(sgGqqU+*K)?SRiM-FQxIXF&V>11gS2C@x>mSm95*-9Sc+*8ezkNw1;yJKC(f
z`oI?%POm@_>(#6J$wH1{=(KUp==L8SOy`N$f$b7;VBa%a1uSYlYRRNxRpiNM3%>p8
zP%`^I^|lKg1Hs-*Ev;#BH7X9g;g7qn@JH0w&3gT6ipI5;s+a!02=FuF?sZb-5QlPJ
zNYhgb%55i%%q4rX=h6m8WBO0V=t{2BVgL2hrq9XboCk9k$<GE!FT%k)!rvAG4MYO}
z{{BnAoFER4FY1Cas?@U!ua=sE_Je7W!2yx7tcE&+OSOt}VI{|4YM*UO{3rJ?Nu#ew
z$<#+mdOu6Y)e&TCM!01U8B@uQr4pTUo=`l7YLKQ9G-J%P1=7D&v^vq(YiBzfRwt&n
z9#@GjaOUk*)r~)VcfM@tS5y(8W^-=ox8;vPtlGrn6pZB~M#*$wl<ma0<L<!tCtKzH
zxkvTm%8Y~2ghBgM<*&fW?i>)d-Z{56T@v|!Izo5U^(kp@M05~T4J58wQktqpdacnf
zVr_OT6&Dtbh4DDCTt?}7ZU>6CXEj-C<ry&X^=2N<rz2F8y-H3fko4>j0eL(c87n<F
zB<0{d_q#v;e4Im9fq#25MAy9P0y<u^?DS=%#909AX(WSjuZDw@IDTU1lLeVic4X~u
z(=7Ul0pt{&s5*?4{l#LD;{c>&qnalYyVpGwMhH541kEbvJ%aR5u}Xrf2~pZQ>$xdw
zR&xQv?HIOhm~@{CK<Q6TbLQtAc4l8#PbdIq-!ZFut`~78^Br4o7X#n*T~ShIn~W`$
z&+vDU#x_xA!(U~SEqjRb>BQ3pno}WjK*L)&*)8(tNX3==PvXm_n5@PvuvSeVZUO6U
z>ia!KC348Aa?eb&H<SC{e#0|7?{g+7)|ogwQiL{7<Wyf&_wu%n;V<3cAi)S*u)M{<
zK!7{c*#48NUTEr~!Z@Fxn>tXlS>xK+IqW)ZA+AO+pvq9!*9AbEv)y)l*0Jue_yhsC
z^QGnP6Z0vrO}wrr!^<&?{bCnprE)%$e70Y<o9jeRP1zB&n>_A?T;{NQr-4_<w$X+*
zs6ErPx6LGp(M#sN`Mt8Nubao=OTtG6Y@5_g^Aq;dc4CBopXveyf(oJ}e&}E)qwgd2
z`F}As5H7!4EYH^Ysq=)rpwv`BK@#7rwF-Oafi?D~CA1;Y5)%%ctq9T9nb-9U)cqe9
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