Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,35 @@
## [3.3.0] — 2026-05-30

### New features

#### Cilium Hubble network flows

- **Live traffic edges in the network map** (`NetworkPanel.tsx`, `NetworkPanel.utils.ts`) — When Cilium with Hubble Relay is present in the cluster, the network map now overlays observed pod-to-pod traffic as teal `hubble-flow` edges. DROPPED and ERROR flows are labelled and visually distinct from forwarded traffic. Edges are opt-in via a **Hubble Flows** filter pill that only appears when `providers.hubbleRelay` is true, so the panel is unaffected on clusters without Hubble.

- **Hubble Relay gRPC client** (`go-core/internal/hubble/client.go`) — Lazy-connecting `Manager` singleton that programmatically port-forwards to a `hubble-relay` pod in `kube-system` on first use, then streams flows via the Cilium Observer gRPC API. Key design properties:
- Connection setup runs outside the manager lock — concurrent context switches (`Reset`) are never blocked for up to the 15 s port-forward timeout.
- A generation counter on every `Reset` lets in-flight fetches detect a cluster switch and discard stale results.
- A per-generation negative cache (pod-not-found only) prevents repeated API calls on clusters without Hubble; transient port-forward and gRPC failures do not cache and retry on the next request.
- Concurrent dial race handled: if two goroutines both attempt to create a connection, the loser discards its tunnel and streams from the winner's connection.

- **`HubbleDiscoverer`** (`go-core/internal/hubble/discoverer.go`) — Implements `graph.Discoverer`; queries all flows from the last 60 s, deduplicates by pod-pair (DROPPED/ERROR wins over FORWARDED), and emits `hubble-flow` edges into the topology graph. Always registered — returns zero edges silently when Hubble is unavailable.

- **`EdgeHubbleFlow` edge kind** (`go-core/internal/graph/graph.go`) — New `EdgeKind = "hubble-flow"` constant; rendered in teal with a 1.2 s animated stroke.

- **Provider detection extended** (`go-core/internal/providers/detect.go`, `go-core/internal/handlers/providers.go`) — `ProviderSet` gains `Cilium` (detected via `cilium.io` API group) and `HubbleRelay` (detected by the existence of the `hubble-relay` Service in `kube-system`). The renderer `ProviderSet` type and `providersSlice` default state updated to match. Context-switch reset in `clusterSlice` now includes both new fields.

### Bug fixes

#### Go sidecar

- **`tools_diag.go` `detect_providers` silently swallowed hubble-relay probe errors** — Added `k8serrors.IsNotFound` check; unexpected API errors are now logged rather than silently treated as "not installed".

#### Renderer

- **Context-switch provider reset missing `cilium` and `hubbleRelay`** (`clusterSlice.ts`) — The inline reset object in `selectContext` did not include the two new provider fields, so stale Hubble values persisted across context switches until `fetchProviders` resolved. Both fields are now explicitly reset to `false`.

---

## [3.2.2] — 2026-05-02

### New features
Expand Down
4 changes: 4 additions & 0 deletions go-core/cmd/podscape-core/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (

"github.com/podscape/go-core/internal/client"
"github.com/podscape/go-core/internal/handlers"
"github.com/podscape/go-core/internal/hubble"
"github.com/podscape/go-core/internal/informers"
"github.com/podscape/go-core/internal/portforward"
"github.com/podscape/go-core/internal/store"
Expand Down Expand Up @@ -174,6 +175,7 @@ func main() {
// Initialize the portforward manager early (with nil clients) so handlers
// like HandleSwitchContext can safely call Manager.StopAll() immediately.
portforward.Init(nil, nil)
hubble.Init(nil, nil)

// Build the k8s client; fail gracefully into setup mode if no valid kubeconfig exists.
// If the file is missing (fresh install, CI, new machine), run in no-kubeconfig
Expand Down Expand Up @@ -205,6 +207,8 @@ func main() {

// Update the portforward manager with valid clients now that we have them.
portforward.Manager.UpdateClients(bundle.Clientset, bundle.Config)
hubble.Init(bundle.Clientset, bundle.Config)
hubble.DefaultManager.WarmUp()

// Start the HTTP server — /health returns 503 until informers sync, so
// startSidecar() keeps polling. portforward is already initialised above.
Expand Down
13 changes: 12 additions & 1 deletion go-core/cmd/podscape-mcp/tools_diag.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"errors"
"fmt"
"log"
"strings"
"sync"
"time"
Expand All @@ -15,6 +16,7 @@ import (
"github.com/podscape/go-core/internal/providers"
corev1 "k8s.io/api/core/v1"
networkingv1 "k8s.io/api/networking/v1"
k8serrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

Expand Down Expand Up @@ -544,6 +546,15 @@ func handleDetectProviders(ctx context.Context, req mcp.CallToolRequest) (*mcp.C
if icList != nil {
items = icList.Items
}
ps := providers.Detect(b.Clientset.Discovery(), items)

hubbleRelayPresent := false
_, hubbleErr := b.Clientset.CoreV1().Services("kube-system").Get(apiCtx, "hubble-relay", metav1.GetOptions{})
if hubbleErr == nil {
hubbleRelayPresent = true
} else if !k8serrors.IsNotFound(hubbleErr) {
log.Printf("[providers] unexpected error checking hubble-relay service: %v", hubbleErr)
}

ps := providers.Detect(b.Clientset.Discovery(), items, hubbleRelayPresent)
return jsonResult(ps)
}
45 changes: 21 additions & 24 deletions go-core/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,22 @@ module github.com/podscape/go-core
go 1.25.5

require (
github.com/cilium/cilium v1.19.4
github.com/controlplaneio/kubesec/v2 v2.14.2
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674
go.uber.org/zap v1.27.1
helm.sh/helm/v3 v3.20.2
k8s.io/api v0.35.2
k8s.io/apimachinery v0.35.2
k8s.io/client-go v0.35.2
k8s.io/api v0.35.4
k8s.io/apimachinery v0.35.4
k8s.io/client-go v0.35.4
sigs.k8s.io/yaml v1.6.0
)

require (
github.com/stretchr/testify v1.11.1 // indirect
go.opentelemetry.io/otel/sdk/metric v1.43.0 // indirect
)

require (
github.com/bahlo/generic-list-go v0.2.0 // indirect
github.com/buger/jsonparser v1.1.2 // indirect
Expand All @@ -25,7 +31,6 @@ require (

require (
dario.cat/mergo v1.0.2 // indirect
github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 // indirect
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect
github.com/BurntSushi/toml v1.6.0 // indirect
github.com/MakeNowJust/heredoc v1.0.0 // indirect
Expand All @@ -40,7 +45,6 @@ require (
github.com/containerd/errdefs v1.0.0 // indirect
github.com/containerd/log v0.1.0 // indirect
github.com/containerd/platforms v1.0.0-rc.2 // indirect
github.com/coreos/go-systemd/v22 v22.6.0 // indirect
github.com/creack/pty v1.1.24 // indirect
github.com/cyphar/filepath-securejoin v0.6.1 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
Expand Down Expand Up @@ -81,7 +85,6 @@ require (
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/go-retryablehttp v0.7.8 // indirect
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
github.com/huandu/xstrings v1.5.0 // indirect
github.com/in-toto/in-toto-golang v0.9.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
Expand All @@ -96,7 +99,6 @@ require (
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.16 // indirect
github.com/mattn/go-sqlite3 v1.14.28 // indirect
github.com/miekg/dns v1.1.61 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
Expand All @@ -112,8 +114,6 @@ require (
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/prometheus/common v0.67.4 // indirect
github.com/prometheus/procfs v0.17.0 // indirect
github.com/redis/go-redis/extra/redisotel/v9 v9.5.3 // indirect
github.com/redis/go-redis/v9 v9.17.2 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
Expand Down Expand Up @@ -141,19 +141,16 @@ require (
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0 // indirect
go.opentelemetry.io/otel/exporters/prometheus v0.60.0 // indirect
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.36.0 // indirect
go.opentelemetry.io/otel/metric v1.43.0 // indirect
go.opentelemetry.io/otel/sdk v1.43.0 // indirect
go.opentelemetry.io/otel/trace v1.43.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.yaml.in/yaml/v2 v2.4.3 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/crypto v0.49.0 // indirect
golang.org/x/net v0.52.0 // indirect
golang.org/x/crypto v0.50.0 // indirect
golang.org/x/net v0.53.0 // indirect
golang.org/x/oauth2 v0.35.0 // indirect
golang.org/x/sync v0.20.0
golang.org/x/sys v0.42.0 // indirect
golang.org/x/term v0.41.0 // indirect
golang.org/x/text v0.35.0 // indirect
golang.org/x/sys v0.43.0 // indirect
golang.org/x/term v0.42.0 // indirect
golang.org/x/text v0.36.0 // indirect
golang.org/x/time v0.14.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20260401024825-9d38bb4040a9 // indirect
google.golang.org/grpc v1.80.0 // indirect
Expand All @@ -162,18 +159,18 @@ require (
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/apiextensions-apiserver v0.35.2
k8s.io/apiserver v0.35.2 // indirect
k8s.io/cli-runtime v0.35.1 // indirect; indirect — TODO: upgrade to v0.35.x alongside kubectl to resolve k8s minor-version skew (used only by Helm CLI, unrelated to apiextensions path)
k8s.io/component-base v0.35.2 // indirect
k8s.io/apiextensions-apiserver v0.35.4
k8s.io/apiserver v0.35.4 // indirect
k8s.io/cli-runtime v0.35.4 // indirect; indirect — TODO: upgrade to v0.35.x alongside kubectl to resolve k8s minor-version skew (used only by Helm CLI, unrelated to apiextensions path)
k8s.io/component-base v0.35.4 // indirect
k8s.io/klog/v2 v2.130.1
k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 // indirect
k8s.io/kubectl v0.35.1 // indirect; indirect — TODO: upgrade to v0.35.x (see cli-runtime above)
k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 // indirect
k8s.io/kubectl v0.35.4 // indirect; indirect — TODO: upgrade to v0.35.x (see cli-runtime above)
k8s.io/utils v0.0.0-20260319190234-28399d86e0b5 // indirect
oras.land/oras-go/v2 v2.6.0 // indirect
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect
sigs.k8s.io/kustomize/api v0.20.1 // indirect
sigs.k8s.io/kustomize/kyaml v0.20.1 // indirect
sigs.k8s.io/randfill v1.0.0 // indirect
sigs.k8s.io/structured-merge-diff/v6 v6.3.0 // indirect
sigs.k8s.io/structured-merge-diff/v6 v6.3.2-0.20260122202528-d9cc6641c482 // indirect
)
Loading
Loading