233 lines
5.1 KiB
Markdown
233 lines
5.1 KiB
Markdown
# Design Document: Shell & Logs Feature Specification
|
|
|
|
## Overview
|
|
Shell and Logs are real-time terminal and streaming views for Kubernetes resources. These features enable users to interact with running pods and monitor application behavior.
|
|
|
|
## Shell Terminal (kubectl exec)
|
|
|
|
### Requirements
|
|
- **Implementation**: xterm.js on client
|
|
- **Backend**: WebSocket → kubectl exec
|
|
- **Protocol**: Bidirectional terminal protocol
|
|
|
|
### Terminal Configuration
|
|
```typescript
|
|
{
|
|
rows: 24,
|
|
cols: 80,
|
|
fontFamily: 'IBM Plex Mono',
|
|
fontSize: 12,
|
|
lineHeight: 1.5,
|
|
cursorBlink: true,
|
|
theme: {
|
|
background: '#1a1e26',
|
|
foreground: '#b9c6d8',
|
|
}
|
|
}
|
|
```
|
|
|
|
### Connection Flow
|
|
1. User opens shell view
|
|
2. Extract pod name and namespace
|
|
3. Connect WebSocket to `/ws/shell?pod=X&ns=Y`
|
|
4. Backend:
|
|
- Extract query params
|
|
- Connect to k8s exec API
|
|
- Create execstream
|
|
- Proxy bidirectionally
|
|
5. Frontend:
|
|
- Initialize xterm
|
|
- Attach to WebSocket
|
|
- Handle resize events
|
|
- Route keypresses
|
|
|
|
### Key Routing
|
|
- **Shell focused + type**: Route to terminal
|
|
- **Canvas shortcuts disabled** when shell has focus
|
|
- **Space key**: Goes to terminal (not spotlight)
|
|
- **Ctrl/⌘+scroll**: Zoom canvas (not terminal zoom)
|
|
|
|
### Resize Handling
|
|
- **Client**: term.resize(cols, rows)
|
|
- **Server**: Send resize message via WebSocket
|
|
- **Backend**: Update k8s exec term size
|
|
- **Debounce**: 100ms for resize events
|
|
|
|
### State Management
|
|
```typescript
|
|
interface ShellState {
|
|
connected: boolean;
|
|
connectedAt: number;
|
|
lastActive: number;
|
|
buffer: string[];
|
|
cols: number;
|
|
rows: number;
|
|
}
|
|
```
|
|
|
|
### Error States
|
|
- Connection failed: Show error message
|
|
- Disconnected: Show "Disconnected" + reconnect button
|
|
- Permission denied: Show clear error
|
|
- Pod not found: Show error message
|
|
|
|
## Logs Viewer (kubectl logs)
|
|
|
|
### Requirements
|
|
- **Implementation**: WebSocket streaming
|
|
- **Auto-scroll**: To bottom by default
|
|
- **Color coding**: ERROR/WARN/INFO
|
|
|
|
### Connection Flow
|
|
1. User opens logs view
|
|
2. Connect to `/ws/logs?pod=X&ns=Y`
|
|
3. Backend:
|
|
- Start kubectl logs stream
|
|
- Forward to WebSocket
|
|
4. Frontend:
|
|
- Append lines to buffer
|
|
- Auto-scroll if at bottom
|
|
- Colorize based on level
|
|
|
|
### Log Parsing
|
|
Each log line should include:
|
|
- Timestamp
|
|
- Log level (ERROR/WARN/INFO/DEBUG)
|
|
- Message
|
|
|
|
Format:
|
|
```typescript
|
|
interface LogLine {
|
|
timestamp: string; // ISO 8601
|
|
level: 'ERROR' | 'WARN' | 'INFO' | 'DEBUG';
|
|
message: string;
|
|
}
|
|
```
|
|
|
|
### Color Coding
|
|
- **ERROR**: `#ef6f6f`
|
|
- **WARN**: `#e8b54a`
|
|
- **INFO**: `#b9c6d8`
|
|
- **DEBUG**: `#6b7280`
|
|
|
|
### Auto-Scroll Logic
|
|
- **Track scroll position**: Store `scrollTop`
|
|
- **At bottom**: Auto-scroll on new log
|
|
- **Scrolled up**: Don't auto-scroll
|
|
- **Threshold**: Within 20px of bottom = "at bottom"
|
|
|
|
### User Controls
|
|
- **Click auto-scroll toggle**: Switch between auto and manual scroll
|
|
- **Clear logs**: Button to clear buffer
|
|
- **Copy log line**: Right-click menu
|
|
- **Filter**: Simple filtering (show/hide levels)
|
|
|
|
### State Management
|
|
```typescript
|
|
interface LogsState {
|
|
connected: boolean;
|
|
autoScroll: boolean;
|
|
logLines: LogLine[];
|
|
scrollPosition: number;
|
|
filterLevels: Set<LogLevel>;
|
|
}
|
|
```
|
|
|
|
### Streaming Considerations
|
|
- **Backpressure**: Buffer if client slow
|
|
- **Rate limiting**: Server can throttle logs
|
|
- **Keep-alive**: Ping every 30s
|
|
- **Reconnect**: Exponential backoff on disconnect
|
|
|
|
### Performance Optimization
|
|
- **Virtualization**: Only render visible lines
|
|
- **Batching**: Flush logs in batches if high volume
|
|
- **Throttling**: 16ms throttle for updates
|
|
- **Cleanup**: Remove old logs (keep last 1000 lines)
|
|
|
|
## Shared Features
|
|
|
|
### View State
|
|
- Both views persist state in krate.window.state
|
|
- reconnect: Auto reconnect on disconnect
|
|
- timestamps: Show/hide timestamps
|
|
- wrap: Word wrap toggle
|
|
|
|
### Tab Switching
|
|
- Shell tab: Enabled for pods only
|
|
- Logs tab: Enabled for pods/workloads
|
|
- Empty state: Show helpful message for unsupported resources
|
|
|
|
### Close Behavior
|
|
- Shell: Keep buffer, show "Disconnnected"
|
|
- Logs: Stop streaming, keep buffer
|
|
- Cleanup: Close WebSocket, cancel watchers
|
|
|
|
## WebSocket Protocol
|
|
|
|
### Shell
|
|
```
|
|
// Client → Server
|
|
{
|
|
type: 'shell:input',
|
|
data: string // Key press data
|
|
}
|
|
|
|
{
|
|
type: 'shell:resize',
|
|
cols: number,
|
|
rows: number
|
|
}
|
|
|
|
// Server → Client
|
|
{
|
|
type: 'shell:output',
|
|
data: string // stdout/stderr
|
|
}
|
|
|
|
{
|
|
type: 'shell:status',
|
|
connected: boolean,
|
|
message?: string
|
|
}
|
|
```
|
|
|
|
### Logs
|
|
```
|
|
// Client → Server
|
|
{
|
|
type: 'logs:subscribe',
|
|
pod: string,
|
|
namespace: string,
|
|
follow: boolean,
|
|
timestamps: boolean
|
|
}
|
|
|
|
{
|
|
type: 'logs:filter',
|
|
levels: string[]
|
|
}
|
|
|
|
// Server → Client
|
|
{
|
|
type: 'log',
|
|
log: LogLine
|
|
}
|
|
|
|
{
|
|
type: 'status',
|
|
connected: boolean,
|
|
message?: string
|
|
}
|
|
```
|
|
|
|
## Gotchas
|
|
1. **Space key**: Must distinguish between canvas pan and shell input
|
|
2. **Focus routing**: Route keys based on hovered window
|
|
3. **Scroll management**: Track scroll position for logs
|
|
4. **Terminal resize**: Debounce resize events
|
|
5. **Reconnection**: Handle WebSocket disconnects gracefully
|
|
6. **Memory**: Clean up old logs/shell buffers
|
|
7. **Authentication**: Validate user on WebSocket upgrade
|
|
8. **Permissions**: Enforce namespace RBAC on backend
|