docs: remove incorrect watchPlugins: false references
Remove all references to the incorrect `config.watchPlugins: false` requirement that was believed necessary for Headlamp v0.39.0+. Investigation revealed that plugins work correctly with the default `watchPlugins: true` setting. The earlier documentation was based on a misunderstanding of the plugin loading mechanism. Changes: - Remove watchPlugins: false from all YAML configuration examples - Remove warning sections about watchPlugins requirement - Update troubleshooting guides to focus on actual issues - Simplify installation instructions by removing unnecessary config Files updated: - README.md (main installation docs and troubleshooting table) - docs/DEPLOYMENT.md - docs/TROUBLESHOOTING.md - docs/getting-started/* (quick-start, installation, prerequisites) - docs/deployment/* (helm, production) - docs/troubleshooting/* (common-issues, README) - Multiple other doc files formatted by prettier This cleanup ensures ArtifactHub and GitHub documentation show correct, simplified installation instructions. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
## Context
|
||||
|
||||
The Headlamp Polaris Plugin needs to fetch Polaris audit data once and share it across multiple components:
|
||||
|
||||
- Dashboard view (cluster overview)
|
||||
- Namespaces list view
|
||||
- Namespace detail view (drawer)
|
||||
@@ -16,12 +17,14 @@ The Headlamp Polaris Plugin needs to fetch Polaris audit data once and share it
|
||||
Multiple state management approaches are available: Redux, Zustand, Jotai, Recoil, React Context (built-in), or component props with prop drilling.
|
||||
|
||||
**Constraints:**
|
||||
|
||||
- Headlamp plugin environment does not allow adding external dependencies (peer dependencies only)
|
||||
- Redux, Zustand, Jotai, Recoil are not available in the plugin runtime
|
||||
- Plugin must work with Headlamp's existing React context (React 17+)
|
||||
- Bundle size should remain small (<50 KB)
|
||||
|
||||
**Requirements:**
|
||||
|
||||
- Share `AuditData` object across all views without duplicate API calls
|
||||
- Support auto-refresh on user-configurable interval (1-30 minutes)
|
||||
- Handle loading and error states consistently
|
||||
@@ -32,6 +35,7 @@ Multiple state management approaches are available: Redux, Zustand, Jotai, Recoi
|
||||
Use **React Context API** (built-in, no dependencies) for shared state management.
|
||||
|
||||
**Implementation:**
|
||||
|
||||
- `PolarisDataProvider` wraps all plugin routes
|
||||
- `usePolarisDataContext()` hook provides `{ data, loading, error, refresh }` to consumers
|
||||
- Single fetch shared across all views
|
||||
@@ -67,12 +71,14 @@ Use **React Context API** (built-in, no dependencies) for shared state managemen
|
||||
### Option 1: Redux
|
||||
|
||||
**Pros:**
|
||||
|
||||
- Powerful state management with middleware
|
||||
- Excellent DevTools for debugging
|
||||
- Time-travel debugging
|
||||
- Well-established patterns
|
||||
|
||||
**Cons:**
|
||||
|
||||
- Redux is not available as a peer dependency in Headlamp plugins
|
||||
- Massive overkill for single AuditData object
|
||||
- Adds significant bundle size (~10-15 KB)
|
||||
@@ -83,11 +89,13 @@ Use **React Context API** (built-in, no dependencies) for shared state managemen
|
||||
### Option 2: Zustand
|
||||
|
||||
**Pros:**
|
||||
|
||||
- Lightweight (~1 KB)
|
||||
- Simple API similar to `useState`
|
||||
- No provider boilerplate
|
||||
|
||||
**Cons:**
|
||||
|
||||
- External peer dependency (not available in plugin runtime)
|
||||
- Still adds bundle size
|
||||
- Unnecessary for read-only state
|
||||
@@ -97,11 +105,13 @@ Use **React Context API** (built-in, no dependencies) for shared state managemen
|
||||
### Option 3: Component Props (Prop Drilling)
|
||||
|
||||
**Pros:**
|
||||
|
||||
- No dependencies
|
||||
- Explicit data flow
|
||||
- TypeScript tracks prop types
|
||||
|
||||
**Cons:**
|
||||
|
||||
- Prop drilling through 5+ component layers (index.tsx → route → view → subcomponent)
|
||||
- Duplicate fetches if not carefully managed
|
||||
- Refactoring nightmare if component tree changes
|
||||
@@ -112,10 +122,12 @@ Use **React Context API** (built-in, no dependencies) for shared state managemen
|
||||
### Option 4: Global Variable / Module State
|
||||
|
||||
**Pros:**
|
||||
|
||||
- Simple to implement
|
||||
- No React dependencies
|
||||
|
||||
**Cons:**
|
||||
|
||||
- No reactivity (components don't re-render on data change)
|
||||
- No built-in loading/error handling
|
||||
- Breaks React's declarative model
|
||||
@@ -126,6 +138,7 @@ Use **React Context API** (built-in, no dependencies) for shared state managemen
|
||||
## Implementation Details
|
||||
|
||||
**Context Definition:**
|
||||
|
||||
```typescript
|
||||
interface PolarisDataContextValue {
|
||||
data: AuditData | null;
|
||||
@@ -138,6 +151,7 @@ const PolarisDataContext = React.createContext<PolarisDataContextValue | undefin
|
||||
```
|
||||
|
||||
**Provider Implementation:**
|
||||
|
||||
```typescript
|
||||
export function PolarisDataProvider({ children }: { children: React.ReactNode }) {
|
||||
const [data, setData] = useState<AuditData | null>(null);
|
||||
@@ -163,6 +177,7 @@ export function PolarisDataProvider({ children }: { children: React.ReactNode })
|
||||
```
|
||||
|
||||
**Consumer Hook:**
|
||||
|
||||
```typescript
|
||||
export function usePolarisDataContext() {
|
||||
const context = useContext(PolarisDataContext);
|
||||
@@ -176,6 +191,7 @@ export function usePolarisDataContext() {
|
||||
## Validation Criteria
|
||||
|
||||
**Success Metrics:**
|
||||
|
||||
- ✅ All views share single fetch (verified via network tab - one request per refresh)
|
||||
- ✅ No duplicate API calls (verified via Kubernetes audit logs)
|
||||
- ✅ Auto-refresh works correctly (5-30 minute intervals)
|
||||
@@ -184,6 +200,7 @@ export function usePolarisDataContext() {
|
||||
- ✅ Bundle size remains <50 KB (currently ~27 KB)
|
||||
|
||||
**Tested Scenarios:**
|
||||
|
||||
- ✅ Initial load with loading spinner
|
||||
- ✅ Error handling (403, 404, network errors)
|
||||
- ✅ Manual refresh via button
|
||||
@@ -200,6 +217,6 @@ export function usePolarisDataContext() {
|
||||
|
||||
## Revision History
|
||||
|
||||
| Date | Author | Change |
|
||||
|------|--------|--------|
|
||||
| Date | Author | Change |
|
||||
| ---------- | ----------- | ---------------- |
|
||||
| 2026-02-12 | Plugin Team | Initial decision |
|
||||
|
||||
@@ -41,17 +41,21 @@ What is the change that we're proposing and/or doing?
|
||||
What becomes easier or more difficult to do because of this change?
|
||||
|
||||
### Positive
|
||||
|
||||
- ...
|
||||
|
||||
### Negative
|
||||
|
||||
- ...
|
||||
|
||||
### Neutral
|
||||
|
||||
- ...
|
||||
|
||||
## Alternatives Considered
|
||||
|
||||
### Option 1: Name
|
||||
|
||||
**Pros**: ...
|
||||
**Cons**: ...
|
||||
**Decision**: Not chosen because...
|
||||
@@ -63,8 +67,8 @@ What becomes easier or more difficult to do because of this change?
|
||||
|
||||
## ADR Index
|
||||
|
||||
| ADR | Title | Status | Date |
|
||||
|-----|-------|--------|------|
|
||||
| ADR | Title | Status | Date |
|
||||
| ------------------------------------- | -------------------------------------- | -------- | ---------- |
|
||||
| [001](001-react-context-for-state.md) | Use React Context for State Management | Accepted | 2026-02-12 |
|
||||
|
||||
**Note:** Additional ADRs documenting other significant decisions (service proxy approach, drawer navigation, MUI import restrictions) can be created following the template above.
|
||||
|
||||
@@ -212,46 +212,46 @@ If no match found:
|
||||
|
||||
```typescript
|
||||
interface AuditData {
|
||||
PolarisOutputVersion: string; // "1.0"
|
||||
AuditTime: string; // ISO 8601 timestamp
|
||||
SourceType: string; // "Cluster"
|
||||
SourceName: string; // Cluster identifier
|
||||
DisplayName: string; // Human-readable name
|
||||
PolarisOutputVersion: string; // "1.0"
|
||||
AuditTime: string; // ISO 8601 timestamp
|
||||
SourceType: string; // "Cluster"
|
||||
SourceName: string; // Cluster identifier
|
||||
DisplayName: string; // Human-readable name
|
||||
ClusterInfo: {
|
||||
Version: string; // K8s version
|
||||
Version: string; // K8s version
|
||||
Nodes: number;
|
||||
Pods: number;
|
||||
Namespaces: number;
|
||||
Controllers: number;
|
||||
};
|
||||
Results: Result[]; // Array of resource audit results
|
||||
Results: Result[]; // Array of resource audit results
|
||||
}
|
||||
|
||||
interface Result {
|
||||
Name: string; // Resource name
|
||||
Namespace: string; // Kubernetes namespace
|
||||
Kind: string; // "Deployment", "StatefulSet", etc.
|
||||
Results: ResultSet; // Resource-level checks
|
||||
Name: string; // Resource name
|
||||
Namespace: string; // Kubernetes namespace
|
||||
Kind: string; // "Deployment", "StatefulSet", etc.
|
||||
Results: ResultSet; // Resource-level checks
|
||||
PodResult?: {
|
||||
Name: string;
|
||||
Results: ResultSet; // Pod-level checks
|
||||
Results: ResultSet; // Pod-level checks
|
||||
ContainerResults: {
|
||||
Name: string;
|
||||
Results: ResultSet; // Container-level checks
|
||||
Results: ResultSet; // Container-level checks
|
||||
}[];
|
||||
};
|
||||
CreatedTime: string; // ISO 8601 timestamp
|
||||
CreatedTime: string; // ISO 8601 timestamp
|
||||
}
|
||||
|
||||
type ResultSet = Record<string, ResultMessage>;
|
||||
|
||||
interface ResultMessage {
|
||||
ID: string; // Check ID (e.g., "cpuLimitsMissing")
|
||||
Message: string; // Human-readable message
|
||||
Details: string[]; // Additional context
|
||||
Success: boolean; // true = passed, false = failed
|
||||
Severity: "ignore" | "warning" | "danger";
|
||||
Category: string; // "Security", "Efficiency", etc.
|
||||
ID: string; // Check ID (e.g., "cpuLimitsMissing")
|
||||
Message: string; // Human-readable message
|
||||
Details: string[]; // Additional context
|
||||
Success: boolean; // true = passed, false = failed
|
||||
Severity: 'ignore' | 'warning' | 'danger';
|
||||
Category: string; // "Security", "Efficiency", etc.
|
||||
}
|
||||
```
|
||||
|
||||
@@ -259,11 +259,11 @@ interface ResultMessage {
|
||||
|
||||
```typescript
|
||||
interface ResultCounts {
|
||||
total: number; // Total checks performed
|
||||
pass: number; // Checks that passed (Success: true)
|
||||
warning: number; // Failed checks with Severity: "warning"
|
||||
danger: number; // Failed checks with Severity: "danger"
|
||||
skipped: number; // Failed checks with Severity: "ignore"
|
||||
total: number; // Total checks performed
|
||||
pass: number; // Checks that passed (Success: true)
|
||||
warning: number; // Failed checks with Severity: "warning"
|
||||
danger: number; // Failed checks with Severity: "danger"
|
||||
skipped: number; // Failed checks with Severity: "ignore"
|
||||
}
|
||||
```
|
||||
|
||||
@@ -361,21 +361,25 @@ function getNamespaces(data: AuditData): string[] {
|
||||
## Caching Strategy
|
||||
|
||||
**Current Implementation:**
|
||||
|
||||
- Data fetched once and stored in React Context
|
||||
- Shared across all plugin views (no duplicate fetches)
|
||||
- Cached until manual refresh or auto-refresh interval
|
||||
|
||||
**Cache Invalidation:**
|
||||
|
||||
- Manual refresh button click
|
||||
- Auto-refresh interval elapses
|
||||
- Settings change (dashboard URL)
|
||||
|
||||
**No Persistence:**
|
||||
|
||||
- Data NOT persisted to localStorage
|
||||
- Each browser session fetches fresh data
|
||||
- No offline mode
|
||||
|
||||
**Future Enhancement:**
|
||||
|
||||
- IndexedDB caching for offline access
|
||||
- Incremental updates (fetch only changed namespaces)
|
||||
- Service Worker for background refresh
|
||||
|
||||
@@ -7,14 +7,16 @@ Key architectural choices and their rationale for the Headlamp Polaris Plugin.
|
||||
**Decision:** Use Kubernetes service proxy, not direct ClusterIP access
|
||||
|
||||
**Context:**
|
||||
|
||||
- Plugin needs to access Polaris dashboard API
|
||||
- Two options: Direct ClusterIP access or Kubernetes service proxy
|
||||
-Headlamp already has K8s API credentials
|
||||
-Headlamp already has K8s API credentials
|
||||
|
||||
**Decision:**
|
||||
Use service proxy path: `/api/v1/namespaces/polaris/services/polaris-dashboard:80/proxy/results.json`
|
||||
|
||||
**Rationale:**
|
||||
|
||||
- Headlamp already has K8s API credentials (service account or user token)
|
||||
- Service proxy leverages existing RBAC (no new credentials needed)
|
||||
- Works with Headlamp's token auth and OIDC
|
||||
@@ -22,10 +24,12 @@ Use service proxy path: `/api/v1/namespaces/polaris/services/polaris-dashboard:8
|
||||
- Consistent with Headlamp's architecture (all API calls go through K8s API)
|
||||
|
||||
**Trade-offs:**
|
||||
|
||||
- ✅ **Pros:** Simpler RBAC, works with user tokens, no new credentials
|
||||
- ❌ **Cons:** Longer URL path, requires `services/proxy` permission
|
||||
|
||||
**Alternatives Considered:**
|
||||
|
||||
- Direct ClusterIP access → Rejected (requires new credentials, network policies)
|
||||
- External Polaris URL → Supported as optional feature (custom URL setting)
|
||||
|
||||
@@ -34,6 +38,7 @@ Use service proxy path: `/api/v1/namespaces/polaris/services/polaris-dashboard:8
|
||||
**Decision:** Use React Context for state management
|
||||
|
||||
**Context:**
|
||||
|
||||
- Plugin needs to share Polaris audit data across multiple views
|
||||
- Options: React Context, Redux, Zustand, or component props
|
||||
|
||||
@@ -41,16 +46,19 @@ Use service proxy path: `/api/v1/namespaces/polaris/services/polaris-dashboard:8
|
||||
Use React Context with `PolarisDataProvider`
|
||||
|
||||
**Rationale:**
|
||||
|
||||
1. **Simple state:** Single AuditData object, no complex mutations
|
||||
2. **Read-only:** No transactions, undo/redo, or optimistic updates
|
||||
3. **Headlamp constraints:** Cannot add external dependencies (Redux not bundled)
|
||||
4. **Performance:** Data changes infrequently (5-30 minute refresh interval)
|
||||
|
||||
**Trade-offs:**
|
||||
|
||||
- ✅ **Pros:** No dependencies, simple API, built-in React feature
|
||||
- ❌ **Cons:** All consumers re-render on data change (acceptable for infrequent updates)
|
||||
|
||||
**Alternatives Considered:**
|
||||
|
||||
- Redux → Rejected (not available in plugin environment)
|
||||
- Zustand → Rejected (requires external dependency)
|
||||
- Component props → Rejected (prop drilling, duplicate fetches)
|
||||
@@ -60,6 +68,7 @@ Use React Context with `PolarisDataProvider`
|
||||
**Decision:** Use drawer for namespace detail, not dedicated route
|
||||
|
||||
**Context:**
|
||||
|
||||
- Namespaces list needs drill-down to per-namespace detail
|
||||
- Options: Dedicated route (`/polaris/ns/:namespace`) or drawer overlay
|
||||
|
||||
@@ -67,16 +76,19 @@ Use React Context with `PolarisDataProvider`
|
||||
Use drawer with URL hash (`/polaris/namespaces#kube-system`)
|
||||
|
||||
**Rationale:**
|
||||
|
||||
- **Better UX:** Drawer overlays table, preserves scroll position and context
|
||||
- **URL hash:** Preserves navigation state, supports browser back/forward
|
||||
- **Keyboard shortcuts:** Escape key to close drawer
|
||||
- **Sidebar limitation:** Headlamp sidebar doesn't support 3-level nesting
|
||||
|
||||
**Trade-offs:**
|
||||
|
||||
- ✅ **Pros:** Better UX, preserves context, keyboard navigation
|
||||
- ❌ **Cons:** Hash-based routing (not "true" route), drawer accessibility considerations
|
||||
|
||||
**Alternatives Considered:**
|
||||
|
||||
- Dedicated route → Rejected (loses table context, requires back navigation)
|
||||
- Modal → Rejected (less natural for drill-down, no URL state)
|
||||
|
||||
@@ -85,6 +97,7 @@ Use drawer with URL hash (`/polaris/namespaces#kube-system`)
|
||||
**Decision:** Never import from `@mui/material` or `@mui/icons-material`
|
||||
|
||||
**Context:**
|
||||
|
||||
- Plugin needs UI components (buttons, icons, etc.)
|
||||
- Headlamp uses MUI but doesn't expose full library to plugins
|
||||
|
||||
@@ -92,20 +105,24 @@ Use drawer with URL hash (`/polaris/namespaces#kube-system`)
|
||||
Use only Headlamp CommonComponents or HTML elements with inline styles
|
||||
|
||||
**Rationale:**
|
||||
|
||||
- Importing MUI causes `createSvgIcon undefined` runtime error
|
||||
- Headlamp plugin environment provides limited MUI exports
|
||||
- CommonComponents cover 90% of use cases
|
||||
|
||||
**Implementation:**
|
||||
|
||||
- Use `StatusLabel`, `SectionBox`, `SimpleTable` from CommonComponents
|
||||
- Use standard HTML elements (`<button>`, `<div>`) with inline styles
|
||||
- Use theme-aware CSS variables (`--mui-palette-background-paper`)
|
||||
|
||||
**Trade-offs:**
|
||||
|
||||
- ✅ **Pros:** No runtime errors, smaller bundle, consistent with Headlamp
|
||||
- ❌ **Cons:** Limited component variety, inline styles verbose
|
||||
|
||||
**Alternatives Considered:**
|
||||
|
||||
- Bundle full MUI → Rejected (huge bundle size, version conflicts)
|
||||
- Use Headlamp's MUI exports → Rejected (incomplete, undocumented)
|
||||
|
||||
@@ -114,6 +131,7 @@ Use only Headlamp CommonComponents or HTML elements with inline styles
|
||||
**Decision:** Sidebar has "Polaris" → "Overview" and "Namespaces" (2 levels max)
|
||||
|
||||
**Context:**
|
||||
|
||||
- Plugin needs hierarchical navigation
|
||||
- Headlamp sidebar supports limited nesting depth
|
||||
|
||||
@@ -121,19 +139,23 @@ Use only Headlamp CommonComponents or HTML elements with inline styles
|
||||
Use 2-level sidebar: `Polaris` (parent) → `Overview`, `Namespaces` (children)
|
||||
|
||||
**Rationale:**
|
||||
|
||||
- Headlamp sidebar `Collapse` component only supports 2 levels
|
||||
- Deeper nesting (Polaris → Namespaces → <each namespace>) doesn't work
|
||||
- Sidebar collapse is route-based, not click-to-toggle
|
||||
|
||||
**Workaround:**
|
||||
|
||||
- Namespace navigation via table (NamespacesListView)
|
||||
- Clickable namespace buttons open drawer (not new route)
|
||||
|
||||
**Trade-offs:**
|
||||
|
||||
- ✅ **Pros:** Works within Headlamp constraints
|
||||
- ❌ **Cons:** Can't have dynamic per-namespace sidebar entries
|
||||
|
||||
**Alternatives Considered:**
|
||||
|
||||
- Dynamic sidebar with namespace entries → Rejected (Headlamp limitation)
|
||||
- Flat sidebar (no nesting) → Rejected (poor UX for plugin with multiple views)
|
||||
|
||||
@@ -142,6 +164,7 @@ Use 2-level sidebar: `Polaris` (parent) → `Overview`, `Namespaces` (children)
|
||||
**Decision:** Enable all TypeScript strict checks
|
||||
|
||||
**Configuration:**
|
||||
|
||||
```json
|
||||
{
|
||||
"compilerOptions": {
|
||||
@@ -155,12 +178,14 @@ Use 2-level sidebar: `Polaris` (parent) → `Overview`, `Namespaces` (children)
|
||||
```
|
||||
|
||||
**Rationale:**
|
||||
|
||||
- Catch errors at compile time (not runtime)
|
||||
- Better IDE support and autocomplete
|
||||
- Enforces type safety (no `any`, no implicit unknowns)
|
||||
- Easier refactoring (type errors surface immediately)
|
||||
|
||||
**Trade-offs:**
|
||||
|
||||
- ✅ **Pros:** Fewer runtime errors, better maintainability, self-documenting code
|
||||
- ❌ **Cons:** More verbose code, steeper learning curve
|
||||
|
||||
@@ -169,6 +194,7 @@ Use 2-level sidebar: `Polaris` (parent) → `Overview`, `Namespaces` (children)
|
||||
**Decision:** Default refresh interval is 5 minutes (configurable 1-30 min)
|
||||
|
||||
**Context:**
|
||||
|
||||
- Plugin needs to refresh Polaris data periodically
|
||||
- Polaris audits typically run every 10-30 minutes
|
||||
|
||||
@@ -176,15 +202,18 @@ Use 2-level sidebar: `Polaris` (parent) → `Overview`, `Namespaces` (children)
|
||||
Default to 5 minutes, allow user to configure (1 / 5 / 10 / 30 minutes)
|
||||
|
||||
**Rationale:**
|
||||
|
||||
- Balance between data freshness and API load
|
||||
- Polaris audits don't change frequently (10-30 min intervals)
|
||||
- 5 minutes provides reasonably fresh data without excessive API calls
|
||||
|
||||
**Trade-offs:**
|
||||
|
||||
- ✅ **Pros:** Reasonable default, user-configurable, low API load
|
||||
- ❌ **Cons:** Not real-time (acceptable for audit data)
|
||||
|
||||
**Alternatives Considered:**
|
||||
|
||||
- WebSocket/SSE for real-time → Rejected (Polaris dashboard doesn't support)
|
||||
- 1 minute default → Rejected (unnecessary API calls, audit data changes slowly)
|
||||
- 30 minute default → Rejected (too stale for interactive dashboard)
|
||||
@@ -194,6 +223,7 @@ Default to 5 minutes, allow user to configure (1 / 5 / 10 / 30 minutes)
|
||||
**Decision:** Plugin is read-only (no write operations)
|
||||
|
||||
**Context:**
|
||||
|
||||
- Plugin could potentially modify Polaris configuration or add exemptions
|
||||
- Write operations require additional RBAC permissions (PATCH, CREATE)
|
||||
|
||||
@@ -201,16 +231,19 @@ Default to 5 minutes, allow user to configure (1 / 5 / 10 / 30 minutes)
|
||||
Plugin only performs GET requests (read-only)
|
||||
|
||||
**Rationale:**
|
||||
|
||||
- **Security:** Minimal RBAC footprint (`get` on `services/proxy` only)
|
||||
- **Simplicity:** No mutation logic, error handling for writes, or rollback
|
||||
- **Polaris design:** Exemptions managed via annotations (outside plugin scope)
|
||||
- **Future:** Can add writes later if user demand exists
|
||||
|
||||
**Trade-offs:**
|
||||
|
||||
- ✅ **Pros:** Minimal permissions, simpler code, fewer failure modes
|
||||
- ❌ **Cons:** Cannot add exemptions via UI (must edit annotations manually)
|
||||
|
||||
**Future Enhancement:**
|
||||
|
||||
- Add PATCH permission for workload annotations
|
||||
- Implement `ExemptionManager` component (UI exists, not integrated)
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ High-level architecture of the Headlamp Polaris Plugin.
|
||||
The Headlamp Polaris Plugin is a **read-only dashboard** that surfaces Fairwinds Polaris audit results within the Headlamp UI. It fetches data from the Polaris dashboard API via the Kubernetes service proxy and presents it in a hierarchical navigation structure.
|
||||
|
||||
**Key Characteristics:**
|
||||
|
||||
- **Read-only:** No write operations to cluster or Polaris
|
||||
- **Service proxy based:** Uses K8s API server proxy to reach Polaris
|
||||
- **React Context for state:** Shared data fetch across components
|
||||
@@ -91,6 +92,7 @@ The Headlamp Polaris Plugin is a **read-only dashboard** that surfaces Fairwinds
|
||||
### Plugin Entry Point
|
||||
|
||||
**`src/index.tsx`**
|
||||
|
||||
- Registers sidebar entries (Polaris → Overview, Namespaces)
|
||||
- Registers routes (`/polaris`, `/polaris/namespaces`)
|
||||
- Registers app bar action (score badge)
|
||||
@@ -100,22 +102,26 @@ The Headlamp Polaris Plugin is a **read-only dashboard** that surfaces Fairwinds
|
||||
### Data Layer
|
||||
|
||||
**`src/api/PolarisDataContext.tsx`**
|
||||
|
||||
- React Context Provider for shared data
|
||||
- Fetches AuditData from Polaris dashboard
|
||||
- Handles auto-refresh based on user settings
|
||||
- Provides `{ data, loading, error, refresh }` to consumers
|
||||
|
||||
**`src/api/polaris.ts`**
|
||||
|
||||
- TypeScript types for AuditData schema
|
||||
- Utility functions: `countResults()`, `computeScore()`
|
||||
- Settings management: `getRefreshInterval()`, `setRefreshInterval()`
|
||||
- Constants: `DASHBOARD_URL_DEFAULT`, `INTERVAL_OPTIONS`
|
||||
|
||||
**`src/api/checkMapping.ts`**
|
||||
|
||||
- Maps Polaris check IDs to human-readable names
|
||||
- Used for display in UI (e.g., "hostIPCSet" → "Host IPC")
|
||||
|
||||
**`src/api/topIssues.ts`**
|
||||
|
||||
- Aggregates failing checks across cluster
|
||||
- Groups by check ID and severity
|
||||
- Used for top issues dashboard
|
||||
@@ -123,6 +129,7 @@ The Headlamp Polaris Plugin is a **read-only dashboard** that surfaces Fairwinds
|
||||
### View Components
|
||||
|
||||
**`src/components/DashboardView.tsx`**
|
||||
|
||||
- **Route:** `/polaris`
|
||||
- **Purpose:** Cluster-wide overview
|
||||
- **Features:**
|
||||
@@ -133,6 +140,7 @@ The Headlamp Polaris Plugin is a **read-only dashboard** that surfaces Fairwinds
|
||||
- **Data:** Uses `usePolarisDataContext()`
|
||||
|
||||
**`src/components/NamespacesListView.tsx`**
|
||||
|
||||
- **Route:** `/polaris/namespaces`
|
||||
- **Purpose:** List all namespaces with scores
|
||||
- **Features:**
|
||||
@@ -142,6 +150,7 @@ The Headlamp Polaris Plugin is a **read-only dashboard** that surfaces Fairwinds
|
||||
- **Data:** Uses `usePolarisDataContext()`, aggregates by namespace
|
||||
|
||||
**`src/components/NamespaceDetailView.tsx`**
|
||||
|
||||
- **Route:** Drawer on `/polaris/namespaces#<namespace>`
|
||||
- **Purpose:** Namespace-level drill-down
|
||||
- **Features:**
|
||||
@@ -154,6 +163,7 @@ The Headlamp Polaris Plugin is a **read-only dashboard** that surfaces Fairwinds
|
||||
### UI Components
|
||||
|
||||
**`src/components/AppBarScoreBadge.tsx`**
|
||||
|
||||
- **Location:** Headlamp app bar (top-right)
|
||||
- **Purpose:** Quick cluster score visibility
|
||||
- **Features:**
|
||||
@@ -163,6 +173,7 @@ The Headlamp Polaris Plugin is a **read-only dashboard** that surfaces Fairwinds
|
||||
- **Data:** Uses `usePolarisDataContext()`
|
||||
|
||||
**`src/components/PolarisSettings.tsx`**
|
||||
|
||||
- **Location:** Settings → Plugins → Polaris
|
||||
- **Purpose:** Plugin configuration
|
||||
- **Features:**
|
||||
@@ -172,6 +183,7 @@ The Headlamp Polaris Plugin is a **read-only dashboard** that surfaces Fairwinds
|
||||
- **Data:** localStorage for persistence
|
||||
|
||||
**`src/components/InlineAuditSection.tsx`**
|
||||
|
||||
- **Location:** Resource detail pages (Deployment, StatefulSet, etc.)
|
||||
- **Purpose:** Show Polaris audit inline
|
||||
- **Features:**
|
||||
@@ -181,6 +193,7 @@ The Headlamp Polaris Plugin is a **read-only dashboard** that surfaces Fairwinds
|
||||
- **Data:** Uses `usePolarisDataContext()`, filters by resource
|
||||
|
||||
**`src/components/ExemptionManager.tsx`**
|
||||
|
||||
- **Location:** (Planned feature, UI exists but not fully integrated)
|
||||
- **Purpose:** Manage Polaris exemptions via annotations
|
||||
- **Features:**
|
||||
@@ -195,6 +208,7 @@ The Headlamp Polaris Plugin is a **read-only dashboard** that surfaces Fairwinds
|
||||
**Decision:** Use React Context instead of Redux/Zustand
|
||||
|
||||
**Rationale:**
|
||||
|
||||
1. **Simple state:** Single AuditData object shared across views
|
||||
2. **Read-only:** No complex mutations or transactions
|
||||
3. **Headlamp constraints:** Plugin cannot add dependencies (Redux not bundled)
|
||||
@@ -204,10 +218,10 @@ The Headlamp Polaris Plugin is a **read-only dashboard** that surfaces Fairwinds
|
||||
|
||||
```typescript
|
||||
interface PolarisDataContextValue {
|
||||
data: AuditData | null; // Audit results or null if loading/error
|
||||
loading: boolean; // True during initial fetch
|
||||
error: string | null; // Error message if fetch failed
|
||||
refresh: () => void; // Manual refresh function
|
||||
data: AuditData | null; // Audit results or null if loading/error
|
||||
loading: boolean; // True during initial fetch
|
||||
error: string | null; // Error message if fetch failed
|
||||
refresh: () => void; // Manual refresh function
|
||||
}
|
||||
```
|
||||
|
||||
@@ -221,6 +235,7 @@ interface PolarisDataContextValue {
|
||||
### localStorage Usage
|
||||
|
||||
Settings persisted in localStorage:
|
||||
|
||||
- **`polaris-plugin-refresh-interval`**: Number (seconds), default 300
|
||||
- **`polaris-plugin-dashboard-url`**: String, default service proxy path
|
||||
|
||||
@@ -236,28 +251,30 @@ No sensitive data stored in localStorage.
|
||||
|
||||
```typescript
|
||||
// Sidebar navigation
|
||||
registerSidebarEntry({ parent, name, label, url, icon })
|
||||
registerSidebarEntry({ parent, name, label, url, icon });
|
||||
|
||||
// Routes
|
||||
registerRoute({ path, sidebar, name, exact, component })
|
||||
registerRoute({ path, sidebar, name, exact, component });
|
||||
|
||||
// App bar actions
|
||||
registerAppBarAction(component)
|
||||
registerAppBarAction(component);
|
||||
|
||||
// Plugin settings
|
||||
registerPluginSettings(name, component, displaySaveButton)
|
||||
registerPluginSettings(name, component, displaySaveButton);
|
||||
|
||||
// Resource detail sections
|
||||
registerDetailsViewSection(component)
|
||||
registerDetailsViewSection(component);
|
||||
```
|
||||
|
||||
**Key Changes in v0.13.0:**
|
||||
|
||||
- `registerDetailsViewSection` now takes 1 argument (component), not 2 (name, component)
|
||||
- `registerAppBarAction` now takes 1 argument (component), not 2 (name, component)
|
||||
|
||||
### Headlamp CommonComponents
|
||||
|
||||
**Used Components:**
|
||||
|
||||
- `SectionBox` - Card-like container with title
|
||||
- `SectionHeader` - Page header with title
|
||||
- `StatusLabel` - Color-coded status badges
|
||||
@@ -267,16 +284,19 @@ registerDetailsViewSection(component)
|
||||
- `Loader` - Loading spinner
|
||||
|
||||
**Router:**
|
||||
|
||||
- `Router.createRouteURL()` - Generate plugin route URLs
|
||||
- React Router's `useHistory()`, `useParams()`, `useLocation()`
|
||||
|
||||
### Kubernetes API (via ApiProxy)
|
||||
|
||||
**Used for:**
|
||||
|
||||
- Fetching Polaris results: `ApiProxy.request(dashboardUrl + 'results.json')`
|
||||
- No direct K8s API calls (all data from Polaris dashboard)
|
||||
|
||||
**RBAC Required:**
|
||||
|
||||
- `get` on `services/proxy` for `polaris-dashboard` in `polaris` namespace
|
||||
|
||||
## Performance Considerations
|
||||
|
||||
Reference in New Issue
Block a user