diff --git a/src/servala/core/models/service.py b/src/servala/core/models/service.py index c6552c4..e973235 100644 --- a/src/servala/core/models/service.py +++ b/src/servala/core/models/service.py @@ -1152,5 +1152,50 @@ class ServiceInstance(ServalaModelMixin, models.Model): except (AttributeError, KeyError, IndexError): return None + @cached_property + def kubernetes_events(self) -> dict: + """ + Returns a list of event dictionaries sorted by last timestamp (newest first). + """ + if not self.kubernetes_object: + return [] + + try: + v1 = kubernetes.client.CoreV1Api( + self.context.control_plane.get_kubernetes_client() + ) + events = v1.list_namespaced_event( + namespace=self.organization.namespace, + field_selector=f"involvedObject.name={self.name},involvedObject.kind={self.context.kind}", + ) + event_list = [] + for event in events.items: + event_dict = { + "type": event.type, # Normal or Warning + "reason": event.reason, + "message": event.message, + "count": event.count or 1, + "first_timestamp": ( + event.first_timestamp.isoformat() + if event.first_timestamp + else None + ), + "last_timestamp": ( + event.last_timestamp.isoformat() + if event.last_timestamp + else None + ), + "source": event.source.component if event.source else None, + } + event_list.append(event_dict) + + event_list.sort(key=lambda x: x.get("last_timestamp") or "", reverse=True) + + return event_list + except ApiException: + return [] + except Exception: + return [] + auditlog.register(ServiceInstance, exclude_fields=["updated_at"], serialize_data=True) diff --git a/src/servala/frontend/templates/frontend/base.html b/src/servala/frontend/templates/frontend/base.html index 620cb6d..8454e0d 100644 --- a/src/servala/frontend/templates/frontend/base.html +++ b/src/servala/frontend/templates/frontend/base.html @@ -35,6 +35,8 @@ {% block page_title_extra %} {% endblock page_title_extra %} + {% block page_subtitle %} + {% endblock page_subtitle %}
{{ instance.context.service_definition.service.name }} - -
| {% translate "Type" %} | -{% translate "Status" %} | -{% translate "Last Transition Time" %} | -{% translate "Reason" %} | -{% translate "Message" %} | -
|---|
| {% translate "Name" %} | +{% translate "Value" %} | ++ | |||||
|---|---|---|---|---|---|---|---|
| {{ condition.type }} | -- {% if condition.status == "True" %} - True - {% elif condition.status == "False" %} - False + | {{ key }} | +
+ {% if key == "error" %}
+ {{ value }}
{% else %}
- {{ condition.status }}
+ ••••••••••••
+ {% endif %}
+ |
+ + {% if key != "error" %} + {% endif %} | -{{ condition.lastTransitionTime|date:"SHORT_DATETIME_FORMAT" }} | -{{ condition.reason|default:"-" }} | -{{ condition.message|truncatewords:20|default:"-" }} |
{% translate "Technical details for connecting to this zone" %}
+{{ field.value|pprint }}
- {% else %}
- {{ field.value|default:"-" }}
+ {{ field.value|pprint }}
- {% else %}
- {{ field.value|default:"-" }}
- {% endif %}
+ {% translate "No specification details to display." %}
{% endfor %}| {% translate "Type" %} | +{% translate "Status" %} | +{% translate "Last Transition" %} | +{% translate "Reason" %} | +{% translate "Message" %} | +
|---|---|---|---|---|
| {{ condition.type }} | ++ {% if condition.status == "True" %} + True + {% elif condition.status == "False" %} + False + {% else %} + {{ condition.status }} + {% endif %} + | +{{ condition.lastTransitionTime|localtime_tag }} | +{{ condition.reason|default:"-" }} | +{{ condition.message|truncatewords:20|default:"-" }} | +
| {% translate "Name" %} | -{% translate "Value" %} | -
|---|---|
| {{ key }} | -
- {% if key == "error" %}
- {{ value }}
- {% else %}
- {{ value }}
- {% endif %}
- |
-