123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132 |
- from urllib.parse import urlparse
- from django.conf import settings
- from django.core.validators import URLValidator
- from django.urls import reverse
- from ninja import Field, ModelSchema
- from ninja.errors import ValidationError
- from pydantic import model_validator
- from glitchtip.schema import CamelSchema
- from .constants import HTTP_MONITOR_TYPES, MonitorType
- from .models import Monitor, MonitorCheck, StatusPage
- class MonitorCheckSchema(CamelSchema, ModelSchema):
- class Meta:
- model = MonitorCheck
- fields = ["is_up", "start_check", "reason"]
- class MonitorCheckResponseTimeSchema(MonitorCheckSchema, ModelSchema):
- """Monitor check with response time. Used in Monitors detail api and monitor checks list"""
- class Meta(MonitorCheckSchema.Meta):
- fields = MonitorCheckSchema.Meta.fields + ["response_time"]
- class MonitorIn(CamelSchema, ModelSchema):
- @model_validator(mode="after")
- def validate(self):
- monitor_type = self.monitor_type
- if self.url == "" and monitor_type in HTTP_MONITOR_TYPES + (MonitorType.SSL,):
- raise ValidationError("URL is required for " + monitor_type)
- if monitor_type in HTTP_MONITOR_TYPES:
- URLValidator()(self.url)
- if self.expected_status is None and monitor_type in [
- MonitorType.GET,
- MonitorType.POST,
- ]:
- raise ValidationError("Expected status is required for " + monitor_type)
- if monitor_type == MonitorType.PORT:
- url = self.url.replace("http://", "//", 1)
- if not url.startswith("//"):
- url = "//" + url
- parsed_url = urlparse(url)
- message = "Invalid Port URL, expected hostname and port"
- try:
- if not all([parsed_url.hostname, parsed_url.port]):
- raise ValidationError(message)
- except ValueError as err:
- raise ValidationError(message) from err
- self.url = f"{parsed_url.hostname}:{parsed_url.port}"
- return self
- class Meta:
- model = Monitor
- fields = [
- "monitor_type",
- "name",
- "url",
- "expected_status",
- "expected_body",
- "project",
- "interval",
- "timeout",
- ]
- class MonitorSchema(MonitorIn, ModelSchema):
- project: int | None = Field(validation_alias="project_id")
- environment: int | None = Field(validation_alias="environment_id")
- is_up: bool | None = Field(validation_alias="latest_is_up")
- last_change: str | None
- heartbeat_endpoint: str | None
- project_name: str | None = None
- env_name: str | None = None
- checks: list[MonitorCheckSchema]
- organization: int = Field(validation_alias="organization_id")
- class Meta(MonitorIn.Meta):
- fields = [
- "id",
- "monitor_type",
- "endpoint_id",
- "created",
- "name",
- "url",
- "expected_status",
- "expected_body",
- "interval",
- "timeout",
- ]
- @staticmethod
- def resolve_last_change(obj):
- if obj.last_change:
- return obj.last_change.isoformat().replace("+00:00", "Z")
- @staticmethod
- def resolve_heartbeat_endpoint(obj):
- if obj.endpoint_id:
- return settings.GLITCHTIP_URL.geturl() + reverse(
- "api:heartbeat_check",
- kwargs={
- "organization_slug": obj.organization.slug,
- "endpoint_id": obj.endpoint_id,
- },
- )
- class MonitorDetailSchema(MonitorSchema):
- checks: list[MonitorCheckResponseTimeSchema]
- class StatusPageIn(CamelSchema, ModelSchema):
- is_public: bool = False
- class Meta:
- model = StatusPage
- fields = ["name", "is_public"]
- class StatusPageSchema(StatusPageIn, ModelSchema):
- monitors: list[MonitorSchema]
- class Meta(StatusPageIn.Meta):
- fields = ["name", "slug", "is_public"]
|