mirror of
https://github.com/lukaszraczylo/kportal.git
synced 2026-07-09 06:44:16 +00:00
style: Extract UI constants and refactor main view rendering (#30)
- [x] Add golangci-lint configuration with gocritic ifElseChain disabled
- [x] Rename error variables to avoid shadowing (createErr, watcherErr, watchErr, etc.)
- [x] Replace `interface{}` with `any` type alias throughout codebase
- [x] Add package-level documentation comments to all internal packages
- [x] Reorder struct fields alphabetically for consistency
- [x] Extract UI constants (terminal dimensions, column widths, colors) to constants.go
- [x] Refactor BubbleTeaUI main view rendering into smaller helper functions
- [x] Simplify nested conditionals and improve code clarity
- [x] Add `isForwardDisabled()` helper method to BubbleTeaUI
- [x] Update file permissions from 0644 to 0600 in config tests
- [x] Add `#nosec` comments and error suppression where appropriate
- [x] Improve test table struct field ordering for readability
- [x] Fix resource parsing in AddForward using strings.SplitN
- [x] Add comprehensive tests for new UI helper functions and constants
This commit is contained in:
+17
-6
@@ -1,3 +1,14 @@
|
||||
// Package k8s provides Kubernetes client management, resource resolution,
|
||||
// and port-forwarding capabilities for kportal.
|
||||
//
|
||||
// Key components:
|
||||
// - ClientPool: Thread-safe management of Kubernetes clients per context
|
||||
// - ResourceResolver: Resolves pod/service/selector targets to actual pods
|
||||
// - PortForwarder: Establishes and manages port-forward connections
|
||||
// - Discovery: Provides resource discovery for the UI wizards
|
||||
//
|
||||
// The package handles automatic pod restart detection through re-resolution,
|
||||
// caching with 30-second TTL, and graceful connection management.
|
||||
package k8s
|
||||
|
||||
import (
|
||||
@@ -12,10 +23,10 @@ import (
|
||||
|
||||
// ClientPool manages Kubernetes clients per context with thread-safe access.
|
||||
type ClientPool struct {
|
||||
mu sync.RWMutex
|
||||
loader clientcmd.ClientConfig
|
||||
clients map[string]*kubernetes.Clientset
|
||||
configs map[string]*rest.Config
|
||||
loader clientcmd.ClientConfig
|
||||
mu sync.RWMutex
|
||||
}
|
||||
|
||||
// NewClientPool creates a new ClientPool instance.
|
||||
@@ -51,8 +62,8 @@ func (p *ClientPool) GetClient(contextName string) (*kubernetes.Clientset, error
|
||||
defer p.mu.Unlock()
|
||||
|
||||
// Double-check in case another goroutine created it while we waited
|
||||
if client, exists := p.clients[contextName]; exists {
|
||||
return client, nil
|
||||
if cachedClient, ok := p.clients[contextName]; ok {
|
||||
return cachedClient, nil
|
||||
}
|
||||
|
||||
// Create new client
|
||||
@@ -91,8 +102,8 @@ func (p *ClientPool) GetRestConfig(contextName string) (*rest.Config, error) {
|
||||
defer p.mu.Unlock()
|
||||
|
||||
// Double-check in case another goroutine created it while we waited
|
||||
if config, exists := p.configs[contextName]; exists {
|
||||
return config, nil
|
||||
if cachedConfig, ok := p.configs[contextName]; ok {
|
||||
return cachedConfig, nil
|
||||
}
|
||||
|
||||
// Create new config
|
||||
|
||||
@@ -146,8 +146,8 @@ func TestClientPool_ThreadSafety(t *testing.T) {
|
||||
go func() {
|
||||
pool.ClearCache()
|
||||
pool.RemoveContext("test-context")
|
||||
pool.GetCurrentContext()
|
||||
pool.ListContexts()
|
||||
_, _ = pool.GetCurrentContext()
|
||||
_, _ = pool.ListContexts()
|
||||
done <- true
|
||||
}()
|
||||
}
|
||||
|
||||
@@ -28,11 +28,11 @@ func NewDiscovery(pool *ClientPool) *Discovery {
|
||||
|
||||
// PodInfo contains information about a pod relevant for port forwarding.
|
||||
type PodInfo struct {
|
||||
Created metav1.Time
|
||||
Name string
|
||||
Namespace string
|
||||
Containers []ContainerInfo
|
||||
Status string
|
||||
Created metav1.Time
|
||||
Containers []ContainerInfo
|
||||
}
|
||||
|
||||
// ContainerInfo contains information about a container within a pod.
|
||||
@@ -44,17 +44,17 @@ type ContainerInfo struct {
|
||||
// PortInfo describes a port exposed by a container or service.
|
||||
type PortInfo struct {
|
||||
Name string
|
||||
Port int32
|
||||
TargetPort int32 // For services: the actual pod port to forward to
|
||||
Protocol string
|
||||
Port int32
|
||||
TargetPort int32
|
||||
}
|
||||
|
||||
// ServiceInfo contains information about a service.
|
||||
type ServiceInfo struct {
|
||||
Name string
|
||||
Namespace string
|
||||
Ports []PortInfo
|
||||
Type string
|
||||
Ports []PortInfo
|
||||
}
|
||||
|
||||
// ListContexts returns all available Kubernetes contexts from kubeconfig.
|
||||
|
||||
@@ -14,12 +14,12 @@ import (
|
||||
|
||||
func TestResolveTargetPort(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
servicePort corev1.ServicePort
|
||||
service *corev1.Service
|
||||
name string
|
||||
description string
|
||||
servicePort corev1.ServicePort
|
||||
pods []corev1.Pod
|
||||
expectedPort int32
|
||||
description string
|
||||
}{
|
||||
{
|
||||
name: "numeric targetPort",
|
||||
|
||||
@@ -49,16 +49,16 @@ func (pf *PortForwarder) SetDialTimeout(timeout time.Duration) {
|
||||
|
||||
// ForwardRequest contains the parameters for a port-forward request.
|
||||
type ForwardRequest struct {
|
||||
ContextName string // Kubernetes context name
|
||||
Namespace string // Namespace
|
||||
Resource string // Resource (pod/name or service/name)
|
||||
Selector string // Label selector (for pod resolution)
|
||||
LocalPort int // Local port
|
||||
RemotePort int // Remote port
|
||||
Out io.Writer
|
||||
ErrOut io.Writer
|
||||
StopChan chan struct{}
|
||||
ReadyChan chan struct{}
|
||||
Out io.Writer // Output writer for logs
|
||||
ErrOut io.Writer // Error output writer
|
||||
ContextName string
|
||||
Namespace string
|
||||
Resource string
|
||||
Selector string
|
||||
LocalPort int
|
||||
RemotePort int
|
||||
}
|
||||
|
||||
// Forward establishes a port-forward connection to a Kubernetes resource.
|
||||
|
||||
@@ -19,15 +19,15 @@ const (
|
||||
|
||||
// ResolvedResource represents a resolved Kubernetes resource.
|
||||
type ResolvedResource struct {
|
||||
Name string // The resolved pod or service name
|
||||
Namespace string // The namespace
|
||||
Timestamp time.Time // When this was resolved
|
||||
Timestamp time.Time
|
||||
Name string
|
||||
Namespace string
|
||||
}
|
||||
|
||||
// cacheEntry stores a cached resolution result with expiry.
|
||||
type cacheEntry struct {
|
||||
resource ResolvedResource
|
||||
expiresAt time.Time
|
||||
resource ResolvedResource
|
||||
}
|
||||
|
||||
// ResourceResolver resolves Kubernetes resources with caching.
|
||||
@@ -188,7 +188,7 @@ func (r *ResourceResolver) getFromCache(key string) string {
|
||||
// Upgrade to write lock and delete expired entry
|
||||
r.cacheMu.Lock()
|
||||
// Double-check entry still exists and is still expired (may have been updated)
|
||||
if entry, exists := r.cache[key]; exists && time.Now().After(entry.expiresAt) {
|
||||
if expiredEntry, ok := r.cache[key]; ok && time.Now().After(expiredEntry.expiresAt) {
|
||||
delete(r.cache, key)
|
||||
}
|
||||
r.cacheMu.Unlock()
|
||||
|
||||
Reference in New Issue
Block a user