|
| 1 | +#!/usr/bin/env python3 |
| 2 | +# -*- encoding: utf-8; py-indent-offset: 4 -*- |
| 3 | + |
| 4 | +# Copyright (C) 2024 Christopher Pommer <cp.software@outlook.de> |
| 5 | + |
| 6 | +# This program is free software; you can redistribute it and/or |
| 7 | +# modify it under the terms of the GNU General Public License |
| 8 | +# as published by the Free Software Foundation; either version 2 |
| 9 | +# of the License, or (at your option) any later version. |
| 10 | + |
| 11 | +# This program is distributed in the hope that it will be useful, |
| 12 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 14 | +# GNU General Public License for more details. |
| 15 | + |
| 16 | +# You should have received a copy of the GNU General Public License |
| 17 | +# along with this program; if not, write to the Free Software |
| 18 | +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
| 19 | + |
| 20 | + |
| 21 | +import json |
| 22 | +from collections.abc import Mapping, Sequence |
| 23 | +from dataclasses import dataclass |
| 24 | +from typing import Any |
| 25 | + |
| 26 | +from cmk.agent_based.v2 import ( |
| 27 | + AgentSection, |
| 28 | + CheckPlugin, |
| 29 | + CheckResult, |
| 30 | + DiscoveryResult, |
| 31 | + Metric, |
| 32 | + render, |
| 33 | + Result, |
| 34 | + Service, |
| 35 | + State, |
| 36 | + StringTable, |
| 37 | +) |
| 38 | + |
| 39 | + |
| 40 | +@dataclass(frozen=True) |
| 41 | +class IntuneApps: |
| 42 | + app_type: str |
| 43 | + app_name: str |
| 44 | + app_publisher: str |
| 45 | + app_license_total: int |
| 46 | + app_license_consumed: int |
| 47 | + app_assigned: bool |
| 48 | + |
| 49 | + |
| 50 | +Section = Mapping[str, Sequence[IntuneApps]] |
| 51 | + |
| 52 | +# Example data from special agent: |
| 53 | +# <<<ms_intune_app_licenses:sep(0)>>> |
| 54 | +# [ |
| 55 | +# { |
| 56 | +# "app_type": "iOS VPP" |
| 57 | +# "app_name": "Adobe Account Access", |
| 58 | +# "app_publisher": "ADOBE SYSTEMS SOFTWARE IRELAND LIMITED", |
| 59 | +# "app_license_total": 40, |
| 60 | +# "app_license_consumed": 7 |
| 61 | +# "app_assigned": true |
| 62 | +# }, |
| 63 | +# { |
| 64 | +# "app_type": "MS Store for business" |
| 65 | +# "app_name": "Microsoft Outlook", |
| 66 | +# "app_publisher": "Microsoft Corporation", |
| 67 | +# "app_license_total": 100, |
| 68 | +# "app_license_consumed": 92 |
| 69 | +# "app_assigned": true |
| 70 | +# }, |
| 71 | +# ... |
| 72 | +# ] |
| 73 | + |
| 74 | + |
| 75 | +def parse_ms_intune_app_licenses(string_table: StringTable) -> Section: |
| 76 | + parsed = {} |
| 77 | + for item in json.loads("".join(string_table[0])): |
| 78 | + parsed[item["app_name"] + " - " + item["app_type"]] = item |
| 79 | + return parsed |
| 80 | + |
| 81 | + |
| 82 | +def discover_ms_intune_app_licenses(section: Section) -> DiscoveryResult: |
| 83 | + for group in section: |
| 84 | + yield Service(item=group) |
| 85 | + |
| 86 | + |
| 87 | +def check_ms_intune_app_licenses(item: str, params: Mapping[str, Any], section: Section) -> CheckResult: |
| 88 | + license = section.get(item) |
| 89 | + if not license: |
| 90 | + return |
| 91 | + |
| 92 | + app_name = license["app_name"] |
| 93 | + app_type = license["app_type"] |
| 94 | + app_publisher = license["app_publisher"] |
| 95 | + app_license_total = license["app_license_total"] |
| 96 | + app_license_consumed = license["app_license_consumed"] |
| 97 | + app_assigned = license["app_assigned"] |
| 98 | + |
| 99 | + app_license_consumed_pct = round(app_license_consumed / app_license_total * 100, 2) |
| 100 | + lic_units_available = app_license_total - app_license_consumed |
| 101 | + |
| 102 | + result_level = "" |
| 103 | + result_state = State.OK |
| 104 | + levels_consumed_abs = (None, None) |
| 105 | + levels_consumed_pct = (None, None) |
| 106 | + params_lic_total_min = params["lic_total_min"] |
| 107 | + if app_license_total >= params_lic_total_min: |
| 108 | + params_levels_available = params["lic_unit_available_lower"] |
| 109 | + if params_levels_available[1][0] == "fixed": |
| 110 | + warning_level, critical_level = params_levels_available[1][1] |
| 111 | + |
| 112 | + if params_levels_available[0] == "lic_unit_available_lower_pct": |
| 113 | + levels_consumed_pct = (100 - warning_level, 100 - critical_level) |
| 114 | + available_percent = lic_units_available / app_license_total * 100 |
| 115 | + |
| 116 | + if available_percent < critical_level: |
| 117 | + result_state = State.CRIT |
| 118 | + elif available_percent < warning_level: |
| 119 | + result_state = State.WARN |
| 120 | + |
| 121 | + result_level = ( |
| 122 | + f" (warn/crit below {render.percent(warning_level)}/{render.percent(critical_level)} available)" |
| 123 | + ) |
| 124 | + |
| 125 | + else: |
| 126 | + levels_consumed_abs = (app_license_total - warning_level, app_license_total - critical_level) |
| 127 | + |
| 128 | + if app_license_consumed > levels_consumed_abs[1]: |
| 129 | + result_state = State.CRIT |
| 130 | + elif app_license_consumed > levels_consumed_abs[0]: |
| 131 | + result_state = State.WARN |
| 132 | + |
| 133 | + result_level = f" (warn/crit below {warning_level}/{critical_level} available)" |
| 134 | + |
| 135 | + result_summary = ( |
| 136 | + f"Consumed: {render.percent(app_license_consumed_pct)} - {app_license_consumed} of {app_license_total}" |
| 137 | + f", Available: {lic_units_available}" |
| 138 | + f"{result_level}" |
| 139 | + ) |
| 140 | + |
| 141 | + result_details = ( |
| 142 | + f"App: {app_name} ({app_publisher})\n - Type: {app_type}\n - Assigned: {app_assigned}" |
| 143 | + f"\n - Total: {app_license_total}\n - Used: {app_license_consumed}" |
| 144 | + ) |
| 145 | + |
| 146 | + yield Result( |
| 147 | + state=result_state, |
| 148 | + summary=result_summary, |
| 149 | + details=result_details, |
| 150 | + ) |
| 151 | + |
| 152 | + yield Metric(name="ms_intune_app_licenses_total", value=app_license_total) |
| 153 | + yield Metric(name="ms_intune_app_licenses_consumed", value=app_license_consumed, levels=levels_consumed_abs) |
| 154 | + yield Metric(name="ms_intune_app_licenses_consumed_pct", value=app_license_consumed_pct, levels=levels_consumed_pct) |
| 155 | + yield Metric(name="ms_intune_app_licenses_available", value=lic_units_available) |
| 156 | + |
| 157 | + |
| 158 | +agent_section_ms_intune_app_licenses = AgentSection( |
| 159 | + name="ms_intune_app_licenses", |
| 160 | + parse_function=parse_ms_intune_app_licenses, |
| 161 | +) |
| 162 | + |
| 163 | + |
| 164 | +check_plugin_ms_intune_app_licenses = CheckPlugin( |
| 165 | + name="ms_intune_app_licenses", |
| 166 | + service_name="Intune app %s", |
| 167 | + discovery_function=discover_ms_intune_app_licenses, |
| 168 | + check_function=check_ms_intune_app_licenses, |
| 169 | + check_ruleset_name="ms_intune_app_licenses", |
| 170 | + check_default_parameters={ |
| 171 | + "lic_unit_available_lower": ("lic_unit_available_lower_pct", ("fixed", (10.0, 5.0))), |
| 172 | + "lic_total_min": 1, |
| 173 | + }, |
| 174 | +) |
0 commit comments