feat: v4 multi-cloud estate, global omni-search, and topology UX refinements - #206
feat: v4 multi-cloud estate, global omni-search, and topology UX refinements#206JLCode-tech wants to merge 51 commits into
Conversation
9f75326 to
42ee999
Compare
…core Self-review findings on feat/v4-multi-cloud-ux-enhancements (tractable minors + a real coverage gap; no blockers). MINOR 1 — llm_observability_service.stats fleet branch: per-cluster `models` is already a COUNT of distinct models, so max() silently understated the fleet whenever clusters ran disjoint model sets. Switch to sum() as an upper bound of "models in use across the fleet" (matching the generic "Models" stat-tile), with a comment stating the true union is not computable from these inputs. Pin the semantics with a fleet `stats` test (previously untested). Coverage gap — routes/k8s/search._scan_cluster_for_query (the ~260-line live-scan core) was FULLY MOCKED in both integration tests. Add unit tests that mock the k8s client RESPONSES (not the scan function) and exercise Ingress/HTTPRoute/VirtualServer/Egress/Gateway/Service parsing, LB-IP harvesting, CRD-absent tolerance, and the ThreadPoolExecutor timeout harvest (partial results, no hang) + cross-cluster dedup. Add a request-based negative-authZ test asserting the route requires require_viewer (was only asserted by inspection). Did NOT touch credentials_service.py (reconciled with #208 at merge). Claude-Session: https://claude.ai/code/session_01UCsZXDxBsWV2s4kT47DwDW
Self-review (cold, adversarial) + fixes appliedIndependent cold audit of the highest-risk surfaces. No blockers. The top-flagged risk — an omni-search cross-tenant leak — was investigated and refuted: Findings (minor) — fixed @
Merge-coordination note: the credential-fallback + dead-Azure-resolver findings in Verified: 41 target tests pass, ruff clean, |
Review —
|
- Convert AWS/IBM region validators from hardcoded-list rejection to pattern-based acceptance so new or private regions are selectable. - Add Azure and GCP region validators using the same pattern-based approach; wire them into project, credential-template, and cluster schemas/routes. - Update frontend region selectors (AWS, Cloud, SystemDefaults) to free-form inputs with datalist suggestions instead of restrictive dropdowns. - Add KubernetesCluster.account_id and discovery_status columns plus fleet-health response fields for cloud context. - Update unit tests for validators, project schemas, k8s schemas, and frontend selectors.
…ctor - Extract shared is_operator_live_connected() helper and use it in the operator list, fleet health, and BNK health context. - Reuse services.scanner.nodes.parse_node() in BNK fetch instead of duplicating the zone/instance-type label fallback logic. - Add an optional label prop to CloudRegionSelector and reuse it in SystemDefaults to remove four near-identical region input blocks.
- Add connectivity and integration sections to BnkHealthResponse. - Reuse the cluster's persisted status for connectivity and the shared operator live-connection helper for integration. - Display ConnectivityBadge and IntegrationBadge in the dashboard banner. - Add backend unit tests and frontend dashboard tests for the new fields.
Add /detect-credentials endpoint that discovers existing Kubernetes clusters from a project's credential template for AWS, IBM Cloud, Azure, and GCP. Each provider lists accessible clusters, builds a kubeconfig from the template credentials, and registers the cluster in BNK-Forge. - New ClusterDiscoveryService orchestrates detection and registration. - Provider helpers: EKS, ROKS, AKS, GKE. - Frontend auto-detect switched to api.detectClustersFromCredentials(). - Backend + frontend tests updated; openapi.json and api-generated.ts regenerated.
- Move BNK Resources tab from System page to Fleet page - Make GET /api/system/bnk-consumption viewer-accessible - Move MCP Server from standalone sidebar page to System page tab - Move Benchmarks sidebar item from OPERATE to OBSERVE section - Update affected tests and regenerate OpenAPI types
- Add services/bnk/traffic_stats.py with analyze_traffic_stats() and fetch_tmm_traffic_stats() wrapping existing TMM debug helpers. - Add Pydantic schemas for listener/egress/firewall-rule traffic stats. - Wire trafficStats into the unified /f5bnk/data response. - Surface hit/connection badges on F5BNKTopologyViewer listener/egress nodes. - Add hits column to F5BNKPolicyViewer firewall-rule tables. - Add total-connections summary chips in TrafficFlowOverview. - Regenerate openapi.json and TypeScript generated types. - Add backend unit tests and frontend component/hook tests.
- Enrich BNK topology with gateway/listener/route accepted/programmed conditions - Add policy resolved/programmed status to topology and policy associations - Add response models for gateway topology and policy associations endpoints - Surface inline status badges in topology, traffic flow, and policy views - Visualize cross-namespace ReferenceGrants in topology and traffic flow - Extract shared ConditionsList component for Gateway/HTTPRoute/Service details - Add lightweight Service detail fallback and register it in resource registry - Regenerate OpenAPI spec and TypeScript generated types
…urce with settings Module Library sync failed for official-bnk-forge-modules because the clone used source.branch and then tried git checkout <git_ref>. A shallow branch clone does not fetch tags, so checking out a tag ref (v2.2.0) failed with 'pathspec did not match any file(s) known to git'. Use source.git_ref (falling back to branch) directly in git clone --branch, which accepts branch and tag names and already checks out the requested ref. Also reconcile the canonical official module source with the current module_library.git_* settings before a direct source sync, so a stale branch/git_ref on the source row does not override the configured ref. Validated: /api/module-sources/3/sync now succeeds, discovers 24 pack modules, and updates the source row to branch=git_ref=release/2.2.
…figview probes when no VS rows
…d CNE available state - Update has_condition() and get_condition_message() to inspect direct conditions arrays on parent_status dicts as well as standard K8s status.conditions. - Add get_policy_operational_status() to evaluate status.ancestors and status.descendants condition refs for BNKNetPolicy and BNKSecPolicy in BNK 2.3. - Update _build_cne_instance() to recognize Available/Reconciled condition states and populate default phase when healthy. - Update _match_routes_to_listener() to check parent_status condition acceptance.
Stop per-request ThreadPoolExecutors from spawning 20 workers each, which exploded backend PID count to 100+ under concurrent BNK page loads. Use module-level shared executors with small caps for BNK CRD fetches and TMM configview probes. Add Redis-backed short-term caches for: - EKS/GCP bearer tokens (10 min TTL) - fetch_all_bnk_data results (30 s TTL) - TMM traffic stats + configview uuid mappings (30 s / 5 min TTL) - CWC license status (30 s) and report (60 s) Each cache supports force=true to bypass when the UI explicitly refreshes. License activation invalidates the cached status/report so the new state is reflected immediately.
Add account_id, discovery_status, connectivity_status, integration_status,
zones, access_method, and node_count to the KubernetesCluster model, cluster
response schemas, serializers, and detail endpoints. Populate account_id from
credential-template discovery paths (AWS account, Azure subscription, GCP
project) and persist version/node_count/zones/last_synced_at from the scanner.
Includes migration v2_157 and a new GET /api/projects/{project_id}/connectivity
route backed by probe_project_clusters.
…uster The _build_bnk_context helper added in the health refactor queries ConnectedOperator by cluster.id. Tests that patched KubernetesService returned a MagicMock cluster, causing a SQLite bind error. Configure the mock to return the real test cluster so the endpoint can build its connectivity/integration context.
…se endpoints; fix project-switch refresh
…zure api_server (M3)
M1 (coverage gap): the discovered-cluster kubeconfig is encrypted at rest via
encrypt_value(), but no test asserted it — a mutation to plaintext passed all 8
tests. Add test_persisted_kubeconfig_is_encrypted_at_rest, which reads the
persisted kubeconfig_encrypted column and asserts it is NOT plaintext
(no "apiVersion" in the stored value; stored != decrypt_value(stored)) yet
decrypts back to the real kubeconfig. Reverting encrypt_value to plaintext reds
this test (decrypt raises / stored equals its plaintext).
M3 (defensive): _detect_azure_clusters composed api_server as
f"https://{creds['server']}:443", which double-prefixes into a malformed URL if
creds['server'] ever carries a scheme or an explicit port. Add
_normalize_api_server_host() to strip a leading http(s):// scheme and a trailing
:port so a bare host, scheme-prefixed host, or host:port all yield one correct
https://host:443, with a 3-shape parametrized test.
Scoped to M1 + M3; region validators (M2) untouched. No API/model change.
Claude-Session: https://claude.ai/code/session_01UCsZXDxBsWV2s4kT47DwDW
…edential templates
…gn alembic docstring
…O routes, doc SSO/terraform split F1: normalize naive azure_sso_token_expiry to UTC before comparing in _test_azure_template — matches get_sso_status / credential_refresh_service guards; fixes TypeError on SQLite/dev naive round-trip. Adds SQLite regression test (mutation-verified: fails with the exact TypeError without the guard). F2: remove the unwired standalone Azure SSO routes (/azure/sso/initiate, /azure/sso/poll, /azure/subscriptions), their request models, and the unused client methods (initiateAzureSSO/pollAzureSSO/listAzureSubscriptions). The frontend uses the server-side template flow (authenticate-sso/poll-sso, returns only has_credentials); these paths leaked long-lived access/refresh tokens in the response body. Regenerated openapi.json + api-generated.ts. F4: document at the terraform credential-injection site that SSO Azure templates deliberately inject no credential (SSO is validation/console; terraform provisioning uses the service-principal secret). Claude-Session: https://claude.ai/code/session_01UCsZXDxBsWV2s4kT47DwDW
- Rebase onto work/v4-localhost (incorporating staging and #205) - Renumber Alembic migration to v2_158 with down_revision v2_157 - Restrict azure_auth_method typing with Literal["service_principal", "sso"] - Persist refreshed Azure SSO tokens on test connection by committing DB session - Ensure SSO action menu and config completeness checks gate strictly on azure_auth_method == 'sso' - Add regression component tests for refresh token DB persistence and config validation
…topology views - Add global Omni-Search endpoint (/api/v1/k8s/search) with client hook and Hero search bar on Dashboard - Add MultiCloudEstate overview card with provider breakdowns and interactive filtering - Streamline F5 BNK page to direct vertical topology views (Object Topology, Traffic Flow Pipeline, Policy Matrix) - Consolidate CRD exploration into a unified Kubernetes Explorer Hub and streamline CNF infrastructure view - Polish Benchmarks page setup headers and remove redundant stepper progress banner - Clean up Fleet Management provider filter chips and guidance - Optimize LLM Observability filters and debounce hooks with full test coverage
…de log aggregation
…licate filter logic
…core Self-review findings on feat/v4-multi-cloud-ux-enhancements (tractable minors + a real coverage gap; no blockers). MINOR 1 — llm_observability_service.stats fleet branch: per-cluster `models` is already a COUNT of distinct models, so max() silently understated the fleet whenever clusters ran disjoint model sets. Switch to sum() as an upper bound of "models in use across the fleet" (matching the generic "Models" stat-tile), with a comment stating the true union is not computable from these inputs. Pin the semantics with a fleet `stats` test (previously untested). Coverage gap — routes/k8s/search._scan_cluster_for_query (the ~260-line live-scan core) was FULLY MOCKED in both integration tests. Add unit tests that mock the k8s client RESPONSES (not the scan function) and exercise Ingress/HTTPRoute/VirtualServer/Egress/Gateway/Service parsing, LB-IP harvesting, CRD-absent tolerance, and the ThreadPoolExecutor timeout harvest (partial results, no hang) + cross-cluster dedup. Add a request-based negative-authZ test asserting the route requires require_viewer (was only asserted by inspection). Did NOT touch credentials_service.py (reconciled with #208 at merge). Claude-Session: https://claude.ai/code/session_01UCsZXDxBsWV2s4kT47DwDW
3cccc07 to
7294fe9
Compare
Re-Review Requested: All Review Feedback Addressed & Rebased onto #207We have rebased
@bonnyr-f5 — ready for final re-review! |
Summary
This pull request brings together multi-cloud Azure / GCP / AWS cluster and auth support, global Omni-Search, unified CRD exploration, direct F5 BNK topology views, multi-cluster LLM Observability analytics, and UX polish across the v4 platform.
Key Highlights
1. Multi-Cloud & Hybrid Estate
2. Global Omni-Search
/api/v1/k8s/search) scanning clusters, projects, stacks, blueprints, and workloads.HeroOmniSearchwith keyboard shortcuts (Cmd+K/Ctrl+K), type categorizations, and instant deep links.3. LLM Observability & Multi-Cluster AI Gateway
4. F5 BNK Topology & Diagnostics Polish
5. CNF & Kubernetes CRD Hub Consolidation
K8sCrdExplorerPanelon the Kubernetes page.6. Fleet & Benchmarks Polish
Verification
LlmDashboard.test.tsxandLlmLogs.test.tsx).test_llm_observability_service.pyand routes).