diff --git a/README.md b/README.md index 38083b336cdc0ca8733d56b2be5cf4db30242816..32aef5745623b6bfa4567f2b791bd6141306b004 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -[PACKAGE]: ../../raw/master/mkp/cisco_meraki-1.4.2-20250104.mkp "cisco_meraki-1.4.2-20250104.mkp" +[PACKAGE]: ../../raw/master/mkp/cisco_meraki-1.4.4-20250303.mkp "cisco_meraki-1.4.4-20250303.mkp" [SDK]: ../../raw/master/mkp/MerakiSDK-1.52.0-20241116.mkp "MerakiSDK-1.52.0-20241116.mkp" # Cisco Meraki special agent diff --git a/mkp/cisco_meraki-1.4.4-20250303.mkp b/mkp/cisco_meraki-1.4.4-20250303.mkp new file mode 100644 index 0000000000000000000000000000000000000000..312ba9020b6e7c5d567f98c312ee95241074ab80 Binary files /dev/null and b/mkp/cisco_meraki-1.4.4-20250303.mkp differ diff --git a/source/cmk_addons_plugins/meraki/agent_based/switch_ports_statuses.py b/source/cmk_addons_plugins/meraki/agent_based/switch_ports_statuses.py index f210421271e57701d52f4976a163ca19ee1a394b..b7e3032d38ed59b1d02a0eab3cc26f5d67496d4d 100644 --- a/source/cmk_addons_plugins/meraki/agent_based/switch_ports_statuses.py +++ b/source/cmk_addons_plugins/meraki/agent_based/switch_ports_statuses.py @@ -7,7 +7,6 @@ # URL : https://thl-cmk.hopto.org # Date : 2023-11-11 # File : switch_ports_statuses.py (check plugin) -from Cython.Shadow import returns # 2024-04-08: moved neighbour_name and neighbour_port to key columns # 2024-04-27: made data parsing more robust # 2024-05-12: added support for MerakiGetOrganizationSwitchPortsStatusesBySwitch (Early Access) @@ -27,6 +26,8 @@ from Cython.Shadow import returns # 2024-11-23 fixed crash on missing traffic data # incompatible removed "Port" from item -> use only interface index # 2024-12-14: reworked output of port status +# changed if_port_type to port_type and from str to int to match Checkmks interface inventory + # ToDo: create service label cmk/meraki/uplink:yes/no @@ -255,9 +256,9 @@ class SwitchPort: usage: SwitchPortUsage | None warnings: Sequence[str] # syntetic settings - alias: str | None - description: str | None - if_port_type: str | None + # alias: str | None + # description: str | None + port_type: int | None name: str | None @classmethod @@ -280,9 +281,9 @@ class SwitchPort: usage=SwitchPortUsage.parse(port.get('usageInKb')), warnings=port['warnings'] if port.get('warnings') is not None else None, # synthetic settings - alias=f'Port {port["portId"]}' if port.get('portId') is not None else None, - description=f'Port {port["portId"]}' if port.get('portId') is not None else None, - if_port_type='6 - ethernetCsmacd', + # alias=f'Port {port["portId"]}' if port.get('portId') is not None else None, + # description=f'Port {port["portId"]}' if port.get('portId') is not None else None, + port_type=6, name=f'Port {port["portId"]}' if port.get('portId') is not None else None, ) @@ -297,7 +298,7 @@ def host_label_meraki_switch_ports_statuses(section: Mapping[str, SwitchPort]) - if port.lldp: yield HostLabel(name="nvdct/has_lldp_neighbours", value="yes") break - # only set LLDP label, Merkai CDP data are not usefully for NVDCT + # only set LLDP label, Meraki CDP data are not usefully for NVDCT def parse_switch_ports_statuses(string_table: StringTable) -> Mapping[str, SwitchPort] | None: @@ -338,7 +339,7 @@ def discover_switch_ports_statuses(params: Mapping[str, object], section: Mappin ) -def render_network_bandwidth_bits(value: int) -> str: +def render_network_bandwidth_bits(value: float) -> str: return render.networkbandwidth(value/8) @@ -432,7 +433,7 @@ def check_switch_ports_statuses(item: str, params: Mapping[str, any], section: M yield Result(state=State.OK, notice=f'Clients: {port.client_count}') if port.is_up_link: - yield Result(state=State.OK, summary='UP-Link', details=f'UP-Link: {is_up_link[port.is_up_link]}') + yield Result(state=State.OK, summary='UP-Link', details=f'UP-Link: {is_up_link[bool(port.is_up_link)]}') else: yield Result(state=State.OK, notice=f'UP-Link: {is_up_link[port.is_up_link]}') @@ -483,13 +484,13 @@ def inventory_meraki_interfaces(section: Mapping[str, SwitchPort]) -> InventoryR "index": port.port_id, }, inventory_columns={ - **({'alias': port.alias} if port.alias else {}), - **({'description': port.description} if port.description else {}), + # **({'alias': port.alias} if port.alias else {}), + # **({'description': port.description} if port.description else {}), **({'name': port.name} if port.name else {}), **({'admin_status': port.admin_state} if port.admin_state else {}), **({'oper_status': port.operational_state} if port.operational_state else {}), **({'speed': port.speed} if port.speed else {}), - **({'if_port_type': port.if_port_type} if port.if_port_type else {}), + **({'port_type': port.port_type} if port.port_type else {}), }, ) @@ -539,7 +540,7 @@ def inventory_meraki_lldp_cache(section: Mapping[str, SwitchPort]) -> InventoryR for port in section.values(): if lldp := port.lldp: key_columns = { - 'local_port': port.port_id, + 'local_port': str(port.port_id), 'neighbour_name': lldp.system_name, 'neighbour_port': lldp.port_id, } diff --git a/source/cmk_addons_plugins/meraki/agent_based/wireless_device_ssid_status.py b/source/cmk_addons_plugins/meraki/agent_based/wireless_device_ssid_status.py index 2710ccccbd6bd41ff8bf172d9760b166270fb76f..a157ff4e691054ef07842fca1ec0b43dd7d8d159 100644 --- a/source/cmk_addons_plugins/meraki/agent_based/wireless_device_ssid_status.py +++ b/source/cmk_addons_plugins/meraki/agent_based/wireless_device_ssid_status.py @@ -66,7 +66,7 @@ class SSID: def parse_wireless_device_status(string_table: StringTable) -> Mapping[str, SSID] | None: json_data = load_json(string_table) if not (json_data := json_data[0]): - return + return None ssids = {} for row in json_data.get('basicServiceSets', []): diff --git a/source/cmk_addons_plugins/meraki/agent_based/wireless_ethernet_statuses.py b/source/cmk_addons_plugins/meraki/agent_based/wireless_ethernet_statuses.py index 88cc8fefc76a256d2a5cf293aa6d37e8288056aa..5b3abbf158d3c3c6dea6cad326b1746972d9c505 100644 --- a/source/cmk_addons_plugins/meraki/agent_based/wireless_ethernet_statuses.py +++ b/source/cmk_addons_plugins/meraki/agent_based/wireless_ethernet_statuses.py @@ -15,6 +15,7 @@ # 2024-11-17: incompatible change item from "Port %s" to "Interface %s" -> rediscover your devices # added interface inventory # 2024-12-12: fixed crash if speed is None +# changed if_port_type to port_type and from str to int to match Checkmks interface inventory # ToDo: create ruleset cisco_meraki_wireless_ethernet_statuses @@ -108,10 +109,10 @@ class WirelessEthernetPort: ) -_is_connected = { - True: 'Yes', - False: 'No', -} +# _is_connected = { +# True: 'Yes', +# False: 'No', +# } def parse_wireless_ethernet_statuses(string_table: StringTable) -> Mapping[str, WirelessEthernetPort] | None: @@ -203,13 +204,13 @@ def inventory_meraki_wireless_ethernet(section: Mapping[str, WirelessEthernetPor "index": port.name.split(' ')[-1], }, inventory_columns={ - 'alias': port.name, - 'description': port.name, + # 'alias': port.name, + # 'description': port.name, 'name': port.name, 'admin_status': 1, 'oper_status': 1, **({'speed': render.nicspeed(port.speed)} if port.speed is not None else {}), - 'if_port_type': '6 - ethernetCsmacd', + 'port_type': 6, }, ) diff --git a/source/cmk_addons_plugins/meraki/lib/agent.py b/source/cmk_addons_plugins/meraki/lib/agent.py index b13c979ce67ab1ac6f89740892657ea41cfae7fb..66600db174be2770e0c2e831780344a47c22fe7f 100644 --- a/source/cmk_addons_plugins/meraki/lib/agent.py +++ b/source/cmk_addons_plugins/meraki/lib/agent.py @@ -43,6 +43,8 @@ # 2024-11-23: added appliance port api call -> not yet active # 2024-12-13: fixed crash in SwitchPortStatus if response has no data (>Response [503}>) # 2025-01-04: added "use network as prefix" option +# 2025-03-03: completely removed APPLIANCE_PORT section -> fixed per section cache +# removed lldp_cdp section # Deprecation information # https://developer.cisco.com/meraki/api-v1/deprecated-operations/#deprecated-operations @@ -97,7 +99,6 @@ from cmk_addons.plugins.meraki.lib.utils import ( # parameter names SEC_NAME_APPLIANCE_UPLINKS, - SEC_NAME_APPLIANCE_PORTS, SEC_NAME_APPLIANCE_UPLINKS_USAGE, SEC_NAME_APPLIANCE_VPNS, SEC_NAME_APPLIANCE_PERFORMANCE, @@ -113,6 +114,7 @@ from cmk_addons.plugins.meraki.lib.utils import ( SEC_NAME_SWITCH_PORTS_STATUSES, SEC_NAME_WIRELESS_DEVICE_STATUS, SEC_NAME_WIRELESS_ETHERNET_STATUSES, + # SEC_NAME_DEVICE_LLDP_CDP, # Early Access SEC_NAME_ORG_SWITCH_PORTS_STATUSES, @@ -134,7 +136,6 @@ from cmk_addons.plugins.meraki.lib.utils import ( SEC_CACHE_SWITCH_PORTS_STATUSES, SEC_CACHE_WIRELESS_DEVICE_STATUS, SEC_CACHE_WIRELESS_ETHERNET_STATUSES, - SEC_CACHE_APPLIANCE_PORTS, ) MERAKI_SDK_MIN_VERSION: Final = '1.46.0' @@ -160,7 +161,6 @@ API_NAME_ORGANISATION_NAME: Final = 'name' SECTION_NAME_MAP = { SEC_NAME_APPLIANCE_UPLINKS: 'appliance_uplinks', SEC_NAME_APPLIANCE_UPLINKS_USAGE: 'appliance_uplinks_usage', - SEC_NAME_APPLIANCE_PORTS: 'appliance_ports', SEC_NAME_APPLIANCE_VPNS: 'appliance_vpns', SEC_NAME_APPLIANCE_PERFORMANCE: 'appliance_performance', SEC_NAME_CELLULAR_UPLINKS: 'cellular_uplinks', @@ -175,6 +175,7 @@ SECTION_NAME_MAP = { SEC_NAME_SWITCH_PORTS_STATUSES: 'switch_ports_statuses', SEC_NAME_WIRELESS_DEVICE_STATUS: 'wireless_device_status', SEC_NAME_WIRELESS_ETHERNET_STATUSES: 'wireless_ethernet_statuses', + # SEC_NAME_DEVICE_LLDP_CDP: 'device_lldp_cdp', # Early Access SEC_NAME_ORG_SWITCH_PORTS_STATUSES: 'org_switch_ports_statuses', } @@ -279,34 +280,35 @@ class _Organisation(TypedDict): # +--\ MerakiSectionOrg # | | - adds org_id parameter # | | -# | |--> MerakiGetOrganization -> default 86400 -# | |--> MerakiGetOrganizationApiRequestsOverviewResponseCodesByInterval -> Off, allways live data -# | |--> MerakiGetOrganizationLicensesOverview -> default 86400 -# | |--> MerakiGetOrganizationDevices -> default 86400 -# | |--> MerakiGetOrganizationNetworks -> default 86400 -# | |--> MerakiGetOrganizationDevicesStatuses -> ex. 60+ -# | |--> MerakiGetOrganizationDevicesUplinksAddressesByDevice -> ex. 60+ -# | |--> MerakiGetOrganizationApplianceUplinkStatuses -> ex. 60+ -# | |--> MerakiGetOrganizationApplianceUplinksUsageByNetwork -> no cache -# | |--> MerakiGetOrganizationApplianceVpnStatuses -> ex. 60+ -# | |--> MerakiGetOrganizationSensorReadingsLatest -> ex. 60+ -# | |--> MerakiGetOrganizationWirelessDevicesEthernetStatuses -> ex. 60+ -# | |--> MerakiGetOrganizationCellularGatewayUplinkStatuses -> ex. 60. -# | |--> MerakiGetOrganizationSwitchPortsStatusesBySwitch -> ex. 60+ +# | +--> MerakiGetOrganization -> default 86400 +# | +--> MerakiGetOrganizationApiRequestsOverviewResponseCodesByInterval -> Off, allways live data +# | +--> MerakiGetOrganizationLicensesOverview -> default 86400 +# | +--> MerakiGetOrganizationDevices -> default 86400 +# | +--> MerakiGetOrganizationNetworks -> default 86400 +# | +--> MerakiGetOrganizationDevicesStatuses -> ex. 60+ +# | +--> MerakiGetOrganizationDevicesUplinksAddressesByDevice -> ex. 60+ +# | +--> MerakiGetOrganizationApplianceUplinkStatuses -> ex. 60+ +# | +--> MerakiGetOrganizationApplianceUplinksUsageByNetwork -> no cache +# | +--> MerakiGetOrganizationApplianceVpnStatuses -> ex. 60+ +# | +--> MerakiGetOrganizationSensorReadingsLatest -> ex. 60+ +# | +--> MerakiGetOrganizationWirelessDevicesEthernetStatuses -> ex. 60+ +# | +--> MerakiGetOrganizationCellularGatewayUplinkStatuses -> ex. 60. +# | +--> MerakiGetOrganizationSwitchPortsStatusesBySwitch -> ex. 60+ # | # +--\ MerakiSectionSerial # | | - adds serial as parameter # | | - sets cache_interval = 60 # | | -# | |--> MerakiGetDeviceSwitchPortsStatuses -> default 60+ -# | |--> MerakiGetDeviceWirelessStatus -> default 60+ -# | |--> MerakiGetDeviceAppliancePerformance +# | +--> MerakiGetDeviceSwitchPortsStatuses -> default 60+ +# | +--> MerakiGetDeviceWirelessStatus -> default 60+ +# | +--> MerakiGetDeviceAppliancePerformance +# | +--> MerakiGetDeviceLldpCdp # | # +--\ MerakiSectionNetwork # | - adds network id as parameter # | - sets cache_interval = 60 # | -# |--> MerakiGetNetworkAppliancePorts +# +--> MerakiGetNetworkAppliancePorts # class MerakiSection(DataCache): @@ -632,6 +634,19 @@ class MerakiGetDeviceWirelessStatus(MerakiSectionSerial): return [] +# class MerakiGetDeviceLldpCdp(MerakiSectionSerial): +# @property +# def name(self): +# return f'getDeviceLldpCdp_{self._serial}' +# +# def get_live_data(self): +# try: +# return self._config.dashboard.devices.getDeviceLldpCdp(self._serial) +# except meraki.exceptions.APIError as e: +# LOGGER.debug('Serial: %r: Get LLDP/CDP data: %r', self._serial, e) +# return [] + + class MerakiGetOrganizationCellularGatewayUplinkStatuses(MerakiSectionOrg): @property def name(self): @@ -692,20 +707,20 @@ class MerakiGetOrganizationSwitchPortsStatusesBySwitch(MerakiSectionOrg): return [] -class MerakiGetNetworkAppliancePorts(MerakiSectionNetwork): - @property - def name(self): - return f'getNetworkAppliancePorts_{self._network_id}' - - def get_live_data(self): - try: - return self._config.dashboard.appliance.getNetworkAppliancePorts( - self._network_id, - # total_pages='all', - ) - except meraki.exceptions.APIError as e: - LOGGER.debug('Network ID: %r: Get appliance ports: %r', self._network_id, e) - return [] +# class MerakiGetNetworkAppliancePorts(MerakiSectionNetwork): +# @property +# def name(self): +# return f'getNetworkAppliancePorts_{self._network_id}' +# +# def get_live_data(self): +# try: +# return self._config.dashboard.appliance.getNetworkAppliancePorts( +# self._network_id, +# # total_pages='all', +# ) +# except meraki.exceptions.APIError as e: +# LOGGER.debug('Network ID: %r: Get appliance ports: %r', self._network_id, e) +# return [] # @@ -788,6 +803,21 @@ class MerakiOrganisation: data=device, piggyback=self._get_device_piggyback(device, devices_by_serial) ) + # if SEC_NAME_DEVICE_LLDP_CDP not in self.config.excluded_sections and device.get( + # 'productType') not in [ + # # 'appliance', # bad data (inconsistent with switch data) + # 'sensor', # no data + # 'camera', # no data + # ]: + # if device_lldp_cdp := MerakiGetDeviceLldpCdp( + # config=self.config, + # serial=str(device['serial']), + # ).get_data(use_cache=self.config.use_cache): + # yield self._make_section( + # name=SEC_NAME_DEVICE_LLDP_CDP, + # data=device_lldp_cdp, + # piggyback=self._get_device_piggyback(device, devices_by_serial) + # ) if SEC_NAME_DEVICE_STATUSES not in self.config.excluded_sections: for device_status in MerakiGetOrganizationDevicesStatuses( @@ -910,60 +940,6 @@ class MerakiOrganisation: piggyback=piggyback, ) - # if _SEC_NAME_APPLIANCE_PORTS not in self.config.excluded_sections and networks: - # for network in networks: - # appliance_ports_by_network = MerakiGetNetworkAppliancePorts( - # config=self.config, - # network_id=network.get('id'), - # cache_interval=30, - # ).get_data(use_cache=self.config.use_cache) - # __ports = [ - # { - # 'number': 5, - # 'enabled': True, - # 'type': 'trunk', - # 'dropUntaggedTraffic': True, - # 'allowedVlans': 'all' - # }, - # { - # 'number': 6, - # 'enabled': True, - # 'type': 'trunk', - # 'dropUntaggedTraffic': True, - # 'allowedVlans': 'all' - # }, - # { - # 'number': 7, - # 'enabled': True, - # 'type': 'trunk', - # 'dropUntaggedTraffic': False, - # 'vlan': 1, - # 'allowedVlans': 'all'}, - # { - # 'number': 8, - # 'enabled': True, - # 'type': 'trunk', - # 'dropUntaggedTraffic': True, - # 'allowedVlans': 'all' - # }, - # { - # 'number': 9, - # 'enabled': True, - # 'type': 'trunk', - # 'dropUntaggedTraffic': False, - # 'vlan': 10, - # 'allowedVlans': 'all' - # }, - # { - # 'number': 10, - # 'enabled': True, - # 'type': 'trunk', - # 'dropUntaggedTraffic': False, - # 'vlan': 10, - # 'allowedVlans': 'all' - # } - # ] - if devices_by_type.get(API_NAME_DEVICE_TYPE_SWITCH): if SEC_NAME_SWITCH_PORTS_STATUSES not in self.config.excluded_sections: for switch in devices_by_type[API_NAME_DEVICE_TYPE_SWITCH]: @@ -1102,7 +1078,7 @@ class MerakiOrganisation: def _get_device_piggyback( self, device: MerakiAPIData, devices_by_serial: Mapping[str, MerakiAPIData] ) -> str | None: - LOGGER.critical(device) + LOGGER.debug(device) prefix = '' if self.config.org_id_as_prefix: prefix=self.organisation_id +'-' @@ -1173,7 +1149,6 @@ def write_sections(sections: Iterable[Section]) -> None: @dataclass(frozen=True) class CachePerSection: appliance_performance: int - appliance_ports: int appliance_uplinks: int appliance_uplinks_usage: int appliance_vpns: int @@ -1278,7 +1253,6 @@ def parse_arguments(argv: Sequence[str] | None) -> Args: help='List of cache time per section in minutes', default=[ SEC_CACHE_APPLIANCE_PERFORMANCE, - SEC_CACHE_APPLIANCE_PORTS, SEC_CACHE_APPLIANCE_UPLINKS, SEC_CACHE_APPLIANCE_UPLINKS_USAGE, SEC_CACHE_APPLIANCE_VPNS, @@ -1401,3 +1375,6 @@ def agent_cisco_meraki_main(args: Args) -> int: def main() -> int: return special_agent_main(parse_arguments, agent_cisco_meraki_main) + + + diff --git a/source/cmk_addons_plugins/meraki/lib/utils.py b/source/cmk_addons_plugins/meraki/lib/utils.py index 941ef4c525f4932e52ca4e9c6b04f332cf1f2131..201108ea3d7ea7bc4627aca66ec0a86458c83b53 100644 --- a/source/cmk_addons_plugins/meraki/lib/utils.py +++ b/source/cmk_addons_plugins/meraki/lib/utils.py @@ -29,7 +29,6 @@ SEC_NAME_NETWORKS: Final = '_networks' # internal use, runs always, needed for SEC_NAME_ORG_API_REQUESTS: Final = 'api-requests-by-organization' # internal use, runs always SEC_NAME_APPLIANCE_UPLINKS: Final = 'appliance-uplinks' -SEC_NAME_APPLIANCE_PORTS: Final = 'appliance-ports' SEC_NAME_APPLIANCE_UPLINKS_USAGE: Final = 'appliance-uplinks-usage' SEC_NAME_APPLIANCE_VPNS: Final = 'appliance-vpns' SEC_NAME_APPLIANCE_PERFORMANCE: Final = 'appliance-performance' @@ -41,6 +40,7 @@ SEC_NAME_SENSOR_READINGS: Final = 'sensor-readings' SEC_NAME_SWITCH_PORTS_STATUSES: Final = 'switch-ports-statuses' SEC_NAME_WIRELESS_DEVICE_STATUS: Final = 'wireless-device-status' SEC_NAME_WIRELESS_ETHERNET_STATUSES: Final = 'wireless-ethernet-statuses' +# SEC_NAME_DEVICE_LLDP_CDP: Final[str] = 'device-lldp-cdp' # api cache defaults per section SEC_CACHE_APPLIANCE_PERFORMANCE = 0 @@ -60,7 +60,6 @@ SEC_CACHE_SENSOR_READINGS = 0 SEC_CACHE_SWITCH_PORTS_STATUSES = 0 SEC_CACHE_WIRELESS_DEVICE_STATUS = 30 SEC_CACHE_WIRELESS_ETHERNET_STATUSES = 30 -SEC_CACHE_APPLIANCE_PORTS = 30 # Early Access SEC_NAME_ORG_SWITCH_PORTS_STATUSES: Final = 'org-switch-ports-statuses' diff --git a/source/cmk_addons_plugins/meraki/rulesets/organisations_api.py b/source/cmk_addons_plugins/meraki/rulesets/organisations_api.py index e76cc02d360b1e86fe22f66b1f41342af727644e..fdd5cdf75094f4c6d8ff5f8cb5a4793db73581fd 100644 --- a/source/cmk_addons_plugins/meraki/rulesets/organisations_api.py +++ b/source/cmk_addons_plugins/meraki/rulesets/organisations_api.py @@ -35,20 +35,15 @@ def _parameter_form() -> Dictionary: # params from discovery 'internal_item_name': DictElement( render_only=True, - parameter_form=ServiceState( + parameter_form=String( title=Title('Discovery internal item name') )), 'item_variant': DictElement( render_only=True, - parameter_form=ServiceState( + parameter_form=String( title=Title('Discovery item variant') )) }, - # ignored_keys=[ - # 'internal_item_name', - # 'old_item_name', - # 'item_variant', - # ], ) diff --git a/source/packages/cisco_meraki b/source/packages/cisco_meraki index 9704007fd5e2629fa5643bc60bfdcdc111e7f52b..fe2751f33f8daa1c1310e08e948c2a676f144397 100644 --- a/source/packages/cisco_meraki +++ b/source/packages/cisco_meraki @@ -63,7 +63,7 @@ 'web': ['plugins/views/cisco_meraki.py']}, 'name': 'cisco_meraki', 'title': 'Cisco Meraki special agent', - 'version': '1.4.2-20250104', + 'version': '1.4.4-20250303', 'version.min_required': '2.3.0b1', 'version.packaged': 'cmk-mkp-tool 0.2.0', 'version.usable_until': '2.4.0b1'}