diff --git a/mkp/cisco_meraki-1.3.0-20240623.mkp b/mkp/cisco_meraki-1.3.0-20240623.mkp index 9b8c0023dfea00e2115884da9be07cab6cc7d829..9f5f1f91227b192a4fb555660407449b600c0339 100644 Binary files a/mkp/cisco_meraki-1.3.0-20240623.mkp and b/mkp/cisco_meraki-1.3.0-20240623.mkp differ diff --git a/source/checks/agent_cisco_meraki b/source/checks/agent_cisco_meraki index 43dea5b1ddd78c8c83d4a482a52f1d91d851110d..fb3808c5f06f3c144fda39152b20ab66b7bed027 100644 --- a/source/checks/agent_cisco_meraki +++ b/source/checks/agent_cisco_meraki @@ -9,6 +9,8 @@ # - added no-cache option # 2023-11-18: changed from section to excluded_sections # 2023-11-22: replaced host_suffix_prefix option by org_id_as_prefix +# 2024-06-23: added cache time per section -> not nice but should work. + # # needs to be re implemented for CMK 2.3.X # https://github.com/Checkmk/checkmk/commit/c12cca9fe631d935ed5f239c23288ea856869e6e @@ -48,6 +50,9 @@ def agent_cisco_meraki_arguments( if excluded_sections := params.get("excluded_sections"): args.extend(["--excluded-sections"] + excluded_sections) + if cache_per_section := params.get("cache_per_section"): + args.extend(["--cache_per_section"] + list(cache_per_section)) + return args diff --git a/source/lib/python3/cmk/special_agents/agent_cisco_meraki.py b/source/lib/python3/cmk/special_agents/agent_cisco_meraki.py index 5a449a8f92a3e0600c5b1969ce1e5916bc2e0064..3d9b69d61b88854ada69e8489bd42aff70798d6f 100644 --- a/source/lib/python3/cmk/special_agents/agent_cisco_meraki.py +++ b/source/lib/python3/cmk/special_agents/agent_cisco_meraki.py @@ -36,6 +36,7 @@ # 2024-05-19: fixed proxy usage (NO_PROXY, FROM_ENVIRONMENT) # 2024-05-20: made appliance uplinks usage user selectable # made API requests per org user selectable +# 2024-06-23: added cache time per section -> not nice but should work. # ToDo: create inventory from Networks, is per organisation, not sure where/how to put this in the inventory # ToDo: list Connected Datacenters like Umbrella https://developer.cisco.com/meraki/api-v1/list-data-centers/ @@ -140,8 +141,8 @@ _SECTION_NAME_MAP = { _SEC_NAME_ORG_SWITCH_PORTS_STATUSES: "org_switch_ports_statuses", } -_MIN_CACHE_INTERVAL = 300 -_RANDOM_CACHE_INTERVAL = 300 +# _MIN_CACHE_INTERVAL = 300 +# _RANDOM_CACHE_INTERVAL = 300 MerakiCacheFilePath = Path(tmp_dir) / "agents" / "agent_cisco_meraki" MerakiAPIData = Mapping[str, object] @@ -192,6 +193,7 @@ class MerakiConfig: api_key: str # needed for Early Access proxy: str # needed for Early Access timespan: int + cache_per_section: CachePerSection | None = None class MerakiAPIDataSource(Enum): @@ -265,13 +267,13 @@ class MerakiSection(DataCache): def __init__( self, config: MerakiConfig, - cache_interval: int = 86400, + cache_interval: int = 1140, ): self._config = config self._received_results = {} self._cache_dir = MerakiCacheFilePath / self._config.hostname self._cache_file = MerakiCacheFilePath / self._config.hostname / self.name - self._cache_interval = cache_interval + self._cache_interval = cache_interval * 60 super().__init__(self._cache_dir, self.name) @property @@ -292,7 +294,7 @@ class MerakiSectionOrg(MerakiSection): self, config: MerakiConfig, org_id: str, - cache_interval: int = 86400, + cache_interval: int = 1140, ): self._org_id = org_id super().__init__(config=config, cache_interval=cache_interval) @@ -303,7 +305,7 @@ class MerakiSectionSerial(MerakiSection): self, config: MerakiConfig, serial: str, - cache_interval: int = _MIN_CACHE_INTERVAL + randrange(_RANDOM_CACHE_INTERVAL), + cache_interval: int = 1, ): self._serial = serial super().__init__(config=config, cache_interval=cache_interval) @@ -618,6 +620,7 @@ class MerakiGetOrganizationSwitchPortsStatusesBySwitch(MerakiSectionOrg): headers=headers, proxies=proxies, params=params, + timeout=3, ) return response.json() # return self._config.dashboard.organizations.getOrganizationDevices(self._org_id, total_pages='all') @@ -649,7 +652,9 @@ class MerakiOrganisation: def query(self) -> Iterator[Section]: if organisation := MerakiGetOrganization( config=self.config, - org_id=self.organisation_id).get_data(use_cache=self.config.use_cache): + org_id=self.organisation_id, + cache_interval=self.config.cache_per_section.organisations, + ).get_data(use_cache=self.config.use_cache): yield self._make_section( name=_SEC_NAME_ORGANISATIONS, data=organisation, @@ -662,8 +667,8 @@ class MerakiOrganisation: if api_requests := MerakiGetOrganizationApiRequestsOverviewResponseCodesByInterval( config=self.config, org_id=self.organisation_id, - # cache_interval=0 - ).get_data(use_cache=False): + cache_interval=self.config.cache_per_section.org_api_requests, + ).get_data(use_cache=False): # here we want always life data yield self._make_section( name=_SEC_NAME_ORG_API_REQUESTS, data={'org_id': self.organisation_id, 'requests': api_requests} @@ -678,7 +683,8 @@ class MerakiOrganisation: if networks := MerakiGetOrganizationNetworks( config=self.config, - org_id=self.organisation_id + org_id=self.organisation_id, + cache_interval=self.config.cache_per_section.networks, ).get_data(use_cache=self.config.use_cache): yield from self._add_networks(networks) @@ -718,7 +724,7 @@ class MerakiOrganisation: for device_status in MerakiGetOrganizationDevicesStatuses( config=self.config, org_id=self.organisation_id, - cache_interval=_MIN_CACHE_INTERVAL + randrange(_RANDOM_CACHE_INTERVAL), + cache_interval=self.config.cache_per_section.device_statuses, ).get_data(use_cache=self.config.use_cache): if piggyback := self._get_device_piggyback(device_status, devices_by_serial): yield self._make_section( @@ -730,7 +736,7 @@ class MerakiOrganisation: for device_uplink in MerakiGetOrganizationDevicesUplinksAddressesByDevice( config=self.config, org_id=self.organisation_id, - cache_interval=_MIN_CACHE_INTERVAL + randrange(_RANDOM_CACHE_INTERVAL), + cache_interval=self.config.cache_per_section.device_uplinks_info, ).get_data(use_cache=self.config.use_cache): if piggyback := self._get_device_piggyback(device_uplink, devices_by_serial): yield self._make_section( @@ -744,7 +750,7 @@ class MerakiOrganisation: for sensor_reading in MerakiGetOrganizationSensorReadingsLatest( config=self.config, org_id=self.organisation_id, - cache_interval=_MIN_CACHE_INTERVAL + randrange(_RANDOM_CACHE_INTERVAL) + cache_interval=self.config.cache_per_section.sensor_readings, ).get_data(use_cache=self.config.use_cache): if piggyback := self._get_device_piggyback(sensor_reading, devices_by_serial): yield self._make_section( @@ -759,7 +765,7 @@ class MerakiOrganisation: uplink_usage_by_network = MerakiGetOrganizationApplianceUplinksUsageByNetwork( config=self.config, org_id=self.organisation_id, - # cache_interval=0, + cache_interval=self.config.cache_per_section.appliance_uplinks_usage, ).get_data(use_cache=False) # here we want always life data # convert usage by network to usage by serial @@ -788,7 +794,7 @@ class MerakiOrganisation: for appliance_uplinks in MerakiGetOrganizationApplianceUplinkStatuses( config=self.config, org_id=self.organisation_id, - cache_interval=_MIN_CACHE_INTERVAL + randrange(_RANDOM_CACHE_INTERVAL) + cache_interval=self.config.cache_per_section.appliance_uplinks, ).get_data(use_cache=self.config.use_cache): if piggyback := self._get_device_piggyback(appliance_uplinks, devices_by_serial): # add network name @@ -811,7 +817,7 @@ class MerakiOrganisation: for appliance_vpn in MerakiGetOrganizationApplianceVpnStatuses( config=self.config, org_id=self.organisation_id, - cache_interval=_MIN_CACHE_INTERVAL + randrange(_RANDOM_CACHE_INTERVAL), + cache_interval=self.config.cache_per_section.appliance_vpns, ).get_data(use_cache=self.config.use_cache): appliance_vpn.update({_API_NAME_DEVICE_SERIAL: appliance_vpn['deviceSerial']}) if piggyback := self._get_device_piggyback(appliance_vpn, devices_by_serial): @@ -825,7 +831,8 @@ class MerakiOrganisation: for device in devices_by_type[_API_NAME_DEVICE_TYPE_APPLIANCE]: appliance_performance = MerakiGetDeviceAppliancePerformance( config=self.config, - serial=device[_API_NAME_DEVICE_SERIAL] + serial=device[_API_NAME_DEVICE_SERIAL], + cache_interval=self.config.cache_per_section.appliance_performance, ).get_data(use_cache=self.config.use_cache) if piggyback := self._get_device_piggyback({ _API_NAME_DEVICE_SERIAL: device[_API_NAME_DEVICE_SERIAL] @@ -842,7 +849,8 @@ class MerakiOrganisation: for switch in devices_by_type[_API_NAME_DEVICE_TYPE_SWITCH]: ports_statuses = MerakiGetDeviceSwitchPortsStatuses( config=self.config, - serial=switch[_API_NAME_DEVICE_SERIAL] + serial=switch[_API_NAME_DEVICE_SERIAL], + cache_interval=self.config.cache_per_section.switch_ports_statuses, ).get_data(use_cache=self.config.use_cache) if piggyback := self._get_device_piggyback( {_API_NAME_DEVICE_SERIAL: switch[_API_NAME_DEVICE_SERIAL]}, devices_by_serial @@ -858,7 +866,7 @@ class MerakiOrganisation: for device in MerakiGetOrganizationWirelessDevicesEthernetStatuses( config=self.config, org_id=self.organisation_id, - cache_interval=_MIN_CACHE_INTERVAL + randrange(_RANDOM_CACHE_INTERVAL), + cache_interval=self.config.cache_per_section.wireless_ethernet_statuses, ).get_data(use_cache=self.config.use_cache): if piggyback := self._get_device_piggyback(device, devices_by_serial): yield self._make_section( @@ -872,6 +880,7 @@ class MerakiOrganisation: wireless_statuses = MerakiGetDeviceWirelessStatus( config=self.config, serial=device[_API_NAME_DEVICE_SERIAL], + cache_interval=self.config.cache_per_section.wireless_device_status, ).get_data(use_cache=self.config.use_cache) if piggyback := self._get_device_piggyback({ _API_NAME_DEVICE_SERIAL: device[_API_NAME_DEVICE_SERIAL] @@ -887,7 +896,7 @@ class MerakiOrganisation: for gateway in MerakiGetOrganizationCellularGatewayUplinkStatuses( config=self.config, org_id=self.organisation_id, - cache_interval=_MIN_CACHE_INTERVAL + randrange(_RANDOM_CACHE_INTERVAL) + cache_interval=self.config.cache_per_section.cellular_uplinks, ).get_data(use_cache=self.config.use_cache): if piggyback := self._get_device_piggyback(gateway, devices_by_serial): yield self._make_section( @@ -901,7 +910,7 @@ class MerakiOrganisation: for switch in MerakiGetOrganizationSwitchPortsStatusesBySwitch( config=self.config, org_id=self.organisation_id, - cache_interval=_MIN_CACHE_INTERVAL + randrange(_RANDOM_CACHE_INTERVAL), + cache_interval=self.config.cache_per_section.org_switch_ports_statuses, ).get_data(use_cache=self.config.use_cache): if piggyback := self._get_device_piggyback(switch, devices_by_serial): yield self._make_section( @@ -954,7 +963,8 @@ class MerakiOrganisation: return _update_licenses_overview( MerakiGetOrganizationLicensesOverview( config=self.config, - org_id=self.organisation_id + org_id=self.organisation_id, + cache_interval=self.config.cache_per_section.licenses_overview, ).get_data(use_cache=self.config.use_cache) ) @@ -973,7 +983,8 @@ class MerakiOrganisation: str(device[_API_NAME_DEVICE_SERIAL]): _update_device(device) for device in MerakiGetOrganizationDevices( config=self.config, - org_id=self.organisation_id + org_id=self.organisation_id, + cache_interval=self.config.cache_per_section.device_info, ).get_data(use_cache=self.config.use_cache) } @@ -1034,6 +1045,27 @@ def _write_sections(sections: Iterable[Section]) -> None: # '----------------------------------------------------------------------' +@dataclass(frozen=True) +class CachePerSection: + appliance_performance: int + appliance_uplinks_usage: int + appliance_uplinks: int + appliance_vpns: int + cellular_uplinks: int + device_info: int + device_statuses: int + device_uplinks_info: int + licenses_overview: int + networks: int + org_api_requests: int + org_switch_ports_statuses: int + organisations: int + sensor_readings: int + switch_ports_statuses: int + wireless_device_status: int + wireless_ethernet_statuses: int + + class Args(Namespace): apikey: str debug: bool @@ -1044,6 +1076,7 @@ class Args(Namespace): orgs: Sequence[str] proxy: str sections: Sequence[str] + cache_per_section: List[int] | None = None def parse_arguments(argv: Sequence[str] | None) -> Args: @@ -1105,6 +1138,14 @@ def parse_arguments(argv: Sequence[str] | None) -> Args: help='Use organisation ID as hostname prefix.' ) + parser.add_argument( + '--cache_per_section', + nargs="+", + type=list[int], + help="List of chache time per section in minutes", + default=[0, 0, 60, 60, 60, 60, 60, 60, 600, 600, 0, 0, 600, 0, 0, 30, 30] + ) + return parser.parse_args(argv) @@ -1146,9 +1187,9 @@ def _get_organisations(config: MerakiConfig, org_ids: Sequence[str]) -> Sequence def get_proxy(raw_proxy: str) -> str | None: match raw_proxy: - # export https_proxy=http://192.168.10.144:3128 - # export http_proxy=http://192.168.10.144:3128 - # export ftp_proxy=http://192.168.10.144:3128 + # export https_proxy=http://192.168.10.144:3128 + # export http_proxy=http://192.168.10.144:3128 + # export ftp_proxy=http://192.168.10.144:3128 case 'NO_PROXY': # environ['NO_PROXY'] = 'api.meraki.com' # did not work environ['no_proxy'] = 'api.meraki.com' # explicit disable proxy for meraki @@ -1181,8 +1222,8 @@ def agent_cisco_meraki_main(args: Args) -> int: api_key=args.apikey, proxy=get_proxy(args.proxy), timespan=60, + cache_per_section=CachePerSection(* args.cache_per_section) if args.cache_per_section else None ) - organisations = [ MerakiOrganisation(config, organisation) for organisation in _get_organisations(config, args.orgs) diff --git a/source/web/plugins/wato/agent_cisco_meraki.py b/source/web/plugins/wato/agent_cisco_meraki.py index cec30c9b753bb6fc577012ddd51df4a6381bc915..a06ee7502940452ec4d9aaf83403d4f52f90fe59 100644 --- a/source/web/plugins/wato/agent_cisco_meraki.py +++ b/source/web/plugins/wato/agent_cisco_meraki.py @@ -22,23 +22,29 @@ # changed excluded_sections option from DualListChoice to ListChoice to avoid the "Selected" header # in conjunction with "excluded Sections" title # 2024-05-15: added api_key to required_keys +# 2024-06-23: added cache time per section -> not nice but should work. + +from typing import List -from _collections_abc import Sequence from cmk.gui.i18n import _ -from cmk.gui.plugins.wato.special_agents.common import RulespecGroupDatasourceProgramsApps +from cmk.gui.plugins.wato.special_agents.common import ( + RulespecGroupDatasourceProgramsApps +) from cmk.gui.plugins.wato.utils import ( HostRulespec, HTTPProxyReference, IndividualOrStoredPassword, - rulespec_registry, MKUserError, + rulespec_registry, ) from cmk.gui.valuespec import ( Dictionary, - ListOfStrings, - ValueSpec, FixedValue, + Integer, ListChoice, + ListOfStrings, + Tuple, + ValueSpec, ) from cmk.base.plugins.agent_based.utils.cisco_meraki import ( # _SEC_NAME_DEVICE_INFO, @@ -61,16 +67,44 @@ from cmk.base.plugins.agent_based.utils.cisco_meraki import ( _SEC_NAME_ORG_SWITCH_PORTS_STATUSES, # type: ignore[import] ) +_SEC_TITLE_DEVICE_INFO = _('Device info (Organization)') +_SEC_TITLE_NETWORKS = _('Network info (Organization)') +_SEC_TITLE_ORGANISATIONS = _('Organization (Agent)') +_SEC_TITLE_ORG_API_REQUESTS = _('API request (Organizaion)') +_SEC_TITLE_APPLIANCE_UPLINKS = _('Appliances uplinks (Organizaion)') +_SEC_TITLE_APPLIANCE_UPLINKS_USAGE = _( + 'Appliances uplinks usage (Organizaion)') +_SEC_TITLE_APPLIANCE_VPNS = _('Appliances VPNs (Organizaion)') +_SEC_TITLE_APPLIANCE_PERFORMANCE = _('Appliances Utilization (Device)') +_SEC_TITLE_CELLULAR_UPLINKS = _('Cellular devices uplinks (Organizaion)') +_SEC_TITLE_DEVICE_STATUSES = _('Devices status (Organizaion)') +_SEC_TITLE_DEVICE_UPLINKS_INFO = _('Devices uplink info (Organizaion)') +_SEC_TITLE_LICENSES_OVERVIEW = _('Licenses overview (Organizaion)') +_SEC_TITLE_SENSOR_READINGS = _('Sensors readings (Organizaion)') +_SEC_TITLE_SWITCH_PORTS_STATUSES = _('Switch ports status (Device)') +_SEC_TITLE_WIRELESS_ETHERNET_STATUSES = _( + 'Wireless devices ethernet status (Organizaion)') +_SEC_TITLE_WIRELESS_DEVICE_STATUS = _('Wireless devices SSIDs status (Device)') +_SEC_TITLE_ORG_SWITCH_PORTS_STATUSES = _( + 'Switch port status (Organizaion/Early Access)') + -def _validate_orgs(value: Sequence[str] | None, var_prefix: str): +def _validate_orgs(value: List[str] | None, var_prefix: str): # Check for duplicate Organisations + if value is None: + return _p = list(set(value.copy())) if len(_p) != len(value): raise MKUserError(var_prefix, _('Duplicate Organisation found')) for org_id in value: if not org_id.isdigit(): - raise MKUserError(var_prefix, _(f'Not a valid Organisation ID {org_id}. Organisation IDs are all digits')) + raise MKUserError( + var_prefix, _( + f'Not a valid Organisation ID {org_id}. Organisation IDs' + ' are all digits' + ) + ) def _valuespec_special_agent_cisco_meraki() -> ValueSpec: @@ -108,36 +142,68 @@ def _valuespec_special_agent_cisco_meraki() -> ValueSpec: ListChoice( title=_('excluded Sections'), choices=[ - (_SEC_NAME_ORG_API_REQUESTS, _('API request (Organizaion)')), - (_SEC_NAME_APPLIANCE_UPLINKS, _('Appliances uplinks (Organizaion)')), - (_SEC_NAME_APPLIANCE_UPLINKS_USAGE, _('Appliances uplinks usage (Organizaion)')), - (_SEC_NAME_APPLIANCE_VPNS, _('Appliances VPNs (Organizaion)')), - (_SEC_NAME_APPLIANCE_PERFORMANCE, _('Appliances Utilization (Device)')), - (_SEC_NAME_CELLULAR_UPLINKS, _('Cellular devices uplinks (Organizaion)')), - (_SEC_NAME_DEVICE_STATUSES, _('Devices status (Organizaion)')), - (_SEC_NAME_DEVICE_UPLINKS_INFO, _('Devices uplink info (Organizaion)')), - (_SEC_NAME_LICENSES_OVERVIEW, _('Licenses overview (Organizaion)')), - (_SEC_NAME_SENSOR_READINGS, _('Sensors readings (Organizaion)')), - (_SEC_NAME_SWITCH_PORTS_STATUSES, _('Switch ports status (Device)')), - (_SEC_NAME_WIRELESS_ETHERNET_STATUSES, _('Wireless devices ethernet status (Organizaion)')), - (_SEC_NAME_WIRELESS_DEVICE_STATUS, _('Wireless devices SSIDs status (Device)')), - (_SEC_NAME_ORG_SWITCH_PORTS_STATUSES, _('Switch port status (Organizaion/Early Access)')), + (_SEC_NAME_ORG_API_REQUESTS, _SEC_TITLE_ORG_API_REQUESTS), + (_SEC_NAME_APPLIANCE_UPLINKS, _SEC_TITLE_APPLIANCE_UPLINKS), + (_SEC_NAME_APPLIANCE_UPLINKS_USAGE, + _SEC_TITLE_APPLIANCE_UPLINKS_USAGE), + (_SEC_NAME_APPLIANCE_VPNS, _SEC_TITLE_APPLIANCE_VPNS), + (_SEC_NAME_APPLIANCE_PERFORMANCE, + _SEC_TITLE_APPLIANCE_PERFORMANCE), + (_SEC_NAME_CELLULAR_UPLINKS, _SEC_TITLE_CELLULAR_UPLINKS), + (_SEC_NAME_DEVICE_STATUSES, _SEC_TITLE_DEVICE_STATUSES), + (_SEC_NAME_DEVICE_UPLINKS_INFO, + _SEC_TITLE_DEVICE_UPLINKS_INFO), + (_SEC_NAME_LICENSES_OVERVIEW, _SEC_TITLE_LICENSES_OVERVIEW), + (_SEC_NAME_SENSOR_READINGS, _SEC_TITLE_SENSOR_READINGS), + (_SEC_NAME_SWITCH_PORTS_STATUSES, + _SEC_TITLE_SWITCH_PORTS_STATUSES), + (_SEC_NAME_WIRELESS_ETHERNET_STATUSES, + _SEC_TITLE_SWITCH_PORTS_STATUSES), + (_SEC_NAME_WIRELESS_DEVICE_STATUS, + _SEC_TITLE_WIRELESS_DEVICE_STATUS), + (_SEC_NAME_ORG_SWITCH_PORTS_STATUSES, + _SEC_TITLE_ORG_SWITCH_PORTS_STATUSES), ], - help=_('Query only the selected sections. Default is Query all sections.'), + help=_( + 'Query only the selected sections. Default is Query all sections.'), default_value=[ - _SEC_NAME_ORG_SWITCH_PORTS_STATUSES, - _SEC_NAME_APPLIANCE_PERFORMANCE, - _SEC_NAME_SWITCH_PORTS_STATUSES, - _SEC_NAME_WIRELESS_DEVICE_STATUS, + _SEC_NAME_ORG_SWITCH_PORTS_STATUSES, + _SEC_NAME_APPLIANCE_PERFORMANCE, + _SEC_NAME_SWITCH_PORTS_STATUSES, + _SEC_NAME_WIRELESS_DEVICE_STATUS, ], )), ('orgs', ListOfStrings( title=_('Organisation IDs'), - help=_('List of Organisation IDs to query. Defaulr is all Organisation IDs'), + help=_( + 'List of Organisation IDs to query. Defaulr is all Organisation IDs'), allow_empty=False, validate=_validate_orgs, )), + ('cache_per_section', + Tuple( + title='Set Cache time per section', + elements=[ + Integer(title=_SEC_TITLE_APPLIANCE_PERFORMANCE, minvalue=0, unit='minutes', default_value=0), + Integer(title=_SEC_TITLE_APPLIANCE_UPLINKS_USAGE, minvalue=0, unit='minutes', default_value=0), + Integer(title=_SEC_TITLE_APPLIANCE_UPLINKS, minvalue=0, unit='minutes', default_value=60), + Integer(title=_SEC_TITLE_APPLIANCE_VPNS, minvalue=0, unit='minutes', default_value=60), + Integer(title=_SEC_TITLE_CELLULAR_UPLINKS, minvalue=0, unit='minutes', default_value=60), + Integer(title=_SEC_TITLE_DEVICE_INFO, minvalue=0, unit='minutes', default_value=60), + Integer(title=_SEC_TITLE_DEVICE_STATUSES, minvalue=0, unit='minutes', default_value=60), + Integer(title=_SEC_TITLE_DEVICE_UPLINKS_INFO, minvalue=0, unit='minutes', default_value=60), + Integer(title=_SEC_TITLE_LICENSES_OVERVIEW, minvalue=0, unit='minutes', default_value=600), + Integer(title=_SEC_TITLE_NETWORKS, minvalue=0, unit='minutes', default_value=600), + Integer(title=_SEC_TITLE_ORG_API_REQUESTS, minvalue=0, unit='minutes', default_value=0), + Integer(title=_SEC_TITLE_ORG_SWITCH_PORTS_STATUSES, minvalue=0, unit='minutes', default_value=0), + Integer(title=_SEC_TITLE_ORGANISATIONS, minvalue=0, unit='minutes', default_value=600), + Integer(title=_SEC_TITLE_SENSOR_READINGS, minvalue=0, unit='minutes', default_value=0), + Integer(title=_SEC_TITLE_SWITCH_PORTS_STATUSES, minvalue=0, unit='minutes', default_value=0), + Integer(title=_SEC_TITLE_WIRELESS_DEVICE_STATUS, minvalue=0, unit='minutes', default_value=30), + Integer(title=_SEC_TITLE_WIRELESS_ETHERNET_STATUSES, minvalue=0, unit='minutes', default_value=30), + ], + )) ], optional_keys=True, ignored_keys=['sections', 'host_suffix_prefix'],