Skip to content

Commit

Permalink
Fix count enabled/warning
Browse files Browse the repository at this point in the history
  • Loading branch information
CLiX-1 committed Jul 18, 2024
1 parent a2adb95 commit 6b63ff4
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 66 deletions.
16 changes: 9 additions & 7 deletions m365/agent_based/m365_licenses.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,10 @@ def check_m365_licenses(item: str, params: Mapping[str, Any], section: Section)
lic_units_suspended = license["lic_units_suspended"]
lic_units_warning = license["lic_units_warning"]

lic_units_consumed_pct = round(lic_units_consumed / lic_units_enabled * 100, 2)
lic_units_available = lic_units_enabled - lic_units_consumed
lic_units_total = lic_units_enabled + lic_units_warning

lic_units_consumed_pct = round(lic_units_consumed / lic_units_total * 100, 2)
lic_units_available = lic_units_total - lic_units_consumed

result_level = ""
result_state = State.OK
Expand All @@ -116,7 +118,7 @@ def check_m365_licenses(item: str, params: Mapping[str, Any], section: Section)

if params_levels_available[0] == "lic_unit_available_lower_pct":
levels_consumed_pct = (100 - warning_level, 100 - critical_level)
available_percent = lic_units_available / lic_units_enabled * 100
available_percent = lic_units_available / lic_units_total * 100

if available_percent < critical_level:
result_state = State.CRIT
Expand All @@ -128,7 +130,7 @@ def check_m365_licenses(item: str, params: Mapping[str, Any], section: Section)
)

else:
levels_consumed_abs = (lic_units_enabled - warning_level, lic_units_enabled - critical_level)
levels_consumed_abs = (lic_units_total - warning_level, lic_units_total - critical_level)

if lic_units_consumed > levels_consumed_abs[1]:
result_state = State.CRIT
Expand All @@ -138,7 +140,7 @@ def check_m365_licenses(item: str, params: Mapping[str, Any], section: Section)
result_level = f" (warn/crit below {warning_level}/{critical_level} available)"

result_summary = (
f"Consumed: {render.percent(lic_units_consumed_pct)} - {lic_units_consumed} of {lic_units_enabled}"
f"Consumed: {render.percent(lic_units_consumed_pct)} - {lic_units_consumed} of {lic_units_total}"
f", Available: {lic_units_available}"
f"{result_level}"
f"{', Warning: ' + str(lic_units_warning) if lic_units_warning > 0 else ''}"
Expand All @@ -160,12 +162,12 @@ def check_m365_licenses(item: str, params: Mapping[str, Any], section: Section)
details=result_details,
)

yield Metric(name="m365_licenses_total", value=lic_units_total)
yield Metric(name="m365_licenses_enabled", value=lic_units_enabled)
yield Metric(name="m365_licenses_consumed", value=lic_units_consumed, levels=levels_consumed_abs)
yield Metric(name="m365_licenses_consumed_pct", value=lic_units_consumed_pct, levels=levels_consumed_pct)
yield Metric(name="m365_licenses_available", value=lic_units_available)
if lic_units_warning > 0:
yield Metric(name="m365_licenses_warning", value=lic_units_warning + lic_units_enabled)
yield Metric(name="m365_licenses_warning", value=lic_units_warning)


agent_section_m365_licenses = AgentSection(
Expand Down
23 changes: 21 additions & 2 deletions m365/checkman/m365_licenses
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,34 @@ catalog: cloud/Microsoft
license: GPLv2
distribution: Christopher Pommer
description:
This check monitors the active licenses from a Microsoft 365 tenant.
This check monitors the Microsoft licenses (enabled and warning)
from a Microsoft 365 tenant.

Depending on the configured check levels, the service is in
state {OK}, {WARN} or {CRIT}.

You have to configure the special agent {Microsoft 365}.

{enabled:}
The number of units that are enabled for the active subscription of
the service SKU.

{lockedOut:}
The number of units that are locked out because the customer canceled
their subscription of the service SKU.

{suspended:}
The number of units that are suspended because the subscription of
the service SKU has been canceled. The units can't be assigned but
can still be reactivated before they're deleted.

{warning:}
The number of units that are in warning status. When the subscription
of the service SKU has expired, the customer has a grace period to
renew their subscription before it's canceled (moved to a suspended state).

item:
M365 license SKU name.

discovery:
One service is created for each active Microsoft 365 license.
One service is created for each Microsoft 365 license (enabled and warning).
19 changes: 13 additions & 6 deletions m365/graphing/m365_licenses.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,13 @@
UNIT_COUNTER = Unit(DecimalNotation(""), StrictPrecision(0))
UNIT_PERCENTAGE = Unit(DecimalNotation("%"))

metric_m365_licenses_available = Metric(
name="m365_licenses_available",
title=Title("Available"),
unit=UNIT_COUNTER,
color=Color.LIGHT_GRAY,
)

metric_m365_licenses_consumed = Metric(
name="m365_licenses_consumed",
title=Title("Consumed"),
Expand All @@ -52,14 +59,14 @@
name="m365_licenses_enabled",
title=Title("Enabled"),
unit=UNIT_COUNTER,
color=Color.DARK_CYAN,
color=Color.PURPLE,
)

metric_m365_licenses_available = Metric(
name="m365_licenses_available",
title=Title("Available"),
metric_m365_licenses_total = Metric(
name="m365_licenses_total",
title=Title("Total (Enabled + Warning)"),
unit=UNIT_COUNTER,
color=Color.LIGHT_GRAY,
color=Color.GREEN,
)

metric_m365_licenses_warning = Metric(
Expand All @@ -77,12 +84,12 @@
"m365_licenses_available",
],
simple_lines=[
"m365_licenses_total",
"m365_licenses_enabled",
"m365_licenses_warning",
WarningOf("m365_licenses_consumed"),
CriticalOf("m365_licenses_consumed"),
],
optional=["m365_licenses_warning"],
)

graph_m365_license_usage = Graph(
Expand Down
101 changes: 50 additions & 51 deletions m365/libexec/agent_m365
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,47 @@ def get_access_token(tenant_id, app_id, app_secret, resource_scope):
return access_token


def get_m365_licenses(token):
m365_licenses_url = (
"https://graph.microsoft.com/v1.0/subscribedSkus"
"?$select=skuId,skuPartNumber,capabilityStatus,consumedUnits,prepaidUnits"
)

headers = {"Authorization": "Bearer " + token}

try:
m365_licenses_response = requests.get(m365_licenses_url, headers=headers)
m365_licenses_response.raise_for_status()
except requests.exceptions.RequestException as err:
print(m365_licenses_response.text)
sys.stderr.write("CRITICAL | Failed to get m365 licenses\n")
sys.stderr.write(f"Error: {err}\n")
sys.exit(2)

m365_licenses = m365_licenses_response.json().get("value", [])

license_list = []
for license in m365_licenses:
lic_units = license["prepaidUnits"]
if license["capabilityStatus"] in ["Enabled", "Warning"]:
license_dict = {
"lic_sku_id": license["skuId"],
"lic_sku_name": license["skuPartNumber"],
"lic_state": license["capabilityStatus"],
"lic_units_consumed": license["consumedUnits"],
"lic_units_enabled": lic_units["enabled"],
"lic_units_lockedout": lic_units["lockedOut"],
"lic_units_suspended": lic_units["suspended"],
"lic_units_warning": lic_units["warning"],
}

license_list.append(license_dict)

return license_list


def get_m365_service_health(token):
m365_healt_overview_url = "https://graph.microsoft.com/v1.0/admin/serviceAnnouncement/healthOverviews/"
m365_healt_overview_url = "https://graph.microsoft.com/v1.0/admin/serviceAnnouncement/healthOverviews"

headers = {"Authorization": "Bearer " + token}

Expand All @@ -95,7 +134,7 @@ def get_m365_service_health(token):
except requests.exceptions.RequestException as err:
sys.stderr.write("CRITICAL | Failed to get m365 service overview\n")
sys.stderr.write(f"Error: {err}\n")
sys.exit(2)
sys.exit(3)

m365_health_overview = m365_health_overview_response.json().get("value", [])

Expand All @@ -112,7 +151,7 @@ def get_m365_service_health(token):
except requests.exceptions.RequestException as err:
sys.stderr.write("CRITICAL | Failed to get m365 service issues\n")
sys.stderr.write(f"Error: {err}\n")
sys.exit(3)
sys.exit(4)

m365_health_issues = m365_health_issues_response.json().get("value", [])

Expand All @@ -123,65 +162,26 @@ def get_m365_service_health(token):
for issue in m365_health_issues:
if service_name == issue["service"]:
issue_dict = {
"issue_title": issue.get("title"),
"issue_start": issue.get("startDateTime"),
"issue_feature": issue.get("feature"),
"issue_classification": issue.get("classification"),
"issue_feature": issue.get("feature"),
"issue_id": issue.get("id"),
"issue_start": issue.get("startDateTime"),
"issue_title": issue.get("title"),
}

issue_list.append(issue_dict)

service_dict = {
"service_issues": issue_list,
"service_name": service_name,
"service_status": service.get("status"),
"service_issues": issue_list,
}

service_list.append(service_dict)

return service_list


def get_m365_licenses(token):
m365_licenses_url = (
"https://graph.microsoft.com/v1.0/subscribedSkus"
"?$select=skuId,skuPartNumber,capabilityStatus,consumedUnits,prepaidUnits"
)

headers = {"Authorization": "Bearer " + token}

try:
m365_licenses_response = requests.get(m365_licenses_url, headers=headers)
m365_licenses_response.raise_for_status()
except requests.exceptions.RequestException as err:
print(m365_licenses_response.text)
sys.stderr.write("CRITICAL | Failed to get m365 licenses\n")
sys.stderr.write(f"Error: {err}\n")
sys.exit(4)

m365_licenses = m365_licenses_response.json().get("value", [])

license_list = []
for license in m365_licenses:
lic_units = license["prepaidUnits"]
if license["capabilityStatus"] in ["Enabled", "Warning"]:
license_dict = {
"lic_sku_id": license["skuId"],
"lic_sku_name": license["skuPartNumber"],
"lic_state": license["capabilityStatus"],
"lic_units_consumed": license["consumedUnits"],
"lic_units_enabled": lic_units["enabled"],
"lic_units_lockedout": lic_units["lockedOut"],
"lic_units_suspended": lic_units["suspended"],
"lic_units_warning": lic_units["warning"],
}

license_list.append(license_dict)

return license_list


def main():
args = parse_arguments()
tenant_id = args.tenant_id
Expand All @@ -195,15 +195,14 @@ def main():

token = get_access_token(tenant_id, app_id, app_secret, resource_scope)

# if not services_to_monitor or "m365_service_health" in services_to_monitor:
if "m365_service_health" in services_to_monitor:
print("<<<m365_service_health:sep(0)>>>")
print(json.dumps(get_m365_service_health(token)))

if "m365_licenses" in services_to_monitor:
print("<<<m365_licenses:sep(0)>>>")
print(json.dumps(get_m365_licenses(token)))

if "m365_service_health" in services_to_monitor:
print("<<<m365_service_health:sep(0)>>>")
print(json.dumps(get_m365_service_health(token)))


if __name__ == "__main__":
main()

0 comments on commit 6b63ff4

Please sign in to comment.