Skip to content

feat(dashboard): cluster overview on the redesign (rebase of #255) - #261

Merged
Matheus-Thurler merged 6 commits into
mainfrom
feat/cluster-overview-on-redesign
Oct 16, 2026
Merged

Matheus-Thurler merged 6 commits into
mainfrom
feat/cluster-overview-on-redesign

Conversation

@Matheus-Thurler

Copy link
Copy Markdown
Contributor

Summary

Test plan

  • go build ./... && go test ./...
  • npm run build e npm test (27 testes)
  • Screenshots do dashboard em claro/escuro, PT/EN (demo)
  • Teste no lab com metrics-server instalado

wesleip and others added 5 commits October 16, 2026 10:06
Extend GET /api/v1/dashboard/summary with three new additive fields
that surface platform-wide telemetry for the operator:

  - hosts:    node count, ready nodes, allocatable CPU and memory
              (millicores / bytes), distinct kubelet versions, OS images
              and architectures. Sourced from core/v1/nodes via
              KubeVirtDriver.ClusterMetrics.
  - hosts.usage: real CPU and memory consumption aggregated from
              metrics.k8s.io/v1beta1/nodes (Tier 2 — requires
              metrics-server, documented prerequisite in helm-charts).
              Served with a 30s in-memory cache, and degrades gracefully
              when the API is absent, Forbidden, or transiently
              unavailable.
  - storage:  tenant-scoped PVC capacity and consumption (Bound vs
              reserved) plus the count. Sourced from the existing PVC
              list path in KubeVirtDriver.
  - addons:   cluster-wide health of critical dependencies
              (KubeVirt, CDI, Multus, metrics-server, networking, and
              any chart that follows the Helm label conventions),
              discovered dynamically from CustomResourceDefinitions
              with the 'app.kubernetes.io/name' label and a small alias
              table for the well-known API groups. Each entry reports
              'ok' (Established) or 'degraded'.

All four reads are fail-soft: 404, 403, 401, 503, timeouts, and
connection-refused return (nil, nil) so the endpoint never 500s.
Memory mode and nil client leave the fields empty.

docs/rbac-contract.yaml documents the dynamic-client access to
metrics.k8s.io in a new dynamicClient section — rbac_contract_test
keeps passing because the typed client AST scan does not see
Discovery().RESTClient().

PlatformService gains a kv field so the service can read the
hypervisor. CHANGELOG entry under Unreleased. A new
2026-10-08-dashboard-host-metrics.md captures the design and the
locked decisions for this slice.
Surface the new hosts/storage/addons fields from the previous slice
on the existing Dashboard page:

  - Rename the section title from 'Cluster nodes' to 'Cluster
    overview' to fit the broader scope (nodes + capacity + addons).
  - Four cards inside the section: Nodes, Ready nodes, Allocatable
    CPU, Allocatable memory. The CPU/memory cards now carry a
    usage bar (used / allocatable) and a percent line, with a
    colour ramp on 60% / 85% thresholds. A small 'Todos prontos' /
    'N degraded' / 'None ready' badge sits next to the Ready
    nodes count.
  - The four cards share a common baseline via h-full + flex-1 so
    the percent and the bars line up at the bottom regardless of
    how much content the other cards carry.
  - A new 'Storage' card replaces the redundant 'Networks' tile in
    the stats row, formatted with auto-scaled units (B / KiB / MiB
    / GiB / TiB) and a percent line.
  - A 'Cluster addons' strip below the Kubelet / OS / Arch footer
    renders one dot per critical dependency, green and pulsing
    when Established, an outlined ring when absent, yellow and
    pulsing when unreachable. The list is discovered dynamically
    by the backend — only addons actually present on the cluster
    are shown.
  - The dashboard query polls every 10s when /ws/events is up and
    5s when it is down, so the usage bars and the addons strip
    stay current without a manual refresh. The existing
    realtime-invalidation path still drives VM transitions.

The polling is on a fixed schedule rather than the previous
'health == ok' gate because the underlying data sources
(metrics.k8s.io, the addon probe) have no /ws/events counterpart.

i18n: PT and EN parity for every new key, asserted by i18n.test.ts.
typecheck: tsc --noEmit reports 0 errors new to this commit (the
'isFetching' unused warning is pre-existing).
The dashboard Cluster overview (node counts, capacity, addons) is
platform-wide telemetry, not tenant-scoped. Hide it from any actor
whose role is not 'root'.

Two layers:

  1. service.DashboardSummary now takes a role argument. When the
     role is anything other than platform.RoleRoot, the service
     skips populateHosts, populateStorage and populateAddons; the
     JSON response carries no 'hosts', 'storage' or 'addons' field,
     so nothing leaks through the Network tab or other consumers.
  2. The Dashboard React component gates the entire <SurfaceCard>
     with selectIsRoot, so non-root never even renders the card.

Tenant admins and tenant users still see the rest of the dashboard:
volume / VPC / SG / network counts, recent activity, the VM
running% badge, and the health card. Only the platform-wide
telemetry is gone.

The handler passes actor.Role (empty string when unauthenticated,
which is also not root). Two new tests
(TestDashboardSummaryHidesClusterOverviewForNonRoot and
TestDashboardSummaryShowsClusterOverviewForRoot) lock the
behaviour; the existing hosts/storage/addons tests now pass
platform.RoleRoot explicitly so they keep exercising the populated
path.
- populateHosts: cluster usage is optional — an unexpected ClusterUsage
  error is logged and leaves hosts.usage nil instead of failing the
  whole dashboard summary (500) for root.
- fetchClusterUsage: parse node quantities with resource.ParseQuantity
  and skip the item on error; resource.MustParse could panic on a
  malformed metrics.k8s.io payload.
- probeAddons: bound the CRD list with a 4s timeout (same bound as the
  usage call) and request a PartialObjectMetadataList so only names and
  labels cross the wire, not full OpenAPI schemas. The API group is
  derived from the CRD object name (<plural>.<group>); Established is
  not part of ObjectMeta, so a discovered addon is now ok by presence.
  The apiextensions.k8s.io/customresourcedefinitions get/list grant is
  listed under dynamicClient in docs/rbac-contract.yaml.
- StorageSummary: rename used_bytes to bound_bytes and reword the UI
  label to "allocated" — the figures are spec.requests sums, i.e.
  allocated capacity, not real guest consumption.
- WithNamespace: build a fresh driver instead of copying the struct —
  the copy cloned the new cache mutexes (go vet copylocks) while
  sharing the cache entries.

Chart grants land in virtfoundry/helm-charts#141 (rules first).
Render the overview with StatsCard/StatusBadge/SurfaceCard and add demo fixtures for hosts, storage and addons.
@Matheus-Thurler
Matheus-Thurler merged commit 788e26c into main Oct 16, 2026
8 checks passed
@Matheus-Thurler
Matheus-Thurler deleted the feat/cluster-overview-on-redesign branch October 16, 2026 18:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants