Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Log probe update metadata #940

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import logging
from datetime import datetime, timezone, timedelta
import time
from typing import List
from typing import List, Optional

from fastapi import APIRouter, Depends, HTTPException, Response
from prometheus_client import Counter, Info
from enum import Enum

from ...common.dependencies import get_settings
from ...common.routers import BaseModel
Expand All @@ -15,6 +17,15 @@

log = logging.getLogger(__name__)

class Metrics:
PROBE_LOGIN = Counter(
"probe_login_requests", "Requests made to the probe login endpoint",
labelnames=["state", "detail", "login"]
)

PROBE_UPDATE_INFO = Info(
"probe_update_info", "Information reported in the probe update endpoint",
)

class ProbeLogin(BaseModel):
# Allow None username and password
Expand All @@ -40,27 +51,28 @@ def probe_login_post(
raise HTTPException(status_code=401, detail="Missing credentials")

token = probe_login.username
# TODO: We have to find a way to explicitly log metrics with prometheus.
# We're currently using the instrumentator default metrics, like http response counts
# Maybe using the same exporter as the instrumentator?

try:
dec = decode_jwt(token, audience="probe_login", key=settings.jwt_encryption_key)
registration_time = dec["iat"]

log.info("probe login: successful")
# metrics.incr("probe_login_successful")
Metrics.PROBE_LOGIN.labels(login = 'standard', detail="ok", state="successful").inc()

except jwt.exceptions.MissingRequiredClaimError:
log.info("probe login: invalid or missing claim")
# metrics.incr("probe_login_failed")
Metrics.PROBE_LOGIN.labels(login = 'standard', detail="invalid_or_missing_claim", state="failed").inc()

raise HTTPException(status_code=401, detail="Invalid credentials")
except jwt.exceptions.InvalidSignatureError:
log.info("probe login: invalid signature")
# metrics.incr("probe_login_failed")
Metrics.PROBE_LOGIN.labels(login = 'standard', detail="invalid_signature", state="failed").inc()

raise HTTPException(status_code=401, detail="Invalid credentials")
except jwt.exceptions.DecodeError:
# Not a JWT token: treat it as a "legacy" login
# return jerror("Invalid or missing credentials", code=401)
log.info("probe login: legacy login successful")
# metrics.incr("probe_legacy_login_successful")
Metrics.PROBE_LOGIN.labels(login = 'legacy', detail="ok", state="successful").inc()

registration_time = None

exp = datetime.now(timezone.utc) + timedelta(days=7)
Expand Down Expand Up @@ -131,7 +143,28 @@ def probe_register_post(


class ProbeUpdate(BaseModel):
pass
"""
The original format of this comes from:
https://github.com/ooni/orchestra/blob/master/registry/registry/handler/registry.go#L25
"""
probe_cc : Optional[str] = None
probe_asn : Optional[str] = None
platform : Optional[str] = None

software_name : Optional[str] = None
software_version : Optional[str] = None
supported_tests : Optional[List[str]] = None

network_type : Optional[str] = None
available_bandwidth : Optional[str] = None
language : Optional[str] = None

token : Optional[str] = None

probe_family : Optional[str] = None
probe_id : Optional[str] = None

password : Optional[str] = None


class ProbeUpdateResponse(BaseModel):
Expand All @@ -141,4 +174,17 @@ class ProbeUpdateResponse(BaseModel):
@router.put("/update/{client_id}", tags=["ooniprobe"])
def probe_update_post(probe_update: ProbeUpdate) -> ProbeUpdateResponse:
log.info("update successful")

# Log update metadata into prometheus
probe_update_dict = probe_update.model_dump(exclude_none=True)

# Info doesn't allows list, if we have a list we have to convert it
# to string
if probe_update_dict['supported_tests'] is not None:
tests = probe_update_dict['supported_tests']
tests_str = ";".join(tests)
probe_update_dict['supported_tests'] = tests_str

Metrics.PROBE_UPDATE_INFO.info(probe_update_dict)

return ProbeUpdateResponse(status="ok")
6 changes: 3 additions & 3 deletions ooniapi/services/ooniprobe/tests/test_probe_auth.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Dict
from typing import Dict, Any
from ooniprobe.common import auth
from fastapi.testclient import TestClient

Expand Down Expand Up @@ -58,14 +58,14 @@ def test_update(client: TestClient, jwt_encryption_key):
assert json["status"] == "ok"


def _get_update_data() -> Dict[str, str]:
def _get_update_data() -> Dict[str, Any]:
return {
"probe_cc": "IT",
"probe_asn": "AS1234",
"platform": "android",
"software_name": "ooni-testing",
"software_version": "0.0.1",
"supported_tests": "web_connectivity",
"supported_tests": ["web_connectivity"],
"network_type": "wifi",
"available_bandwidth": "100",
"language": "en",
Expand Down
Loading